]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
inital checkin of unimrcp svn revision 985 from http://unimrcp.googlecode.com/svn...
authorMichael Jerris <mike@jerris.com>
Tue, 16 Jun 2009 22:31:19 +0000 (22:31 +0000)
committerMichael Jerris <mike@jerris.com>
Tue, 16 Jun 2009 22:31:19 +0000 (22:31 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@13790 d0543943-73ff-0310-b7d9-9358b9ac24b2

349 files changed:
libs/unimrcp/AUTHORS [new file with mode: 0644]
libs/unimrcp/INSTALL [new file with mode: 0644]
libs/unimrcp/LICENSE [new file with mode: 0644]
libs/unimrcp/Makefile.am [new file with mode: 0644]
libs/unimrcp/README [new file with mode: 0644]
libs/unimrcp/bootstrap [new file with mode: 0755]
libs/unimrcp/build/Makefile.am [new file with mode: 0644]
libs/unimrcp/build/acmacros/apr.m4 [new file with mode: 0644]
libs/unimrcp/build/acmacros/apu.m4 [new file with mode: 0644]
libs/unimrcp/build/acmacros/find_apr.m4 [new file with mode: 0644]
libs/unimrcp/build/acmacros/find_apu.m4 [new file with mode: 0644]
libs/unimrcp/build/acmacros/sofia-sip.m4 [new file with mode: 0644]
libs/unimrcp/build/acmacros/swift.m4 [new file with mode: 0644]
libs/unimrcp/build/get-version.sh [new file with mode: 0755]
libs/unimrcp/build/pkgconfig/Makefile.am [new file with mode: 0644]
libs/unimrcp/build/pkgconfig/unimrcpclient.pc.in [new file with mode: 0644]
libs/unimrcp/build/pkgconfig/unimrcpplugin.pc.in [new file with mode: 0644]
libs/unimrcp/build/pkgconfig/unimrcpserver.pc.in [new file with mode: 0644]
libs/unimrcp/build/tools/prepare.vcproj [new file with mode: 0644]
libs/unimrcp/build/tools/unimrcp_service.c [new file with mode: 0644]
libs/unimrcp/build/tools/unimrcpservice.exe.manifest [new file with mode: 0644]
libs/unimrcp/build/tools/unimrcpservice.vcproj [new file with mode: 0644]
libs/unimrcp/build/uni_version.h [new file with mode: 0644]
libs/unimrcp/build/vsprops/apr.vsprops [new file with mode: 0644]
libs/unimrcp/build/vsprops/apt.vsprops [new file with mode: 0644]
libs/unimrcp/build/vsprops/cepstral.vsprops [new file with mode: 0644]
libs/unimrcp/build/vsprops/mpf.vsprops [new file with mode: 0644]
libs/unimrcp/build/vsprops/mrcp.vsprops [new file with mode: 0644]
libs/unimrcp/build/vsprops/mrcpclient.vsprops [new file with mode: 0644]
libs/unimrcp/build/vsprops/mrcpengine.vsprops [new file with mode: 0644]
libs/unimrcp/build/vsprops/mrcpserver.vsprops [new file with mode: 0644]
libs/unimrcp/build/vsprops/mrcpsignaling.vsprops [new file with mode: 0644]
libs/unimrcp/build/vsprops/mrcpv2transport.vsprops [new file with mode: 0644]
libs/unimrcp/build/vsprops/sdk/unimrcpclient.vsprops [new file with mode: 0644]
libs/unimrcp/build/vsprops/sdk/unimrcpplugin.vsprops [new file with mode: 0644]
libs/unimrcp/build/vsprops/sdk/unimrcpsdk.vsprops [new file with mode: 0644]
libs/unimrcp/build/vsprops/sdk/unimrcpserver.vsprops [new file with mode: 0644]
libs/unimrcp/build/vsprops/sofiasip.vsprops [new file with mode: 0644]
libs/unimrcp/build/vsprops/unibase.vsprops [new file with mode: 0644]
libs/unimrcp/build/vsprops/unidebug.vsprops [new file with mode: 0644]
libs/unimrcp/build/vsprops/unimrcpclient.vsprops [new file with mode: 0644]
libs/unimrcp/build/vsprops/unimrcpplugin.vsprops [new file with mode: 0644]
libs/unimrcp/build/vsprops/unimrcpserver.vsprops [new file with mode: 0644]
libs/unimrcp/build/vsprops/unirelease.vsprops [new file with mode: 0644]
libs/unimrcp/build/vsprops/unirtsp.vsprops [new file with mode: 0644]
libs/unimrcp/conf/unimrcpclient.xml [new file with mode: 0644]
libs/unimrcp/conf/unimrcpserver.xml [new file with mode: 0644]
libs/unimrcp/configure.ac [new file with mode: 0644]
libs/unimrcp/data/demo.pcm [new file with mode: 0644]
libs/unimrcp/data/grammar.xml [new file with mode: 0644]
libs/unimrcp/data/one.pcm [new file with mode: 0644]
libs/unimrcp/data/result.xml [new file with mode: 0644]
libs/unimrcp/data/speak.xml [new file with mode: 0644]
libs/unimrcp/docs/doxygen.conf [new file with mode: 0644]
libs/unimrcp/libs/Makefile.am [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/Makefile.am [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/aprtoolkit.vcproj [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/include/apt.h [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/include/apt_consumer_task.h [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/include/apt_cyclic_queue.h [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/include/apt_dir_layout.h [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/include/apt_log.h [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/include/apt_net.h [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/include/apt_net_client_task.h [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/include/apt_net_server_task.h [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/include/apt_obj_list.h [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/include/apt_pair.h [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/include/apt_pollset.h [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/include/apt_pool.h [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/include/apt_string.h [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/include/apt_string_table.h [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/include/apt_task.h [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/include/apt_task_msg.h [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/include/apt_test_suite.h [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/include/apt_text_stream.h [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/src/apt_consumer_task.c [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/src/apt_cyclic_queue.c [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/src/apt_dir_layout.c [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/src/apt_log.c [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/src/apt_net.c [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/src/apt_net_client_task.c [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/src/apt_net_server_task.c [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/src/apt_obj_list.c [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/src/apt_pair.c [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/src/apt_pollset.c [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/src/apt_pool.c [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/src/apt_string_table.c [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/src/apt_task.c [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/src/apt_task_msg.c [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/src/apt_test_suite.c [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/src/apt_text_stream.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/Makefile.am [new file with mode: 0644]
libs/unimrcp/libs/mpf/codecs/g711/g711.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/codecs/g711/g711.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_activity_detector.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_audio_file_descriptor.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_audio_file_stream.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_bridge.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_buffer.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_codec.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_codec_descriptor.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_codec_manager.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_context.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_decoder.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_encoder.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_engine.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_file_termination_factory.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_frame.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_jitter_buffer.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_media_descriptor.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_message.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_object.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_rtp_attribs.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_rtp_defs.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_rtp_descriptor.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_rtp_header.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_rtp_stat.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_rtp_stream.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_rtp_termination_factory.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_stream.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_stream_mode.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_termination.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_timer.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_types.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_user.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/mpf.vcproj [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_activity_detector.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_audio_file_stream.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_bridge.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_buffer.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_codec_descriptor.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_codec_g711.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_codec_linear.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_codec_manager.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_context.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_decoder.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_encoder.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_engine.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_file_termination_factory.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_jitter_buffer.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_rtp_attribs.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_rtp_stream.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_rtp_termination_factory.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_termination.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_timer.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp-client/Makefile.am [new file with mode: 0644]
libs/unimrcp/libs/mrcp-client/include/mrcp_application.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp-client/include/mrcp_client.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp-client/include/mrcp_client_session.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp-client/include/mrcp_client_types.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp-client/mrcpclient.vcproj [new file with mode: 0644]
libs/unimrcp/libs/mrcp-client/src/mrcp_client.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp-client/src/mrcp_client_session.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp-engine/Makefile.am [new file with mode: 0644]
libs/unimrcp/libs/mrcp-engine/include/mrcp_resource_engine.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp-engine/include/mrcp_resource_plugin.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp-engine/mrcpengine.vcproj [new file with mode: 0644]
libs/unimrcp/libs/mrcp-engine/src/mrcp_resource_engine.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp-server/Makefile.am [new file with mode: 0644]
libs/unimrcp/libs/mrcp-server/include/mrcp_server.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp-server/include/mrcp_server_session.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp-server/include/mrcp_server_types.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp-server/mrcpserver.vcproj [new file with mode: 0644]
libs/unimrcp/libs/mrcp-server/src/mrcp_server.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp-server/src/mrcp_server_session.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp-signaling/Makefile.am [new file with mode: 0644]
libs/unimrcp/libs/mrcp-signaling/include/mrcp_session.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp-signaling/include/mrcp_session_descriptor.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp-signaling/include/mrcp_sig_agent.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp-signaling/include/mrcp_sig_types.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp-signaling/mrcpsignaling.vcproj [new file with mode: 0644]
libs/unimrcp/libs/mrcp-signaling/src/mrcp_session_descriptor.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp-signaling/src/mrcp_sig_agent.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp/Makefile.am [new file with mode: 0644]
libs/unimrcp/libs/mrcp/control/include/mrcp_resource.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp/control/include/mrcp_resource_factory.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp/control/include/mrcp_state_machine.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp/control/include/mrcp_stream.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp/control/src/mrcp_resource_factory.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp/control/src/mrcp_stream.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp/include/mrcp.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp/include/mrcp_types.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp/message/include/mrcp_generic_header.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp/message/include/mrcp_header_accessor.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp/message/include/mrcp_message.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp/message/src/mrcp_generic_header.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp/message/src/mrcp_header_accessor.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp/message/src/mrcp_message.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp/mrcp.vcproj [new file with mode: 0644]
libs/unimrcp/libs/mrcp/resources/include/mrcp_default_factory.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp/resources/include/mrcp_recog_header.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp/resources/include/mrcp_recog_resource.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp/resources/include/mrcp_recog_state_machine.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp/resources/include/mrcp_synth_header.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp/resources/include/mrcp_synth_resource.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp/resources/include/mrcp_synth_state_machine.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp/resources/src/mrcp_default_factory.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_client_state_machine.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_header.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_resource.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_server_state_machine.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_client_state_machine.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_header.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_resource.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_server_state_machine.c [new file with mode: 0644]
libs/unimrcp/libs/mrcpv2-transport/Makefile.am [new file with mode: 0644]
libs/unimrcp/libs/mrcpv2-transport/include/mrcp_client_connection.h [new file with mode: 0644]
libs/unimrcp/libs/mrcpv2-transport/include/mrcp_connection.h [new file with mode: 0644]
libs/unimrcp/libs/mrcpv2-transport/include/mrcp_connection_types.h [new file with mode: 0644]
libs/unimrcp/libs/mrcpv2-transport/include/mrcp_control_descriptor.h [new file with mode: 0644]
libs/unimrcp/libs/mrcpv2-transport/include/mrcp_server_connection.h [new file with mode: 0644]
libs/unimrcp/libs/mrcpv2-transport/mrcpv2transport.vcproj [new file with mode: 0644]
libs/unimrcp/libs/mrcpv2-transport/src/mrcp_client_connection.c [new file with mode: 0644]
libs/unimrcp/libs/mrcpv2-transport/src/mrcp_connection.c [new file with mode: 0644]
libs/unimrcp/libs/mrcpv2-transport/src/mrcp_control_descriptor.c [new file with mode: 0644]
libs/unimrcp/libs/mrcpv2-transport/src/mrcp_server_connection.c [new file with mode: 0644]
libs/unimrcp/libs/uni-rtsp/Makefile.am [new file with mode: 0644]
libs/unimrcp/libs/uni-rtsp/include/rtsp.h [new file with mode: 0644]
libs/unimrcp/libs/uni-rtsp/include/rtsp_client.h [new file with mode: 0644]
libs/unimrcp/libs/uni-rtsp/include/rtsp_header.h [new file with mode: 0644]
libs/unimrcp/libs/uni-rtsp/include/rtsp_message.h [new file with mode: 0644]
libs/unimrcp/libs/uni-rtsp/include/rtsp_server.h [new file with mode: 0644]
libs/unimrcp/libs/uni-rtsp/include/rtsp_start_line.h [new file with mode: 0644]
libs/unimrcp/libs/uni-rtsp/include/rtsp_stream.h [new file with mode: 0644]
libs/unimrcp/libs/uni-rtsp/src/rtsp_client.c [new file with mode: 0644]
libs/unimrcp/libs/uni-rtsp/src/rtsp_header.c [new file with mode: 0644]
libs/unimrcp/libs/uni-rtsp/src/rtsp_message.c [new file with mode: 0644]
libs/unimrcp/libs/uni-rtsp/src/rtsp_server.c [new file with mode: 0644]
libs/unimrcp/libs/uni-rtsp/src/rtsp_start_line.c [new file with mode: 0644]
libs/unimrcp/libs/uni-rtsp/src/rtsp_stream.c [new file with mode: 0644]
libs/unimrcp/libs/uni-rtsp/unirtsp.vcproj [new file with mode: 0644]
libs/unimrcp/modules/Makefile.am [new file with mode: 0644]
libs/unimrcp/modules/mrcp-sofiasip/Makefile.am [new file with mode: 0644]
libs/unimrcp/modules/mrcp-sofiasip/include/mrcp_sdp.h [new file with mode: 0644]
libs/unimrcp/modules/mrcp-sofiasip/include/mrcp_sofiasip_client_agent.h [new file with mode: 0644]
libs/unimrcp/modules/mrcp-sofiasip/include/mrcp_sofiasip_server_agent.h [new file with mode: 0644]
libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.vcproj [new file with mode: 0644]
libs/unimrcp/modules/mrcp-sofiasip/src/mrcp_sdp.c [new file with mode: 0644]
libs/unimrcp/modules/mrcp-sofiasip/src/mrcp_sofiasip_client_agent.c [new file with mode: 0644]
libs/unimrcp/modules/mrcp-sofiasip/src/mrcp_sofiasip_server_agent.c [new file with mode: 0644]
libs/unimrcp/modules/mrcp-unirtsp/Makefile.am [new file with mode: 0644]
libs/unimrcp/modules/mrcp-unirtsp/include/mrcp_unirtsp_client_agent.h [new file with mode: 0644]
libs/unimrcp/modules/mrcp-unirtsp/include/mrcp_unirtsp_sdp.h [new file with mode: 0644]
libs/unimrcp/modules/mrcp-unirtsp/include/mrcp_unirtsp_server_agent.h [new file with mode: 0644]
libs/unimrcp/modules/mrcp-unirtsp/mrcpunirtsp.vcproj [new file with mode: 0644]
libs/unimrcp/modules/mrcp-unirtsp/src/mrcp_unirtsp_client_agent.c [new file with mode: 0644]
libs/unimrcp/modules/mrcp-unirtsp/src/mrcp_unirtsp_sdp.c [new file with mode: 0644]
libs/unimrcp/modules/mrcp-unirtsp/src/mrcp_unirtsp_server_agent.c [new file with mode: 0644]
libs/unimrcp/packages/inno-setup/setup.iss [new file with mode: 0644]
libs/unimrcp/packages/inno-setup/unimrcp-sdk.iss [new file with mode: 0644]
libs/unimrcp/packages/inno-setup/unimrcp.iss [new file with mode: 0644]
libs/unimrcp/platforms/Makefile.am [new file with mode: 0644]
libs/unimrcp/platforms/libunimrcp-client/Makefile.am [new file with mode: 0644]
libs/unimrcp/platforms/libunimrcp-client/include/unimrcp_client.h [new file with mode: 0644]
libs/unimrcp/platforms/libunimrcp-client/libunimrcpclient.vcproj [new file with mode: 0644]
libs/unimrcp/platforms/libunimrcp-client/src/unimrcp_client.c [new file with mode: 0644]
libs/unimrcp/platforms/libunimrcp-server/Makefile.am [new file with mode: 0644]
libs/unimrcp/platforms/libunimrcp-server/include/unimrcp_server.h [new file with mode: 0644]
libs/unimrcp/platforms/libunimrcp-server/libunimrcpserver.vcproj [new file with mode: 0644]
libs/unimrcp/platforms/libunimrcp-server/src/unimrcp_server.c [new file with mode: 0644]
libs/unimrcp/platforms/unimrcp-client/Makefile.am [new file with mode: 0644]
libs/unimrcp/platforms/unimrcp-client/include/demo_application.h [new file with mode: 0644]
libs/unimrcp/platforms/unimrcp-client/include/demo_framework.h [new file with mode: 0644]
libs/unimrcp/platforms/unimrcp-client/include/demo_util.h [new file with mode: 0644]
libs/unimrcp/platforms/unimrcp-client/src/demo_bypass_application.c [new file with mode: 0644]
libs/unimrcp/platforms/unimrcp-client/src/demo_discover_application.c [new file with mode: 0644]
libs/unimrcp/platforms/unimrcp-client/src/demo_framework.c [new file with mode: 0644]
libs/unimrcp/platforms/unimrcp-client/src/demo_recog_application.c [new file with mode: 0644]
libs/unimrcp/platforms/unimrcp-client/src/demo_synth_application.c [new file with mode: 0644]
libs/unimrcp/platforms/unimrcp-client/src/demo_util.c [new file with mode: 0644]
libs/unimrcp/platforms/unimrcp-client/src/main.c [new file with mode: 0644]
libs/unimrcp/platforms/unimrcp-client/unimrcpclient.vcproj [new file with mode: 0644]
libs/unimrcp/platforms/unimrcp-server/Makefile.am [new file with mode: 0644]
libs/unimrcp/platforms/unimrcp-server/src/main.c [new file with mode: 0644]
libs/unimrcp/platforms/unimrcp-server/src/uni_cmdline.c [new file with mode: 0644]
libs/unimrcp/platforms/unimrcp-server/src/uni_daemon.c [new file with mode: 0644]
libs/unimrcp/platforms/unimrcp-server/src/uni_service.c [new file with mode: 0644]
libs/unimrcp/platforms/unimrcp-server/unimrcpserver.vcproj [new file with mode: 0644]
libs/unimrcp/plugins/Makefile.am [new file with mode: 0644]
libs/unimrcp/plugins/demo-recog/Makefile.am [new file with mode: 0644]
libs/unimrcp/plugins/demo-recog/demorecog.vcproj [new file with mode: 0644]
libs/unimrcp/plugins/demo-recog/src/demo_recog_engine.c [new file with mode: 0644]
libs/unimrcp/plugins/demo-synth/Makefile.am [new file with mode: 0644]
libs/unimrcp/plugins/demo-synth/demosynth.vcproj [new file with mode: 0644]
libs/unimrcp/plugins/demo-synth/src/demo_synth_engine.c [new file with mode: 0644]
libs/unimrcp/plugins/mrcp-cepstral/Makefile.am [new file with mode: 0644]
libs/unimrcp/plugins/mrcp-cepstral/mrcpcepstral.vcproj [new file with mode: 0644]
libs/unimrcp/plugins/mrcp-cepstral/src/mrcp_swift.c [new file with mode: 0644]
libs/unimrcp/tests/Makefile.am [new file with mode: 0644]
libs/unimrcp/tests/apttest/Makefile.am [new file with mode: 0644]
libs/unimrcp/tests/apttest/apttest.vcproj [new file with mode: 0644]
libs/unimrcp/tests/apttest/src/consumer_task_suite.c [new file with mode: 0644]
libs/unimrcp/tests/apttest/src/main.c [new file with mode: 0644]
libs/unimrcp/tests/apttest/src/task_suite.c [new file with mode: 0644]
libs/unimrcp/tests/mpftest/Makefile.am [new file with mode: 0644]
libs/unimrcp/tests/mpftest/mpftest.vcproj [new file with mode: 0644]
libs/unimrcp/tests/mpftest/src/main.c [new file with mode: 0644]
libs/unimrcp/tests/mpftest/src/mpf_suite.c [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/Makefile.am [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/mrcptest.vcproj [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/src/main.c [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/src/parse_gen_suite.c [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/src/set_get_suite.c [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/v1/definegrammar.msg [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/v1/getparams.msg [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/v1/multi.msg [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/v1/pause.msg [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/v1/recognitioncomplete.msg [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/v1/recognize.msg [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/v1/response.msg [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/v1/resume.msg [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/v1/setparams.msg [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/v1/speak.msg [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/v1/speakcomplete.msg [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/v1/stop.msg [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/v2/definegrammar.msg [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/v2/getparams.msg [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/v2/recognitioncomplete.msg [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/v2/recognize.msg [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/v2/setparams.msg [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/v2/speak.msg [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/v2/speakcomplete.msg [new file with mode: 0644]
libs/unimrcp/tests/mrcptest/v2/stop.msg [new file with mode: 0644]
libs/unimrcp/tests/rtsptest/Makefile.am [new file with mode: 0644]
libs/unimrcp/tests/rtsptest/msg/announce.msg [new file with mode: 0644]
libs/unimrcp/tests/rtsptest/msg/ok.msg [new file with mode: 0644]
libs/unimrcp/tests/rtsptest/msg/re-ok.msg [new file with mode: 0644]
libs/unimrcp/tests/rtsptest/msg/re-setup.msg [new file with mode: 0644]
libs/unimrcp/tests/rtsptest/msg/setup.msg [new file with mode: 0644]
libs/unimrcp/tests/rtsptest/msg/teardown.msg [new file with mode: 0644]
libs/unimrcp/tests/rtsptest/msg/ultimate.msg [new file with mode: 0644]
libs/unimrcp/tests/rtsptest/rtsptest.vcproj [new file with mode: 0644]
libs/unimrcp/tests/rtsptest/src/main.c [new file with mode: 0644]
libs/unimrcp/tests/rtsptest/src/parse_gen_suite.c [new file with mode: 0644]
libs/unimrcp/tests/sipp/mrcp_uac_multi [new file with mode: 0644]
libs/unimrcp/tests/sipp/mrcp_uac_recog [new file with mode: 0644]
libs/unimrcp/tests/sipp/mrcp_uac_synth [new file with mode: 0644]
libs/unimrcp/tests/sipp/mrcp_uac_unknown [new file with mode: 0644]
libs/unimrcp/tests/sipp/mrcp_uac_update [new file with mode: 0644]
libs/unimrcp/tests/sipp/mrcp_uas_recog [new file with mode: 0644]
libs/unimrcp/tests/sipp/mrcp_uas_reject [new file with mode: 0644]
libs/unimrcp/tests/sipp/mrcp_uas_synth [new file with mode: 0644]
libs/unimrcp/tests/sipp/mrcp_uas_unknown [new file with mode: 0644]
libs/unimrcp/tests/strtablegen/Makefile.am [new file with mode: 0644]
libs/unimrcp/tests/strtablegen/src/main.c [new file with mode: 0644]
libs/unimrcp/tests/strtablegen/stringtable.in [new file with mode: 0644]
libs/unimrcp/tests/strtablegen/strtablegen.vcproj [new file with mode: 0644]
libs/unimrcp/unimrcp.sln [new file with mode: 0644]

diff --git a/libs/unimrcp/AUTHORS b/libs/unimrcp/AUTHORS
new file mode 100644 (file)
index 0000000..365eaf0
--- /dev/null
@@ -0,0 +1,12 @@
+Author(s):
+   Arsen Chaloyan <achaloyan@gmail.com>
+
+
+Contributor(s):
+   Kamil Shakirov <kamils80@gmail.com>
+   Anthony Masse <amasse.telisma@gmail.com>
+   Vlad Socaciu <Curatica@gmail.com>
+   Garmt <garmt.noname@gmail.com>
+   Patrick <pnunes29@gmail.com>
+   Bayram <bayramboyraz@gmail.com>
+   Mahmoud Hassan <firstmahmoud2002@gmail.com>
\ No newline at end of file
diff --git a/libs/unimrcp/INSTALL b/libs/unimrcp/INSTALL
new file mode 100644 (file)
index 0000000..50826f3
--- /dev/null
@@ -0,0 +1,103 @@
+BUILD REQUIREMENTS
+==================
+UniMRCP depends on a number of third party tools and libraries,
+which must be installed prior to UniMRCP build.
+
+1. Apache Portable Runtime [>=1.2.x] (http://apr.apache.org/)
+Whenever you want to build any part of UniMRCP, you need the
+Apache Portable Runtime (APR) and the APR Utility (APR-util)
+libraries.
+
+2. Sofia-SIP [>=1.12.6] (http://sofia-sip.sourceforge.net/)
+Sofia-SIP library is used to implement MRCPv2 specification
+compliant SIP signaling. Sofia-SIP is an open-source SIP User-Agent
+library, compliant with the IETF RFC3261 specification.
+
+Use the link below to download one of known to work and 
+ready to use packages of APR and Sofia-SIP libraries.
+    http://www.unimrcp.org/dependencies/
+
+
+GNU BUILD
+===================
+Additional requirements
+- autoconf 2.57 or newer
+- automake
+- libtool 1.4 or newer
+- gcc
+- pkg-config
+
+Build procedure
+$ ./bootstrap
+$ ./configure
+$ make
+$ make install
+
+Installed directory layout
+bin      - binaries (unimrcpserver, unimrcpclient)
+conf     - configuration files
+include  - header files
+libs     - shared (convenient) libraries
+plugins  - run-time loadable modules
+
+There are a couple of options to "./configure".
+To specify where to look for the APR and APR-util libraries
+use the "--with-apr=" and "--with-apr-util=" options.
+For example
+$ ./configure --with-apr=/usr/local/apr \
+              --with-apr-util=/usr/local/apr
+
+To specify  where to look for the Sofia-SIP library
+use the "--with-sofia-sip=" option. 
+For example
+$ ./configure --with-sofia-sip=/usr/local/sofia-sip
+
+To install the default configuration use
+$ make def-conf
+
+To generate doxygen documentation from the sources use
+$ make dox
+
+To build distribution tarball use
+$ make dist
+
+
+WINDOWS BUILD
+======================
+Additional requirements
+- Microsoft Visual Studio 2005
+
+One-time pre-build preparation
+You may need to adjust the paths for 3-rd party libraries
+in appropriate property sheets to match your local installation,
+while below are the defaults (build/vsprops).
+
+apr.vsprops
+       <UserMacro
+               Name="AprDir"
+               Value="$(SolutionDir)libs\apr"
+       />
+       <UserMacro
+               Name="AprUtilDir"
+               Value="$(SolutionDir)libs\apr-util"
+       />
+       
+sofiasip.vsprops
+       <UserMacro
+               Name="SofiaDir"
+               Value="$(SolutionDir)libs\sofia-sip"
+       />
+
+Build procedure
+Open unimrcp.sln solution file and build the solution (Build -> Build Solution).
+
+One-time pre-run output directory preparation
+Build prepare.vcproj utility project (right click on tools -> prebuild in 
+Solution Explorer and select Build from context menu). This is a one-time 
+output directory preparation. It copies all the required APR and SofiaSIP 
+libraries and the default configuration to the output directory. 
+
+Output directory layout
+bin      - binaries (unimrcpserver, unimrcpclient) and all the required dlls
+conf     - configuration files
+plugins  - run-time loadable modules
\ No newline at end of file
diff --git a/libs/unimrcp/LICENSE b/libs/unimrcp/LICENSE
new file mode 100644 (file)
index 0000000..d645695
--- /dev/null
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/libs/unimrcp/Makefile.am b/libs/unimrcp/Makefile.am
new file mode 100644 (file)
index 0000000..a720714
--- /dev/null
@@ -0,0 +1,42 @@
+macrodir               = @ac_macro_dir@
+auxdir                 = @ac_aux_dir@
+AUX_DIST               = $(auxdir)/config.guess \
+                          $(auxdir)/config.sub \
+                          $(auxdir)/install-sh \
+                          $(auxdir)/ltconfig \
+                          $(auxdir)/ltmain.sh \
+                          $(auxdir)/depcomp \
+                          $(auxdir)/missing
+EXTRA_DIST             = bootstrap
+
+AUTOMAKE_OPTIONS       = foreign
+MAINTAINERCLEANFILES   = Makefile.in aclocal.m4 configure $(AUX_DIST)
+
+ACLOCAL                        = aclocal -I $(macrodir)
+
+SUBDIRS                 = libs modules plugins platforms build
+if TEST_SUITES
+SUBDIRS                += tests
+endif
+
+dox:
+       doxygen $(top_srcdir)/docs/doxygen.conf
+
+def-conf:
+       test -d $(confdir) || $(mkinstalldirs) $(confdir)
+       for conffile in `find conf -name \*.xml` ; do \
+           filename=`echo $$conffile | sed -e 's|^.*/||'`; \
+           $(INSTALL) -m 644 conf/$$filename $(confdir); \
+       done
+
+def-data:
+       test -d $(datadir) || $(mkinstalldirs) $(datadir)
+       for datafile in `find data -name *.pcm -o -name *.xml` ; do \
+           filename=`echo $$datafile | sed -e 's|^.*/||'`; \
+           $(INSTALL) -m 644 data/$$filename $(datadir); \
+       done
+           
+install-data-local:
+       test -d $(confdir) || $(MAKE) def-conf
+       test -d $(datadir) || $(MAKE) def-data
+       test -d $(logdir)  || $(mkinstalldirs) $(logdir)
diff --git a/libs/unimrcp/README b/libs/unimrcp/README
new file mode 100644 (file)
index 0000000..bcd2dae
--- /dev/null
@@ -0,0 +1,51 @@
+INTRODUCTION
+============
+UniMRCP - Open Source Media Resource Control Protocol Stack.
+
+
+INSTALLATION
+============
+See the file "INSTALLATION" for installation tips.
+
+
+DOCUMENTATION
+=============
+See the directory "docs/dox" for doxygen generated documentation.
+See the directory "docs/ea" for UML based design concepts
+   (Enterpise Architect generated HTML pages).
+
+
+REFERENCES
+==========
+Website:
+   http://www.unimrcp.org
+
+Project Home:
+   http://code.google.com/p/unimrcp/
+
+Wiki:
+   http://code.google.com/p/unimrcp/w/list
+
+Issue Tracker:
+   http://code.google.com/p/unimrcp/issues/list
+
+Discussion Group:
+   http://groups.google.com/group/unimrcp
+
+Version Control Repository (SVN):
+   http://unimrcp.googlecode.com/svn/trunk/
+
+UML Documentation File (Enterpise Architect):
+   http://unimrcp.googlecode.com/svn/misc/unimrcp.eap
+
+Commit Monitor:
+   http://code.google.com/p/unimrcp/source/list
+   http://groups.google.com/group/unimrcp-svn-commits
+
+
+LICENSING
+=========
+UniMRCP is licensed under terms of the Apache 2.0 license.
+See the file "LICENSE" for more information.
+
+Copyright 2008 Arsen Chaloyan
diff --git a/libs/unimrcp/bootstrap b/libs/unimrcp/bootstrap
new file mode 100755 (executable)
index 0000000..e037f54
--- /dev/null
@@ -0,0 +1,14 @@
+#! /bin/sh
+
+case `uname` in
+    Darwin) libtoolize=glibtoolize ;;
+    *)      libtoolize=libtoolize  ;;
+esac
+
+set -x
+$libtoolize --force --automake --copy
+aclocal -I build/acmacros
+automake --foreign --add-missing --copy
+autoconf
+
+rm -rf autom4te.cache
diff --git a/libs/unimrcp/build/Makefile.am b/libs/unimrcp/build/Makefile.am
new file mode 100644 (file)
index 0000000..76d10e5
--- /dev/null
@@ -0,0 +1,3 @@
+MAINTAINERCLEANFILES   = Makefile.in
+
+SUBDIRS                = pkgconfig
diff --git a/libs/unimrcp/build/acmacros/apr.m4 b/libs/unimrcp/build/acmacros/apr.m4
new file mode 100644 (file)
index 0000000..dc786c2
--- /dev/null
@@ -0,0 +1,44 @@
+dnl  UNIMRCP_CHECK_APR
+
+AC_DEFUN([UNIMRCP_CHECK_APR],
+[
+  AC_MSG_NOTICE([Apache Portable Runtime (APR) library configuration])
+
+  APR_FIND_APR("", "", 1, 1)
+
+  if test $apr_found = "no"; then
+    AC_MSG_WARN([APR not found])
+    UNIMRCP_DOWNLOAD_APR
+  fi
+
+  if test $apr_found = "reconfig"; then
+    AC_MSG_WARN([APR reconfig])
+  fi
+
+  dnl check APR version number
+
+  apr_version="`$apr_config --version`"
+  AC_MSG_RESULT([$apr_version])
+
+  dnl Get build information from APR
+
+  CPPFLAGS="$CPPFLAGS `$apr_config --cppflags`"
+  CFLAGS="$CFLAGS `$apr_config --cflags`"
+  LDFLAGS="$LDFLAGS `$apr_config --ldflags`"
+
+  UNIMRCP_APR_INCLUDES="`$apr_config --includes`"
+  UNIMRCP_APR_LIBS="`$apr_config --link-libtool --libs`"
+
+  AC_SUBST(UNIMRCP_APR_INCLUDES)
+  AC_SUBST(UNIMRCP_APR_LIBS)
+])
+
+dnl UNIMRCP_DOWNLOAD_APR
+dnl no apr found, print out a message telling the user what to do
+AC_DEFUN([UNIMRCP_DOWNLOAD_APR],
+[
+  echo "The Apache Portable Runtime (APR) library cannot be found."
+  echo "Please install APR on this system and supply the appropriate"
+  echo "--with-apr option to 'configure'"
+  AC_MSG_ERROR([no suitable APR found])
+])
diff --git a/libs/unimrcp/build/acmacros/apu.m4 b/libs/unimrcp/build/acmacros/apu.m4
new file mode 100644 (file)
index 0000000..4d47f09
--- /dev/null
@@ -0,0 +1,42 @@
+dnl  UNIMRCP_CHECK_APU
+
+AC_DEFUN([UNIMRCP_CHECK_APU],
+[
+  AC_MSG_NOTICE([Apache Portable Runtime Utility (APU) library configuration])
+
+  APR_FIND_APU("", "", 1, 1)
+
+  if test $apu_found = "no"; then
+    AC_MSG_WARN([APU not found])
+    UNIMRCP_DOWNLOAD_APU
+  fi
+
+  if test $apu_found = "reconfig"; then
+    AC_MSG_WARN([APU reconfig])
+  fi
+
+  dnl check APU version number
+
+  apu_version="`$apu_config --version`"
+  AC_MSG_RESULT([$apu_version])
+
+  dnl Get build information from APU
+
+  LDFLAGS="$LDFLAGS `$apu_config --ldflags`"
+
+  UNIMRCP_APU_INCLUDES="`$apu_config --includes`"
+  UNIMRCP_APU_LIBS="`$apu_config --link-libtool --libs`"
+
+  AC_SUBST(UNIMRCP_APU_INCLUDES)
+  AC_SUBST(UNIMRCP_APU_LIBS)
+])
+
+dnl UNIMRCP_DOWNLOAD_APU
+dnl no apr-util found, print out a message telling the user what to do
+AC_DEFUN([UNIMRCP_DOWNLOAD_APU],
+[
+  echo "The Apache Portable Runtime Utility (APU) library cannot be found."
+  echo "Please install APRUTIL on this system and supply the appropriate"
+  echo "--with-apr-util option to 'configure'"
+  AC_MSG_ERROR([no suitable APU found])
+])
diff --git a/libs/unimrcp/build/acmacros/find_apr.m4 b/libs/unimrcp/build/acmacros/find_apr.m4
new file mode 100644 (file)
index 0000000..048cb7b
--- /dev/null
@@ -0,0 +1,167 @@
+dnl -------------------------------------------------------- -*- autoconf -*-
+dnl Licensed to the Apache Software Foundation (ASF) under one or more
+dnl contributor license agreements.  See the NOTICE file distributed with
+dnl this work for additional information regarding copyright ownership.
+dnl The ASF licenses this file to You under the Apache License, Version 2.0
+dnl (the "License"); you may not use this file except in compliance with
+dnl the License.  You may obtain a copy of the License at
+dnl
+dnl     http://www.apache.org/licenses/LICENSE-2.0
+dnl
+dnl Unless required by applicable law or agreed to in writing, software
+dnl distributed under the License is distributed on an "AS IS" BASIS,
+dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+dnl See the License for the specific language governing permissions and
+dnl limitations under the License.
+
+dnl
+dnl find_apr.m4 : locate the APR include files and libraries
+dnl
+dnl This macro file can be used by applications to find and use the APR
+dnl library. It provides a standardized mechanism for using APR. It supports
+dnl embedding APR into the application source, or locating an installed
+dnl copy of APR.
+dnl
+dnl APR_FIND_APR(srcdir, builddir, implicit-install-check, acceptable-majors)
+dnl
+dnl   where srcdir is the location of the bundled APR source directory, or
+dnl   empty if source is not bundled.
+dnl
+dnl   where builddir is the location where the bundled APR will will be built,
+dnl   or empty if the build will occur in the srcdir.
+dnl
+dnl   where implicit-install-check set to 1 indicates if there is no
+dnl   --with-apr option specified, we will look for installed copies.
+dnl
+dnl   where acceptable-majors is a space separated list of acceptable major
+dnl   version numbers. Often only a single major version will be acceptable.
+dnl   If multiple versions are specified, and --with-apr=PREFIX or the
+dnl   implicit installed search are used, then the first (leftmost) version
+dnl   in the list that is found will be used.  Currently defaults to [0 1].
+dnl
+dnl Sets the following variables on exit:
+dnl
+dnl   apr_found : "yes", "no", "reconfig"
+dnl
+dnl   apr_config : If the apr-config tool exists, this refers to it. If
+dnl                apr_found is "reconfig", then the bundled directory
+dnl                should be reconfigured *before* using apr_config.
+dnl
+dnl Note: this macro file assumes that apr-config has been installed; it
+dnl       is normally considered a required part of an APR installation.
+dnl
+dnl If a bundled source directory is available and needs to be (re)configured,
+dnl then apr_found is set to "reconfig". The caller should reconfigure the
+dnl (passed-in) source directory, placing the result in the build directory,
+dnl as appropriate.
+dnl
+dnl If apr_found is "yes" or "reconfig", then the caller should use the
+dnl value of apr_config to fetch any necessary build/link information.
+dnl
+
+AC_DEFUN([APR_FIND_APR], [
+  apr_found="no"
+
+  if test "$target_os" = "os2-emx"; then
+    # Scripts don't pass test -x on OS/2
+    TEST_X="test -f"
+  else
+    TEST_X="test -x"
+  fi
+
+  ifelse([$4], [], [
+         ifdef(AC_WARNING,AC_WARNING([$0: missing argument 4 (acceptable-majors): Defaulting to APR 0.x then APR 1.x]))
+         acceptable_majors="0 1"],
+         [acceptable_majors="$4"])
+
+  apr_temp_acceptable_apr_config=""
+  for apr_temp_major in $acceptable_majors
+  do
+    case $apr_temp_major in
+      0)
+      apr_temp_acceptable_apr_config="$apr_temp_acceptable_apr_config apr-config"
+      ;;
+      *)
+      apr_temp_acceptable_apr_config="$apr_temp_acceptable_apr_config apr-$apr_temp_major-config"
+      ;;
+    esac
+  done
+
+  AC_MSG_CHECKING(for APR)
+  AC_ARG_WITH(apr,
+  [  --with-apr=PATH         prefix for installed APR, path to APR build tree,
+                          or the full path to apr-config],
+  [
+    if test "$withval" = "no" || test "$withval" = "yes"; then
+      AC_MSG_ERROR([--with-apr requires a directory or file to be provided])
+    fi
+
+    for apr_temp_apr_config_file in $apr_temp_acceptable_apr_config
+    do
+      for lookdir in "$withval/bin" "$withval"
+      do
+        if $TEST_X "$lookdir/$apr_temp_apr_config_file"; then
+          apr_found="yes"
+          apr_config="$lookdir/$apr_temp_apr_config_file"
+          break 2
+        fi
+      done
+    done
+
+    if test "$apr_found" != "yes" && $TEST_X "$withval" && $withval --help > /dev/null 2>&1 ; then
+      apr_found="yes"
+      apr_config="$withval"
+    fi
+
+    dnl if --with-apr is used, it is a fatal error for its argument
+    dnl to be invalid
+    if test "$apr_found" != "yes"; then
+      AC_MSG_ERROR([the --with-apr parameter is incorrect. It must specify an install prefix, a build directory, or an apr-config file.])
+    fi
+  ],[
+    dnl If we allow installed copies, check those before using bundled copy.
+    if test -n "$3" && test "$3" = "1"; then
+      for apr_temp_apr_config_file in $apr_temp_acceptable_apr_config
+      do
+        if $apr_temp_apr_config_file --help > /dev/null 2>&1 ; then
+          apr_found="yes"
+          apr_config="$apr_temp_apr_config_file"
+          break
+        else
+          dnl look in some standard places
+          for lookdir in /usr /usr/local /usr/local/apr /opt/apr; do
+            if $TEST_X "$lookdir/bin/$apr_temp_apr_config_file"; then
+              apr_found="yes"
+              apr_config="$lookdir/bin/$apr_temp_apr_config_file"
+              break 2
+            fi
+          done
+        fi
+      done
+    fi
+    dnl if we have not found anything yet and have bundled source, use that
+    if test "$apr_found" = "no" && test -d "$1"; then
+      apr_temp_abs_srcdir="`cd $1 && pwd`"
+      apr_found="reconfig"
+      apr_bundled_major="`sed -n '/#define.*APR_MAJOR_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p' \"$1/include/apr_version.h\"`"
+      case $apr_bundled_major in
+        "")
+          AC_MSG_ERROR([failed to find major version of bundled APR])
+        ;;
+        0)
+          apr_temp_apr_config_file="apr-config"
+        ;;
+        *)
+          apr_temp_apr_config_file="apr-$apr_bundled_major-config"
+        ;;
+      esac
+      if test -n "$2"; then
+        apr_config="$2/$apr_temp_apr_config_file"
+      else
+        apr_config="$1/$apr_temp_apr_config_file"
+      fi
+    fi
+  ])
+
+  AC_MSG_RESULT($apr_found)
+])
diff --git a/libs/unimrcp/build/acmacros/find_apu.m4 b/libs/unimrcp/build/acmacros/find_apu.m4
new file mode 100644 (file)
index 0000000..e29bc60
--- /dev/null
@@ -0,0 +1,176 @@
+dnl -------------------------------------------------------- -*- autoconf -*-
+dnl Copyright 2002-2005 The Apache Software Foundation or its licensors, as
+dnl applicable.
+dnl
+dnl Licensed under the Apache License, Version 2.0 (the "License");
+dnl you may not use this file except in compliance with the License.
+dnl You may obtain a copy of the License at
+dnl
+dnl     http://www.apache.org/licenses/LICENSE-2.0
+dnl
+dnl Unless required by applicable law or agreed to in writing, software
+dnl distributed under the License is distributed on an "AS IS" BASIS,
+dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+dnl See the License for the specific language governing permissions and
+dnl limitations under the License.
+
+dnl
+dnl find_apu.m4 : locate the APR-util (APU) include files and libraries
+dnl
+dnl This macro file can be used by applications to find and use the APU
+dnl library. It provides a standardized mechanism for using APU. It supports
+dnl embedding APU into the application source, or locating an installed
+dnl copy of APU.
+dnl
+dnl APR_FIND_APU(srcdir, builddir, implicit-install-check, acceptable-majors)
+dnl
+dnl   where srcdir is the location of the bundled APU source directory, or
+dnl   empty if source is not bundled.
+dnl
+dnl   where builddir is the location where the bundled APU will be built,
+dnl   or empty if the build will occur in the srcdir.
+dnl
+dnl   where implicit-install-check set to 1 indicates if there is no
+dnl   --with-apr-util option specified, we will look for installed copies.
+dnl
+dnl   where acceptable-majors is a space separated list of acceptable major
+dnl   version numbers. Often only a single major version will be acceptable.
+dnl   If multiple versions are specified, and --with-apr-util=PREFIX or the
+dnl   implicit installed search are used, then the first (leftmost) version
+dnl   in the list that is found will be used.  Currently defaults to [0 1].
+dnl
+dnl Sets the following variables on exit:
+dnl
+dnl   apu_found : "yes", "no", "reconfig"
+dnl
+dnl   apu_config : If the apu-config tool exists, this refers to it.  If
+dnl                apu_found is "reconfig", then the bundled directory
+dnl                should be reconfigured *before* using apu_config.
+dnl
+dnl Note: this macro file assumes that apr-config has been installed; it
+dnl       is normally considered a required part of an APR installation.
+dnl
+dnl Note: At this time, we cannot find *both* a source dir and a build dir.
+dnl       If both are available, the build directory should be passed to
+dnl       the --with-apr-util switch.
+dnl
+dnl Note: the installation layout is presumed to follow the standard
+dnl       PREFIX/lib and PREFIX/include pattern. If the APU config file
+dnl       is available (and can be found), then non-standard layouts are
+dnl       possible, since it will be described in the config file.
+dnl
+dnl If a bundled source directory is available and needs to be (re)configured,
+dnl then apu_found is set to "reconfig". The caller should reconfigure the
+dnl (passed-in) source directory, placing the result in the build directory,
+dnl as appropriate.
+dnl
+dnl If apu_found is "yes" or "reconfig", then the caller should use the
+dnl value of apu_config to fetch any necessary build/link information.
+dnl
+
+AC_DEFUN([APR_FIND_APU], [
+  apu_found="no"
+
+  if test "$target_os" = "os2-emx"; then
+    # Scripts don't pass test -x on OS/2
+    TEST_X="test -f"
+  else
+    TEST_X="test -x"
+  fi
+
+  ifelse([$4], [],
+  [
+    ifdef(AC_WARNING,([$0: missing argument 4 (acceptable-majors): Defaulting to APU 0.x then APU 1.x]))
+    acceptable_majors="0 1"
+  ], [acceptable_majors="$4"])
+
+  apu_temp_acceptable_apu_config=""
+  for apu_temp_major in $acceptable_majors
+  do
+    case $apu_temp_major in
+      0)
+      apu_temp_acceptable_apu_config="$apu_temp_acceptable_apu_config apu-config"
+      ;;
+      *)
+      apu_temp_acceptable_apu_config="$apu_temp_acceptable_apu_config apu-$apu_temp_major-config"
+      ;;
+    esac
+  done
+
+  AC_MSG_CHECKING(for APR-util)
+  AC_ARG_WITH(apr-util,
+  [  --with-apr-util=PATH    prefix for installed APU, path to APU build tree,
+                          or the full path to apu-config],
+  [
+    if test "$withval" = "no" || test "$withval" = "yes"; then
+      AC_MSG_ERROR([--with-apr-util requires a directory or file to be provided])
+    fi
+
+    for apu_temp_apu_config_file in $apu_temp_acceptable_apu_config
+    do
+      for lookdir in "$withval/bin" "$withval"
+      do
+        if $TEST_X "$lookdir/$apu_temp_apu_config_file"; then
+          apu_found="yes"
+          apu_config="$lookdir/$apu_temp_apu_config_file"
+          break 2
+        fi
+      done
+    done
+
+    if test "$apu_found" != "yes" && $TEST_X "$withval" && $withval --help > /dev/null 2>&1 ; then
+      apu_found="yes"
+      apu_config="$withval"
+    fi
+
+    dnl if --with-apr-util is used, it is a fatal error for its argument
+    dnl to be invalid
+    if test "$apu_found" != "yes"; then
+      AC_MSG_ERROR([the --with-apr-util parameter is incorrect. It must specify an install prefix, a build directory, or an apu-config file.])
+    fi
+  ],[
+    if test -n "$3" && test "$3" = "1"; then
+      for apu_temp_apu_config_file in $apu_temp_acceptable_apu_config
+      do
+        if $apu_temp_apu_config_file --help > /dev/null 2>&1 ; then
+          apu_found="yes"
+          apu_config="$apu_temp_apu_config_file"
+          break
+        else
+          dnl look in some standard places (apparently not in builtin/default)
+          for lookdir in /usr /usr/local /usr/local/apr /opt/apr /usr/local/apache2 ; do
+            if $TEST_X "$lookdir/bin/$apu_temp_apu_config_file"; then
+              apu_found="yes"
+              apu_config="$lookdir/bin/$apu_temp_apu_config_file"
+              break 2
+            fi
+          done
+        fi
+      done
+    fi
+    dnl if we have not found anything yet and have bundled source, use that
+    if test "$apu_found" = "no" && test -d "$1"; then
+      apu_temp_abs_srcdir="`cd $1 && pwd`"
+      apu_found="reconfig"
+      apu_bundled_major="`sed -n '/#define.*APU_MAJOR_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p' \"$1/include/apu_version.h\"`"
+      case $apu_bundled_major in
+        "")
+          AC_MSG_ERROR([failed to find major version of bundled APU])
+        ;;
+        0)
+          apu_temp_apu_config_file="apu-config"
+        ;;
+        *)
+          apu_temp_apu_config_file="apu-$apu_bundled_major-config"
+        ;;
+      esac
+      if test -n "$2"; then
+        apu_config="$2/$apu_temp_apu_config_file"
+      else
+        apu_config="$1/$apu_temp_apu_config_file"
+      fi
+    fi
+  ])
+
+  AC_MSG_RESULT($apu_found)
+])
diff --git a/libs/unimrcp/build/acmacros/sofia-sip.m4 b/libs/unimrcp/build/acmacros/sofia-sip.m4
new file mode 100644 (file)
index 0000000..aefc062
--- /dev/null
@@ -0,0 +1,49 @@
+dnl UNIMRCP_CHECK_SOFIA
+
+AC_DEFUN([UNIMRCP_CHECK_SOFIA],
+[  
+    AC_MSG_NOTICE([Sofia SIP library configuration])
+
+    AC_MSG_CHECKING([for Sofia-SIP])
+    AC_ARG_WITH(sofia-sip,
+                [  --with-sofia-sip=PATH   prefix for installed Sofia-SIP or
+                          path to Sofia-SIP build tree],
+                [sofia_path=$withval],
+                [sofia_path="/usr/local"]
+                )
+    
+    sofiaconfig="lib/pkgconfig/sofia-sip-ua.pc"
+    sofiasrcdir="libsofia-sip-ua"
+    for dir in $sofia_path ; do
+        cd $dir && sofiadir=`pwd` && cd - > /dev/null
+        if test -f "$dir/$sofiaconfig"; then
+            found_sofia="yes"
+            UNIMRCP_SOFIA_INCLUDES="`pkg-config --cflags $dir/$sofiaconfig`"
+            UNIMRCP_SOFIA_LIBS="`pkg-config --libs $dir/$sofiaconfig`"
+           sofia_version="`pkg-config --modversion $dir/$sofiaconfig`"
+            break
+        fi
+        if test -d "$dir/$sofiasrcdir"; then
+            found_sofia="yes"
+            UNIMRCP_SOFIA_INCLUDES="-I$sofiadir/$sofiasrcdir -I$sofiadir/$sofiasrcdir/bnf -I$sofiadir/$sofiasrcdir/features -I$sofiadir/$sofiasrcdir/http -I$sofiadir/$sofiasrcdir/ipt -I$sofiadir/$sofiasrcdir/iptsec -I$sofiadir/$sofiasrcdir/msg -I$sofiadir/$sofiasrcdir/nea -I$sofiadir/$sofiasrcdir/nta -I$sofiadir/$sofiasrcdir/nth -I$sofiadir/$sofiasrcdir/nua -I$sofiadir/$sofiasrcdir/sdp -I$sofiadir/$sofiasrcdir/sip -I$sofiadir/$sofiasrcdir/soa -I$sofiadir/$sofiasrcdir/sresolv -I$sofiadir/$sofiasrcdir/stun -I$sofiadir/$sofiasrcdir/su -I$sofiadir/$sofiasrcdir/tport -I$sofiadir/$sofiasrcdir/url"
+            UNIMRCP_SOFIA_LIBS="$sofiadir/$sofiasrcdir/libsofia-sip-ua.la"
+           sofia_version="`pkg-config --modversion $sofiadir/packages/sofia-sip-ua.pc`"
+            break
+        fi
+    done
+
+    if test x_$found_sofia != x_yes; then
+        AC_MSG_ERROR(Cannot find Sofia-SIP - looked for sofia-config:$sofiaconfig and srcdir:$sofiasrcdir in $sofia_path)
+    else
+        AC_MSG_RESULT([$found_sofia])
+        AC_MSG_RESULT([$sofia_version])
+
+case "$host" in
+    *darwin*)
+       UNIMRCP_SOFIA_LIBS="$UNIMRCP_SOFIA_LIBS -framework CoreFoundation -framework SystemConfiguration"                                                                ;;
+esac
+
+        AC_SUBST(UNIMRCP_SOFIA_INCLUDES)
+        AC_SUBST(UNIMRCP_SOFIA_LIBS)
+    fi
+])
diff --git a/libs/unimrcp/build/acmacros/swift.m4 b/libs/unimrcp/build/acmacros/swift.m4
new file mode 100644 (file)
index 0000000..c3730b9
--- /dev/null
@@ -0,0 +1,30 @@
+dnl UNIMRCP_CHECK_SWIFT
+
+AC_DEFUN([UNIMRCP_CHECK_SWIFT],
+[  
+    AC_MSG_NOTICE([Cepstral Swift library configuration])
+
+    AC_MSG_CHECKING([for Swift])
+    AC_ARG_WITH(swift,
+                [  --with-swift=PATH       prefix for installed Swift],
+                [swift_path=$withval],
+                [swift_path="/opt/swift"]
+                )
+    
+    if test -d "$swift_path"; then
+        found_swift="yes"
+        UNIMRCP_SWIFT_INCLUDES="-I$swift_path/include"
+        UNIMRCP_SWIFT_LIBS="-lswift -lceplex_us -lceplang_en -lm"
+        UNIMRCP_SWIFT_LDFLAGS="-L$swift_path/lib/ -R$swift_path/lib/"
+
+        AC_SUBST(UNIMRCP_SWIFT_INCLUDES)
+        AC_SUBST(UNIMRCP_SWIFT_LIBS)
+        AC_SUBST(UNIMRCP_SWIFT_LDFLAGS)
+        
+       AC_MSG_RESULT($swift_path)
+    else
+       AC_MSG_WARN([not found - looked for $swift_path])
+    fi
+
+    AM_CONDITIONAL([CEPSTRAL_PLUGIN], [test x_$found_swift = x_yes])
+])
diff --git a/libs/unimrcp/build/get-version.sh b/libs/unimrcp/build/get-version.sh
new file mode 100755 (executable)
index 0000000..fd685b2
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# extract version numbers from a header file
+#
+# USAGE: get-version.sh CMD VERSION_HEADER PREFIX
+#   where CMD is one of: all, major, libtool
+#   where PREFIX is the prefix to {MAJOR|MINOR|PATCH}_VERSION defines
+#
+#   get-version.sh all returns a dotted version number
+#   get-version.sh major returns just the major version number
+#   get-version.sh libtool returns a version "libtool -version-info" format
+#
+
+if test $# != 3; then
+  echo "USAGE: $0 CMD VERSION_HEADER PREFIX"
+  echo "  where CMD is one of: all, major, libtool"
+  exit 1
+fi
+
+major_sed="/#define.*$3_MAJOR_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p"
+minor_sed="/#define.*$3_MINOR_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p"
+patch_sed="/#define.*$3_PATCH_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p"
+major="`sed -n $major_sed $2`"
+minor="`sed -n $minor_sed $2`"
+patch="`sed -n $patch_sed $2`"
+
+if test "$1" = "all"; then
+  echo ${major}.${minor}.${patch}
+elif test "$1" = "major"; then
+  echo ${major}
+elif test "$1" = "libtool"; then
+  # Yes, ${minor}:${patch}:${minor} is correct due to libtool idiocy.
+  echo ${minor}:${patch}:${minor}
+else
+  echo "ERROR: unknown version CMD ($1)"
+  exit 1
+fi
diff --git a/libs/unimrcp/build/pkgconfig/Makefile.am b/libs/unimrcp/build/pkgconfig/Makefile.am
new file mode 100644 (file)
index 0000000..ce3a063
--- /dev/null
@@ -0,0 +1,4 @@
+MAINTAINERCLEANFILES   = Makefile.in
+
+pkgconfigdir           = $(libdir)/pkgconfig
+pkgconfig_DATA         = unimrcpclient.pc unimrcpserver.pc unimrcpplugin.pc
diff --git a/libs/unimrcp/build/pkgconfig/unimrcpclient.pc.in b/libs/unimrcp/build/pkgconfig/unimrcpclient.pc.in
new file mode 100644 (file)
index 0000000..7fe3f1c
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@ @UNIMRCP_APR_INCLUDES@
+
+Name: unimrcpclient
+Description: UniMRCP Client Stack
+Requires: 
+Version: @UNI_DOTTED_VERSION@
+Libs: -L${libdir} -lunimrcpclient
+Cflags: @CPPFLAGS@ @CFLAGS@ -I${includedir}
diff --git a/libs/unimrcp/build/pkgconfig/unimrcpplugin.pc.in b/libs/unimrcp/build/pkgconfig/unimrcpplugin.pc.in
new file mode 100644 (file)
index 0000000..df78b8e
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@ @UNIMRCP_APR_INCLUDES@
+
+Name: unimrcpplugin
+Description: UniMRCP Server Plugin
+Requires: 
+Version: @UNI_DOTTED_VERSION@
+Libs: -L${libdir} -lunimrcpserver
+Cflags: @CPPFLAGS@ @CFLAGS@ -I${includedir}
diff --git a/libs/unimrcp/build/pkgconfig/unimrcpserver.pc.in b/libs/unimrcp/build/pkgconfig/unimrcpserver.pc.in
new file mode 100644 (file)
index 0000000..3ed91ec
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@ @UNIMRCP_APR_INCLUDES@
+
+Name: unimrcpserver
+Description: UniMRCP Server Stack
+Requires: 
+Version: @UNI_DOTTED_VERSION@
+Libs: -L${libdir} -lunimrcpserver
+Cflags: @CPPFLAGS@ @CFLAGS@ -I${includedir}
diff --git a/libs/unimrcp/build/tools/prepare.vcproj b/libs/unimrcp/build/tools/prepare.vcproj
new file mode 100644 (file)
index 0000000..c296a0e
--- /dev/null
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="prepare"
+       ProjectGUID="{01D63BF5-7798-4746-852A-4B45229BB735}"
+       RootNamespace="prepare"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+                       IntermediateDirectory="$(ConfigurationName)"
+                       ConfigurationType="10"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\apr.vsprops;$(SolutionDir)build\vsprops\sofiasip.vsprops"
+                       CharacterSet="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                               CommandLine="xcopy &quot;$(AprDir)\$(ConfigurationName)\libapr-1.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;xcopy &quot;$(AprUtilDir)\$(ConfigurationName)\libaprutil-1.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;xcopy &quot;$(AprIconvDir)\$(ConfigurationName)\libapriconv-1.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;xcopy &quot;$(SofiaDir)\win32\libsofia-sip-ua\$(ConfigurationName)\libsofia_sip_ua.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;xcopy &quot;$(SofiaDir)\win32\pthread\pthreadVC2.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;&#x0D;&#x0A;if not exist &quot;$(SolutionDir)$(ConfigurationName)\conf&quot; xcopy &quot;$(SolutionDir)conf\*.xml&quot; &quot;$(SolutionDir)$(ConfigurationName)\conf\&quot; /Y&#x0D;&#x0A;if not exist &quot;$(SolutionDir)$(ConfigurationName)\data&quot; xcopy &quot;$(SolutionDir)data\*&quot; &quot;$(SolutionDir)$(ConfigurationName)\data\&quot; /Y&#x0D;&#x0A;if not exist &quot;$(SolutionDir)$(ConfigurationName)\log&quot; mkdir &quot;$(SolutionDir)$(ConfigurationName)\log\&quot;&#x0D;&#x0A;"
+                               ExcludedFromBuild="false"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="10"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\apr.vsprops;$(SolutionDir)build\vsprops\sofiasip.vsprops"
+                       CharacterSet="1"
+                       WholeProgramOptimization="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                               CommandLine="xcopy &quot;$(AprDir)\$(ConfigurationName)\libapr-1.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;xcopy &quot;$(AprUtilDir)\$(ConfigurationName)\libaprutil-1.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;xcopy &quot;$(AprIconvDir)\$(ConfigurationName)\libapriconv-1.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;xcopy &quot;$(SofiaDir)\win32\libsofia-sip-ua\$(ConfigurationName)\libsofia_sip_ua.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;xcopy &quot;$(SofiaDir)\win32\pthread\pthreadVC2.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;&#x0D;&#x0A;if not exist &quot;$(SolutionDir)$(ConfigurationName)\conf&quot; xcopy &quot;$(SolutionDir)conf\*.xml&quot; &quot;$(SolutionDir)$(ConfigurationName)\conf\&quot; /Y&#x0D;&#x0A;if not exist &quot;$(SolutionDir)$(ConfigurationName)\data&quot; xcopy &quot;$(SolutionDir)data\*&quot; &quot;$(SolutionDir)$(ConfigurationName)\data\&quot; /Y&#x0D;&#x0A;if not exist &quot;$(SolutionDir)$(ConfigurationName)\log&quot; mkdir &quot;$(SolutionDir)$(ConfigurationName)\log\&quot;&#x0D;&#x0A;"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/build/tools/unimrcp_service.c b/libs/unimrcp/build/tools/unimrcp_service.c
new file mode 100644 (file)
index 0000000..b8a1bd7
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <windows.h>
+#include <apr_getopt.h>
+#include "apt.h"
+#include "apt_pool.h"
+
+#define WIN_SERVICE_NAME "unimrcp"
+
+
+/** Register/install service in SCM */
+static apt_bool_t uni_service_register(const char *root_dir_path, apr_pool_t *pool)
+{
+       char *bin_path;
+       SERVICE_DESCRIPTION desc;
+       SC_HANDLE sch_service;
+       SC_HANDLE sch_manager = OpenSCManager(0,0,SC_MANAGER_ALL_ACCESS);
+       if(!sch_manager) {
+               printf("Failed to Open SCManager %d\n", GetLastError());
+               return FALSE;
+       }
+
+       bin_path = apr_psprintf(pool,"%s\\bin\\unimrcpserver.exe --service --root-dir \"%s\" -o 2",
+                                       root_dir_path,
+                                       root_dir_path);
+       sch_service = CreateService(
+                                       sch_manager,
+                                       WIN_SERVICE_NAME,
+                                       "UniMRCP Server",
+                                       GENERIC_EXECUTE | SERVICE_CHANGE_CONFIG,
+                                       SERVICE_WIN32_OWN_PROCESS,
+                                       SERVICE_DEMAND_START,
+                                       SERVICE_ERROR_NORMAL,
+                                       bin_path,0,0,0,0,0);
+       if(!sch_service) {
+               printf("Failed to Create Service %d\n", GetLastError());
+               CloseServiceHandle(sch_manager);
+               return FALSE;
+       }
+
+       desc.lpDescription = "Launches UniMRCP Server";
+       if(!ChangeServiceConfig2(sch_service,SERVICE_CONFIG_DESCRIPTION,&desc)) {
+               printf("Failed to Set Service Description %d\n", GetLastError());
+       }
+
+       CloseServiceHandle(sch_service);
+       CloseServiceHandle(sch_manager);
+       return TRUE;
+}
+
+/** Unregister/uninstall service from SCM */
+static apt_bool_t uni_service_unregister()
+{
+       apt_bool_t status = TRUE;
+       SERVICE_STATUS ss_status;
+       SC_HANDLE sch_service;
+       SC_HANDLE sch_manager = OpenSCManager(0,0,SC_MANAGER_ALL_ACCESS);
+       if(!sch_manager) {
+               printf("Failed to Open SCManager %d\n", GetLastError());
+               return FALSE;
+       }
+
+       sch_service = OpenService(sch_manager,WIN_SERVICE_NAME,DELETE|SERVICE_STOP);
+       if(!sch_service) {
+               printf("Failed to Open Service %d\n", GetLastError());
+               CloseServiceHandle(sch_manager);
+               return FALSE;
+       }
+
+       ControlService(sch_service,SERVICE_CONTROL_STOP,&ss_status);
+       if(!DeleteService(sch_service)) {
+               printf("Failed to Delete Service %d\n", GetLastError());
+               status = FALSE;
+       }
+       CloseServiceHandle(sch_service);
+       CloseServiceHandle(sch_manager);
+       return status;
+}
+
+/** Start service */
+static apt_bool_t uni_service_start()
+{
+       apt_bool_t status = TRUE;
+       SC_HANDLE sch_service;
+       SC_HANDLE sch_manager = OpenSCManager(0,0,SC_MANAGER_ALL_ACCESS);
+       if(!sch_manager) {
+               printf("Failed to Open SCManager %d\n", GetLastError());
+               return FALSE;
+       }
+
+       sch_service = OpenService(sch_manager,WIN_SERVICE_NAME,SERVICE_START);
+       if(!sch_service) {
+               printf("Failed to Open Service %d\n", GetLastError());
+               CloseServiceHandle(sch_manager);
+               return FALSE;
+       }
+
+       if(!StartService(sch_service,0,NULL)) {
+               printf("Failed to Start Service %d\n", GetLastError());
+               status = FALSE;
+       }
+       CloseServiceHandle(sch_service);
+       CloseServiceHandle(sch_manager);
+       return status;
+}
+
+/** Stop service */
+static apt_bool_t uni_service_stop()
+{
+       apt_bool_t status = TRUE;
+       SERVICE_STATUS ss_status;
+       SC_HANDLE sch_service;
+       SC_HANDLE sch_manager = OpenSCManager(0,0,SC_MANAGER_ALL_ACCESS);
+       if(!sch_manager) {
+               printf("Failed to Open SCManager %d\n", GetLastError());
+               return FALSE;
+       }
+
+       sch_service = OpenService(sch_manager,WIN_SERVICE_NAME,SERVICE_STOP);
+       if(!sch_service) {
+               printf("Failed to Open Service %d\n", GetLastError());
+               CloseServiceHandle(sch_manager);
+               return FALSE;
+       }
+
+       if(!ControlService(sch_service,SERVICE_CONTROL_STOP,&ss_status)) {
+               printf("Failed to Stop Service %d\n", GetLastError());
+               status = FALSE;
+       }
+
+       CloseServiceHandle(sch_service);
+       CloseServiceHandle(sch_manager);
+       return status;
+}
+
+
+static void usage()
+{
+       printf(
+               "\n"
+               "Usage:\n"
+               "\n"
+               "  unimrcpservice [options]\n"
+               "\n"
+               "  Available options:\n"
+               "\n"
+               "   -r [--register] rootdir : Register the Windows service.\n"
+               "\n"
+               "   -u [--unregister]       : Unregister the Windows service.\n"
+               "\n"
+               "   -s [--start]            : Start the Windows service.\n"
+               "\n"
+               "   -t [--stop]             : Stop the Windows service.\n"
+               "\n"
+               "   -h [--help]             : Show the help.\n"
+               "\n");
+}
+
+int main(int argc, const char * const *argv)
+{
+       apr_pool_t *pool;
+       apr_status_t rv;
+       apr_getopt_t *opt;
+
+       static const apr_getopt_option_t opt_option[] = {
+               /* long-option, short-option, has-arg flag, description */
+               { "register",   'r', TRUE,  "register service" },  /* -r or --register arg */
+               { "unregister", 'u', FALSE, "unregister service" },/* -u or --unregister */
+               { "start",      's', FALSE, "start service" },     /* -s or --start */
+               { "stop",       't', FALSE, "stop service" },      /* -t or --stop */
+               { "help",       'h', FALSE, "show help" },         /* -h or --help */
+               { NULL, 0, 0, NULL },                               /* end */
+       };
+
+       /* APR global initialization */
+       if(apr_initialize() != APR_SUCCESS) {
+               apr_terminate();
+               return 0;
+       }
+
+       /* create APR pool */
+       pool = apt_pool_create();
+       if(!pool) {
+               apr_terminate();
+               return 0;
+       }
+
+       rv = apr_getopt_init(&opt, pool , argc, argv);
+       if(rv == APR_SUCCESS) {
+               int optch;
+               const char *optarg;
+               while((rv = apr_getopt_long(opt, opt_option, &optch, &optarg)) == APR_SUCCESS) {
+                       switch(optch) {
+                               case 'r':
+                                       uni_service_register(optarg,pool);
+                                       break;
+                               case 'u':
+                                       uni_service_unregister();
+                                       break;
+                               case 's':
+                                       uni_service_start();
+                                       break;
+                               case 't':
+                                       uni_service_stop();
+                                       break;
+                               case 'h':
+                                       usage();
+                                       break;
+                       }
+               }
+               if(rv != APR_EOF) {
+                       usage();
+               }
+       }
+
+       /* destroy APR pool */
+       apr_pool_destroy(pool);
+       /* APR global termination */
+       apr_terminate();
+       return 0;
+}
diff --git a/libs/unimrcp/build/tools/unimrcpservice.exe.manifest b/libs/unimrcp/build/tools/unimrcpservice.exe.manifest
new file mode 100644 (file)
index 0000000..3a14ebf
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\r
+  <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="<AppName>" type="win32"/>\r
+  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">\r
+    <security>\r
+      <requestedPrivileges>\r
+        <requestedExecutionLevel level="requireAdministrator"/>\r
+      </requestedPrivileges>\r
+    </security>\r
+  </trustInfo>\r
+</assembly>\r
diff --git a/libs/unimrcp/build/tools/unimrcpservice.vcproj b/libs/unimrcp/build/tools/unimrcpservice.vcproj
new file mode 100644 (file)
index 0000000..abddf90
--- /dev/null
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="unimrcpservice"
+       ProjectGUID="{4714EF49-BFD5-4B22-95F7-95A07F1EAC25}"
+       RootNamespace="unimrcpservice"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\apt.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="libaprutil-1.lib libapr-1.lib"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                               AdditionalManifestFiles="unimrcpservice.exe.manifest"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\apt.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="libaprutil-1.lib libapr-1.lib"
+                               LinkTimeCodeGeneration="1"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                               AdditionalManifestFiles="unimrcpservice.exe.manifest"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+                       >
+                       <File
+                               RelativePath=".\unimrcp_service.c"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/build/uni_version.h b/libs/unimrcp/build/uni_version.h
new file mode 100644 (file)
index 0000000..b453927
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UNI_VERSION_H__
+#define __UNI_VERSION_H__
+
+/**
+ * @file uni_version.h
+ * @brief UniMRCP Version Numbering
+ * 
+ * UniMRCP version numbering is derived from APR project specified in:
+ *
+ *     http://apr.apache.org/versioning.html
+ */
+
+#include <apr_version.h>
+
+/** major version 
+ * Major API changes that could cause compatibility problems for older
+ * programs such as structure size changes.  No binary compatibility is
+ * possible across a change in the major version.
+ */
+#define UNI_MAJOR_VERSION   0
+
+/** minor version
+ * Minor API changes that do not cause binary compatibility problems.
+ * Reset to 0 when upgrading UNI_MAJOR_VERSION
+ */
+#define UNI_MINOR_VERSION   6
+
+/** patch level 
+ * The Patch Level never includes API changes, simply bug fixes.
+ * Reset to 0 when upgrading UNI_MINOR_VERSION
+ */
+#define UNI_PATCH_VERSION   0
+
+
+/**
+ * Check at compile time if the UNI version is at least a certain
+ * level.
+ */
+#define UNI_VERSION_AT_LEAST(major,minor,patch)                    \
+(((major) < UNI_MAJOR_VERSION)                                     \
+ || ((major) == UNI_MAJOR_VERSION && (minor) < UNI_MINOR_VERSION) \
+ || ((major) == UNI_MAJOR_VERSION && (minor) == UNI_MINOR_VERSION && (patch) <= UNI_PATCH_VERSION))
+
+/** The formatted string of UniMRCP's version */
+#define UNI_VERSION_STRING \
+     APR_STRINGIFY(UNI_MAJOR_VERSION) "." \
+     APR_STRINGIFY(UNI_MINOR_VERSION) "." \
+     APR_STRINGIFY(UNI_PATCH_VERSION)
+
+#endif /* __UNI_VERSION_H__ */
diff --git a/libs/unimrcp/build/vsprops/apr.vsprops b/libs/unimrcp/build/vsprops/apr.vsprops
new file mode 100644 (file)
index 0000000..3cc1c96
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="apr"
+       InheritedPropertySheets="$(SolutionDir)build\vsprops\unibase.vsprops"
+       >
+       <Tool
+               Name="VCCLCompilerTool"
+               AdditionalIncludeDirectories="&quot;$(AprDir)\include&quot;;&quot;$(AprUtilDir)\include&quot;"
+       />
+       <Tool
+               Name="VCLinkerTool"
+               AdditionalLibraryDirectories="&quot;$(AprDir)\$(ConfigurationName)&quot;;&quot;$(AprUtilDir)\$(ConfigurationName)&quot;"
+       />
+       <UserMacro
+               Name="AprDir"
+               Value="$(ProjectRootDir)libs\apr"
+       />
+       <UserMacro
+               Name="AprUtilDir"
+               Value="$(ProjectRootDir)libs\apr-util"
+       />
+       <UserMacro
+               Name="AprIconvDir"
+               Value="$(ProjectRootDir)libs\apr-iconv"
+       />
+</VisualStudioPropertySheet>
diff --git a/libs/unimrcp/build/vsprops/apt.vsprops b/libs/unimrcp/build/vsprops/apt.vsprops
new file mode 100644 (file)
index 0000000..263579c
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="apt"
+       InheritedPropertySheets="apr.vsprops"
+       >
+       <Tool
+               Name="VCCLCompilerTool"
+               AdditionalIncludeDirectories="&quot;$(ProjectRootDir)libs\apr-toolkit\include&quot;"
+               PreprocessorDefinitions="APT_STATIC_LIB"
+       />
+       <Tool
+               Name="VCLinkerTool"
+               AdditionalLibraryDirectories="&quot;$(OutDir)&quot;"
+       />
+</VisualStudioPropertySheet>
diff --git a/libs/unimrcp/build/vsprops/cepstral.vsprops b/libs/unimrcp/build/vsprops/cepstral.vsprops
new file mode 100644 (file)
index 0000000..8df44eb
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="cepstral"
+       >
+       <Tool
+               Name="VCCLCompilerTool"
+               AdditionalIncludeDirectories="&quot;$(CepstralSDKDir)\include&quot;"
+       />
+       <Tool
+               Name="VCLinkerTool"
+               AdditionalDependencies="swift.lib"
+               AdditionalLibraryDirectories="&quot;$(CepstralSDKDir)\lib\lib-windows&quot;"
+       />
+       <UserMacro
+               Name="CepstralSDKDir"
+               Value="C:\Program Files\Cepstral\sdk"
+       />
+</VisualStudioPropertySheet>
diff --git a/libs/unimrcp/build/vsprops/mpf.vsprops b/libs/unimrcp/build/vsprops/mpf.vsprops
new file mode 100644 (file)
index 0000000..f03cdcc
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="mpf"
+       InheritedPropertySheets="apt.vsprops"
+       >
+       <Tool
+               Name="VCCLCompilerTool"
+               AdditionalIncludeDirectories="&quot;$(ProjectRootDir)libs\mpf\include&quot;"
+               PreprocessorDefinitions="MPF_STATIC_LIB"
+       />
+       <Tool
+               Name="VCLinkerTool"
+               AdditionalLibraryDirectories="&quot;$(OutDir)&quot;"
+       />
+</VisualStudioPropertySheet>
diff --git a/libs/unimrcp/build/vsprops/mrcp.vsprops b/libs/unimrcp/build/vsprops/mrcp.vsprops
new file mode 100644 (file)
index 0000000..bbb759e
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="mrcp"
+       InheritedPropertySheets=".\apt.vsprops"
+       >
+       <Tool
+               Name="VCCLCompilerTool"
+               AdditionalIncludeDirectories="&quot;$(ProjectRootDir)libs\mrcp\include&quot;;&quot;$(ProjectRootDir)libs\mrcp\message\include&quot;;&quot;$(ProjectRootDir)libs\mrcp\control\include&quot;;&quot;$(ProjectRootDir)libs\mrcp\resources\include&quot;"
+               PreprocessorDefinitions="MRCP_STATIC_LIB"
+       />
+       <Tool
+               Name="VCLinkerTool"
+               AdditionalLibraryDirectories="&quot;$(OutDir)&quot;"
+       />
+</VisualStudioPropertySheet>
diff --git a/libs/unimrcp/build/vsprops/mrcpclient.vsprops b/libs/unimrcp/build/vsprops/mrcpclient.vsprops
new file mode 100644 (file)
index 0000000..5a51b59
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="mrcpclient"
+       InheritedPropertySheets=".\mrcpsignaling.vsprops;.\mrcpv2transport.vsprops"
+       >
+       <Tool
+               Name="VCCLCompilerTool"
+               AdditionalIncludeDirectories="&quot;$(ProjectRootDir)libs\mrcp-client\include&quot;"
+       />
+       <Tool
+               Name="VCLinkerTool"
+               AdditionalLibraryDirectories="&quot;$(OutDir)&quot;"
+       />
+</VisualStudioPropertySheet>
diff --git a/libs/unimrcp/build/vsprops/mrcpengine.vsprops b/libs/unimrcp/build/vsprops/mrcpengine.vsprops
new file mode 100644 (file)
index 0000000..e57efb7
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="mrcpengine"
+       InheritedPropertySheets=".\mpf.vsprops;.\mrcp.vsprops"
+       >
+       <Tool
+               Name="VCCLCompilerTool"
+               AdditionalIncludeDirectories="&quot;$(ProjectRootDir)libs\mrcp-engine\include&quot;"
+       />
+       <Tool
+               Name="VCLinkerTool"
+               AdditionalLibraryDirectories="&quot;$(OutDir)&quot;"
+       />
+</VisualStudioPropertySheet>
diff --git a/libs/unimrcp/build/vsprops/mrcpserver.vsprops b/libs/unimrcp/build/vsprops/mrcpserver.vsprops
new file mode 100644 (file)
index 0000000..1965a90
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="mrcpserver"
+       InheritedPropertySheets=".\mrcpengine.vsprops;.\mrcpsignaling.vsprops;.\mrcpv2transport.vsprops"
+       >
+       <Tool
+               Name="VCCLCompilerTool"
+               AdditionalIncludeDirectories="&quot;$(ProjectRootDir)libs\mrcp-server\include&quot;"
+       />
+       <Tool
+               Name="VCLinkerTool"
+               AdditionalLibraryDirectories="&quot;$(OutDir)&quot;"
+       />
+</VisualStudioPropertySheet>
diff --git a/libs/unimrcp/build/vsprops/mrcpsignaling.vsprops b/libs/unimrcp/build/vsprops/mrcpsignaling.vsprops
new file mode 100644 (file)
index 0000000..64d7e14
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="mrcpsignaling"
+       InheritedPropertySheets=".\mpf.vsprops;.\mrcp.vsprops"
+       >
+       <Tool
+               Name="VCCLCompilerTool"
+               AdditionalIncludeDirectories="&quot;$(ProjectRootDir)libs\mrcp-signaling\include&quot;"
+       />
+       <Tool
+               Name="VCLinkerTool"
+               AdditionalLibraryDirectories="&quot;$(OutDir)&quot;"
+       />
+</VisualStudioPropertySheet>
diff --git a/libs/unimrcp/build/vsprops/mrcpv2transport.vsprops b/libs/unimrcp/build/vsprops/mrcpv2transport.vsprops
new file mode 100644 (file)
index 0000000..481d85b
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="mrcpv2transport"
+       InheritedPropertySheets=".\mrcp.vsprops"
+       >
+       <Tool
+               Name="VCCLCompilerTool"
+               AdditionalIncludeDirectories="&quot;$(ProjectRootDir)libs\mrcpv2-transport\include&quot;"
+       />
+       <Tool
+               Name="VCLinkerTool"
+               AdditionalLibraryDirectories="&quot;$(OutDir)&quot;"
+       />
+</VisualStudioPropertySheet>
diff --git a/libs/unimrcp/build/vsprops/sdk/unimrcpclient.vsprops b/libs/unimrcp/build/vsprops/sdk/unimrcpclient.vsprops
new file mode 100644 (file)
index 0000000..09ca2cd
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="unimrcpclient"
+       InheritedPropertySheets="unimrcpsdk.vsprops"
+       >
+       <Tool
+               Name="VCLinkerTool"
+               AdditionalDependencies="libunimrcpclient.lib mrcpsofiasip.lib mrcpunirtsp.lib unirtsp.lib mrcpclient.lib mrcpv2transport.lib mrcpsignaling.lib libsofia_sip_ua.lib ws2_32.lib winmm.lib"
+       />
+</VisualStudioPropertySheet>
diff --git a/libs/unimrcp/build/vsprops/sdk/unimrcpplugin.vsprops b/libs/unimrcp/build/vsprops/sdk/unimrcpplugin.vsprops
new file mode 100644 (file)
index 0000000..96fb0cf
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="unimrcpplugin"
+       InheritedPropertySheets="unimrcpsdk.vsprops"
+       >
+       <Tool
+               Name="VCLinkerTool"
+               AdditionalDependencies="mrcpengine.lib"
+       />
+</VisualStudioPropertySheet>
diff --git a/libs/unimrcp/build/vsprops/sdk/unimrcpsdk.vsprops b/libs/unimrcp/build/vsprops/sdk/unimrcpsdk.vsprops
new file mode 100644 (file)
index 0000000..f5cd0d3
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="unimrcpsdk"
+       >
+       <Tool
+               Name="VCCLCompilerTool"
+               AdditionalIncludeDirectories="&quot;$(ProjectRootDir)\include&quot;"
+               PreprocessorDefinitions="APT_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB"
+       />
+       <Tool
+               Name="VCLinkerTool"
+               AdditionalLibraryDirectories="&quot;$(ProjectRootDir)\lib&quot;"
+               AdditionalDependencies="mrcp.lib mpf.lib aprtoolkit.lib libaprutil-1.lib libapr-1.lib"
+       />
+       <UserMacro
+               Name="ProjectRootDir"
+               Value="C:\Program Files\UniMRCP"
+       />
+</VisualStudioPropertySheet>
diff --git a/libs/unimrcp/build/vsprops/sdk/unimrcpserver.vsprops b/libs/unimrcp/build/vsprops/sdk/unimrcpserver.vsprops
new file mode 100644 (file)
index 0000000..df5df74
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="unimrcpserver"
+       InheritedPropertySheets="unimrcpsdk.vsprops"
+       >
+       <Tool
+               Name="VCLinkerTool"
+               AdditionalDependencies="libunimrcpserver.lib mrcpsofiasip.lib mrcpunirtsp.lib unirtsp.lib mrcpserver.lib mrcpv2transport.lib mrcpsignaling.lib mrcpengine.lib libsofia_sip_ua.lib ws2_32.lib winmm.lib"
+       />
+</VisualStudioPropertySheet>
diff --git a/libs/unimrcp/build/vsprops/sofiasip.vsprops b/libs/unimrcp/build/vsprops/sofiasip.vsprops
new file mode 100644 (file)
index 0000000..905d3ea
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="sofiasip"
+       InheritedPropertySheets="$(SolutionDir)build\vsprops\unibase.vsprops"
+       >
+       <Tool
+               Name="VCCLCompilerTool"
+               AdditionalIncludeDirectories="&quot;$(SofiaDir)\win32&quot;;&quot;$(SofiaDir)\libsofia-sip-ua\su&quot;;&quot;$(SofiaDir)\libsofia-sip-ua\nua&quot;;&quot;$(SofiaDir)\libsofia-sip-ua\url&quot;;&quot;$(SofiaDir)\libsofia-sip-ua\sip&quot;;&quot;$(SofiaDir)\libsofia-sip-ua\msg&quot;;&quot;$(SofiaDir)\libsofia-sip-ua\sdp&quot;;&quot;$(SofiaDir)\libsofia-sip-ua\nta&quot;;&quot;$(SofiaDir)\libsofia-sip-ua\nea&quot;;&quot;$(SofiaDir)\libsofia-sip-ua\soa&quot;;&quot;$(SofiaDir)\libsofia-sip-ua\iptsec&quot;;&quot;$(SofiaDir)\libsofia-sip-ua\bnf&quot;;&quot;$(SofiaDir)\libsofia-sip-ua\features&quot;"
+       />
+       <Tool
+               Name="VCLinkerTool"
+               AdditionalLibraryDirectories="&quot;$(SofiaDir)\win32\libsofia-sip-ua\$(ConfigurationName)&quot;"
+       />
+       <UserMacro
+               Name="SofiaDir"
+               Value="$(ProjectRootDir)libs\sofia-sip"
+       />
+</VisualStudioPropertySheet>
diff --git a/libs/unimrcp/build/vsprops/unibase.vsprops b/libs/unimrcp/build/vsprops/unibase.vsprops
new file mode 100644 (file)
index 0000000..843d0fc
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="unibase"
+       OutputDirectory="$(SolutionDir)$(ConfigurationName)\bin"
+       IntermediateDirectory="$(ConfigurationName)"
+       >
+       <Tool
+               Name="VCCLCompilerTool"
+               PreprocessorDefinitions="WIN32"
+               WarningLevel="4"
+               WarnAsError="true"
+               DisableSpecificWarnings="4100"
+       />
+       <Tool
+               Name="VCLinkerTool"
+               AdditionalLibraryDirectories="&quot;$(OutDir)&quot;"
+       />
+       <UserMacro
+               Name="ProjectRootDir"
+               Value="$(SolutionDir)"
+       />
+</VisualStudioPropertySheet>
diff --git a/libs/unimrcp/build/vsprops/unidebug.vsprops b/libs/unimrcp/build/vsprops/unidebug.vsprops
new file mode 100644 (file)
index 0000000..d3abbff
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="unidebug"
+       InheritedPropertySheets="$(SolutionDir)build\vsprops\unibase.vsprops"
+       >
+       <Tool
+               Name="VCCLCompilerTool"
+               Optimization="0"
+               PreprocessorDefinitions="_DEBUG"
+               MinimalRebuild="true"
+               BasicRuntimeChecks="3"
+               RuntimeLibrary="3"
+               UsePrecompiledHeader="0"
+               DebugInformationFormat="4"
+       />
+       <Tool
+               Name="VCLinkerTool"
+               LinkIncremental="2"
+               GenerateDebugInformation="true"
+               TargetMachine="1"
+       />
+</VisualStudioPropertySheet>
diff --git a/libs/unimrcp/build/vsprops/unimrcpclient.vsprops b/libs/unimrcp/build/vsprops/unimrcpclient.vsprops
new file mode 100644 (file)
index 0000000..de020ae
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="unimrcpclient"
+       InheritedPropertySheets=".\mrcpclient.vsprops;.\sofiasip.vsprops"
+       >
+       <Tool
+               Name="VCCLCompilerTool"
+               AdditionalIncludeDirectories="&quot;$(ProjectRootDir)platforms\libunimrcp-client\include&quot;;&quot;$(ProjectRootDir)build&quot;"
+       />
+       <Tool
+               Name="VCLinkerTool"
+               AdditionalLibraryDirectories="&quot;$(OutDir)&quot;"
+       />
+       <UserMacro
+               Name="UniMRCPClientLibs"
+               Value="libunimrcpclient.lib mrcpclient.lib mrcpsignaling.lib mrcp.lib aprtoolkit.lib libaprutil-1.lib libapr-1.lib libsofia_sip_ua.lib ws2_32.lib winmm.lib"
+       />
+</VisualStudioPropertySheet>
diff --git a/libs/unimrcp/build/vsprops/unimrcpplugin.vsprops b/libs/unimrcp/build/vsprops/unimrcpplugin.vsprops
new file mode 100644 (file)
index 0000000..00dcc9e
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="unimrcpplugin"
+       OutputDirectory="$(SolutionDir)$(ConfigurationName)\plugin"
+       InheritedPropertySheets=".\mrcpengine.vsprops"
+       >
+       <Tool
+               Name="VCLinkerTool"
+       />
+       <Tool
+               Name="VCLinkerTool"
+               AdditionalLibraryDirectories="&quot;$(SolutionDir)$(ConfigurationName)\bin&quot;"
+               AdditionalDependencies="mrcpengine.lib mrcp.lib mpf.lib aprtoolkit.lib libaprutil-1.lib libapr-1.lib"
+       />
+</VisualStudioPropertySheet>
diff --git a/libs/unimrcp/build/vsprops/unimrcpserver.vsprops b/libs/unimrcp/build/vsprops/unimrcpserver.vsprops
new file mode 100644 (file)
index 0000000..966d2b7
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="unimrcpserver"
+       InheritedPropertySheets=".\mrcpserver.vsprops;.\sofiasip.vsprops"
+       >
+       <Tool
+               Name="VCCLCompilerTool"
+               AdditionalIncludeDirectories="&quot;$(ProjectRootDir)platforms\libunimrcp-server\include&quot;;&quot;$(ProjectRootDir)build&quot;"
+       />
+       <Tool
+               Name="VCLinkerTool"
+               AdditionalLibraryDirectories="&quot;$(OutDir)&quot;"
+       />
+       <UserMacro
+               Name="UniMRCPServerLibs"
+               Value="libunimrcpserver.lib mrcpserver.lib mrcpsignaling.lib mrcp.lib aprtoolkit.lib libaprutil-1.lib libapr-1.lib libsofia_sip_ua.lib ws2_32.lib winmm.lib"
+       />
+</VisualStudioPropertySheet>
diff --git a/libs/unimrcp/build/vsprops/unirelease.vsprops b/libs/unimrcp/build/vsprops/unirelease.vsprops
new file mode 100644 (file)
index 0000000..2d2f4ea
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="unirelease"
+       InheritedPropertySheets="$(SolutionDir)build\vsprops\unibase.vsprops"
+       >
+       <Tool
+               Name="VCCLCompilerTool"
+               PreprocessorDefinitions="NDEBUG;"
+               RuntimeLibrary="2"
+               UsePrecompiledHeader="0"
+               DebugInformationFormat="3"
+       />
+</VisualStudioPropertySheet>
diff --git a/libs/unimrcp/build/vsprops/unirtsp.vsprops b/libs/unimrcp/build/vsprops/unirtsp.vsprops
new file mode 100644 (file)
index 0000000..b5dede2
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="unirtsp"
+       InheritedPropertySheets="apt.vsprops"
+       >
+       <Tool
+               Name="VCCLCompilerTool"
+               AdditionalIncludeDirectories="&quot;$(ProjectRootDir)libs\uni-rtsp\include&quot;"
+               PreprocessorDefinitions="RTSP_STATIC_LIB"
+       />
+       <Tool
+               Name="VCLinkerTool"
+               AdditionalLibraryDirectories="&quot;$(OutDir)&quot;"
+       />
+</VisualStudioPropertySheet>
diff --git a/libs/unimrcp/conf/unimrcpclient.xml b/libs/unimrcp/conf/unimrcpclient.xml
new file mode 100644 (file)
index 0000000..fc903ff
--- /dev/null
@@ -0,0 +1,76 @@
+<!-- UniMRCP client document -->
+<unimrcpclient>
+  <!-- Client settings (signaling, media, ...) -->
+  <settings>
+    <!-- SIP, RTSP signaling agents -->
+    <signaling>
+      <!-- SofiaSIP MRCPv2 signaling agent -->
+      <agent name="SIP-Agent-1" class="SofiaSIP">
+        <param name="client-ip" value="auto"/>
+        <!-- <param name="client-ext-ip" value="auto"/> -->
+        <param name="client-port" value="8062"/>
+        <param name="server-ip" value="auto"/>
+        <param name="server-port" value="8060"/>
+        <!-- <param name="force-destination" value="1"/> -->
+        <!-- <param name="sip-transport" value="tcp"/> -->
+        <param name="sip-transport" value="udp"/>
+        <param name="ua-name" value="UniMRCP SofiaSIP"/>
+        <param name="sdp-origin" value="UniMRCPClient"/>
+      </agent>
+      <!-- UniRTSP MRCPv1 signaling agent -->
+      <agent name="RTSP-Agent-1" class="UniRTSP">
+        <param name="server-ip" value="auto"/>
+        <param name="server-port" value="1554"/>
+        <!-- <param name="force-destination" value="1"/> -->
+        <param name="resource-location" value="media"/>
+        <resourcemap>
+          <param name="speechsynth" value="speechsynthesizer"/>
+          <param name="speechrecog" value="speechrecognizer"/>
+        </resourcemap>
+      </agent>
+    </signaling>
+
+    <!-- MRCPv2 connection agents -->
+    <connection>
+      <agent name="MRCPv2-Agent-1">
+        <param name="max-connection-count" value="100"/>
+        <!-- <param name="offer-new-connection" value="1"/> -->
+      </agent>
+    </connection>
+
+    <!-- Media engines -->
+    <media>
+      <engine name="Media-Engine-1"/>
+      <rtp name="RTP-Factory-1">
+        <param name="rtp-ip" value="auto"/>
+        <!-- <param name="rtp-ext-ip" value="auto"/> -->
+        <param name="rtp-port-min" value="4000"/>
+        <param name="rtp-port-max" value="5000"/>
+        <!-- <param name="playout-delay" value="50"/> -->
+        <!-- <param name="max-playout-delay" value="200"/> -->
+        <!-- <param name="ptime" value="20"/> -->
+        <param name="codecs" value="PCMU PCMA L16/96/8000"/>
+      </rtp>
+    </media>
+  </settings>
+
+  <!-- Client profiles -->
+  <profiles>
+    <!-- MRCPv2 default profile -->
+    <profile name="MRCPv2-Default">
+      <param name="signaling-agent" value="SIP-Agent-1"/>
+      <param name="connection-agent" value="MRCPv2-Agent-1"/>
+      <param name="media-engine" value="Media-Engine-1"/>
+      <param name="rtp-factory" value="RTP-Factory-1"/>
+    </profile>
+    <!-- MRCPv1 default profile -->
+    <profile name="MRCPv1-Default">
+      <param name="signaling-agent" value="RTSP-Agent-1"/>
+      <param name="media-engine" value="Media-Engine-1"/>
+      <param name="rtp-factory" value="RTP-Factory-1"/>
+    </profile>
+
+    <!-- more profiles might be added here -->
+  </profiles>
+</unimrcpclient>
diff --git a/libs/unimrcp/conf/unimrcpserver.xml b/libs/unimrcp/conf/unimrcpserver.xml
new file mode 100644 (file)
index 0000000..6cf213d
--- /dev/null
@@ -0,0 +1,80 @@
+<!-- unimrcpserver document -->
+<unimrcpserver>
+  <!-- Server settings (signaling, media, ...) -->
+  <settings>
+    <!-- SIP, RTSP signaling agents -->
+    <signaling>
+      <agent name="SIP-Agent-1" class="SofiaSIP">
+        <param name="sip-ip" value="auto"/>
+        <!-- <param name="sip-ext-ip" value="auto"/> -->
+        <param name="sip-port" value="8060"/>
+        <param name="sip-transport" value="udp,tcp"/>
+        <!-- <param name="force-destination" value="1"/> -->
+        <param name="ua-name" value="UniMRCP SofiaSIP"/>
+        <param name="sdp-origin" value="UniMRCPServer"/>
+      </agent>
+      <agent name="RTSP-Agent-1" class="UniRTSP">
+        <param name="rtsp-ip" value="auto"/>
+        <param name="rtsp-port" value="1554"/>
+        <!-- <param name="force-destination" value="1"/> -->
+        <resourcemap>
+          <param name="speechsynth" value="speechsynthesizer"/>
+          <param name="speechrecog" value="speechrecognizer"/>
+        </resourcemap>
+      </agent>
+    </signaling>
+
+    <!-- MRCPv2 connection agents -->
+    <connection>
+      <agent name="MRCPv2-Agent-1">
+        <param name="mrcp-ip" value="auto"/>
+        <param name="mrcp-port" value="1544"/>
+        <param name="max-connection-count" value="100"/>
+        <!-- <param name="force-new-connection" value="1"/> -->
+      </agent>
+    </connection>
+
+    <!-- Media engines -->
+    <media>
+      <engine name="Media-Engine-1"/>
+      <rtp name="RTP-Factory-1">
+        <param name="rtp-ip" value="auto"/>
+        <!-- <param name="rtp-ext-ip" value="auto"/> -->
+        <param name="rtp-port-min" value="5000"/>
+        <param name="rtp-port-max" value="6000"/>
+        <!-- <param name="playout-delay" value="50"/> -->
+        <!-- <param name="max-playout-delay" value="200"/> -->
+        <!-- <param name="ptime" value="20"/> -->
+        <param name="codecs" value="PCMU PCMA L16/96/8000"/>
+        <!-- <param name="own-preference" value="1"/> -->
+      </rtp>
+    </media>
+
+    <!-- Resource plugins -->
+    <plugin>
+      <engine name="Cepstral-Swift-1" class="mrcpcepstral" enable="0"/>
+      <engine name="Demo-Synth-1" class="demosynth" enable="1"/>
+      <engine name="Demo-Recog-1" class="demorecog" enable="1"/>
+    </plugin>
+  </settings>
+
+  <!-- Server profiles -->
+  <profiles>
+    <!-- MRCPv2 default profile -->
+    <profile name="MRCPv2-Default">
+      <param name="signaling-agent" value="SIP-Agent-1"/>
+      <param name="connection-agent" value="MRCPv2-Agent-1"/>
+      <param name="media-engine" value="Media-Engine-1"/>
+      <param name="rtp-factory" value="RTP-Factory-1"/>
+    </profile>
+    <!-- MRCPv1 default profile -->
+    <profile name="MRCPv1-Default">
+      <param name="signaling-agent" value="RTSP-Agent-1"/>
+      <param name="media-engine" value="Media-Engine-1"/>
+      <param name="rtp-factory" value="RTP-Factory-1"/>
+    </profile>
+
+    <!-- more profiles might be added here -->
+  </profiles>
+</unimrcpserver>
diff --git a/libs/unimrcp/configure.ac b/libs/unimrcp/configure.ac
new file mode 100644 (file)
index 0000000..7a569fd
--- /dev/null
@@ -0,0 +1,149 @@
+#                                               -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.57)
+
+AC_INIT([unimrcp],[0.6.0])
+
+AC_CONFIG_AUX_DIR([build])
+AC_CONFIG_MACRO_DIR([build/acmacros])
+AC_PREFIX_DEFAULT(/usr/local/unimrcp)
+
+plugindir='${prefix}/plugin'
+confdir='${prefix}/conf'
+logdir='${prefix}/log'
+datadir='${prefix}/data'
+
+AM_INIT_AUTOMAKE(foreign)
+
+#Set default language
+AC_LANG_C
+
+AC_PROG_CC
+AC_PROG_CXX
+AC_PROG_INSTALL
+
+#skip detection of Fortran
+m4_undefine([AC_PROG_F77])
+m4_defun([AC_PROG_F77],[])
+AC_PROG_LIBTOOL
+
+# get version information
+get_version="build/get-version.sh"
+version_hdr="build/uni_version.h"
+plugin_version_hdr="libs/mrcp-engine/include/mrcp_resource_plugin.h"
+UNI_DOTTED_VERSION="`$get_version all $version_hdr UNI`"
+UNI_LT_VERSION="-version-info `$get_version libtool $version_hdr UNI`"
+PLUGIN_LT_VERSION="-version-info `$get_version libtool $plugin_version_hdr PLUGIN`"
+
+AC_SUBST(UNI_DOTTED_VERSION)
+AC_SUBST(UNI_LT_VERSION)
+AC_SUBST(PLUGIN_LT_VERSION)
+
+echo "UniMRCP Version: ${UNI_DOTTED_VERSION}"
+
+UNIMRCP_CHECK_APR
+UNIMRCP_CHECK_APU
+
+UNIMRCP_CHECK_SOFIA
+
+UNIMRCP_CHECK_SWIFT
+
+
+AC_SUBST(ac_aux_dir)
+AC_SUBST(ac_macro_dir)
+AC_SUBST(plugindir)
+AC_SUBST(confdir)
+AC_SUBST(logdir)
+
+AC_DEFUN([AX_COMPILER_VENDOR],
+[
+AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor,
+ [ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=unknown
+  # note: don't check for gcc first since some other compilers define __GNUC__
+  for ventest in intel:__ICC,__ECC,__INTEL_COMPILER ibm:__xlc__,__xlC__,__IBMC__,__IBMCPP__ gnu:__GNUC__ sun:__SUNPRO_C,__SUNPRO_CC hp:__HP_cc,__HP_aCC dec:__DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland:__BORLANDC__,__TURBOC__ comeau:__COMO__ cray:_CRAYC kai:__KCC lcc:__LCC__ metrowerks:__MWERKS__ sgi:__sgi,sgi microsoft:_MSC_VER watcom:__WATCOMC__ portland:__PGI; do
+    vencpp="defined("`echo $ventest | cut -d: -f2 | sed 's/,/) || defined(/g'`")"
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[
+#if !($vencpp)
+      thisisanerror;
+#endif
+])], [ax_cv_]_AC_LANG_ABBREV[_compiler_vendor=`echo $ventest | cut -d: -f1`; break])
+  done
+ ])
+])
+
+AX_COMPILER_VENDOR
+
+
+AC_ARG_ENABLE(maintainer-mode,
+    [AC_HELP_STRING([--enable-maintainer-mode  ],[turn on debugging and compile time warnings])],
+    [enable_maintainer_mode="$enableval"],
+    [enable_maintainer_mode="no"])
+
+if test "${enable_maintainer_mode}" != "no"; then
+    CFLAGS="$CFLAGS -g"
+    if test "x${ax_cv_c_compiler_vendor}"  =  "xgnu" ; then
+      CFLAGS="$CFLAGS -Wall -Werror"
+    fi
+fi
+
+AC_ARG_ENABLE(test-suites,
+    [AC_HELP_STRING([--enable-test-suites  ],[build test suites])],
+    [enable_test_suites="$enableval"],
+    [enable_test_suites="no"])
+
+AM_CONDITIONAL([TEST_SUITES],[test "${enable_test_suites}" != "no"])
+
+AC_ARG_ENABLE(demosynth-plugin,
+    [AC_HELP_STRING([--disable-demosynth-plugin  ],[exclude demo synthesizer plugin from build])],
+    [enable_demosynth_plugin="$enableval"],
+    [enable_demosynth_plugin="yes"])
+
+AM_CONDITIONAL([DEMOSYNTH_PLUGIN],[test "${enable_demosynth_plugin}" = "yes"])
+
+AC_ARG_ENABLE(demorecog-plugin,
+    [AC_HELP_STRING([--disable-demorecog-plugin  ],[exclude demo recognizer plugin from build])],
+    [enable_demorecog_plugin="$enableval"],
+    [enable_demorecog_plugin="yes"])
+
+AM_CONDITIONAL([DEMORECOG_PLUGIN],[test "${enable_demorecog_plugin}" = "yes"])
+
+
+AC_CONFIG_FILES([
+  Makefile
+  libs/Makefile
+  libs/apr-toolkit/Makefile
+  libs/mpf/Makefile
+  libs/mrcp/Makefile
+  libs/mrcp-signaling/Makefile
+  libs/mrcpv2-transport/Makefile
+  libs/mrcp-engine/Makefile
+  libs/mrcp-server/Makefile
+  libs/mrcp-client/Makefile
+  libs/uni-rtsp/Makefile
+  modules/Makefile
+  modules/mrcp-sofiasip/Makefile
+  modules/mrcp-unirtsp/Makefile
+  plugins/Makefile
+  plugins/mrcp-cepstral/Makefile
+  plugins/demo-synth/Makefile
+  plugins/demo-recog/Makefile
+  platforms/Makefile
+  platforms/libunimrcp-server/Makefile
+  platforms/libunimrcp-client/Makefile
+  platforms/unimrcp-server/Makefile
+  platforms/unimrcp-client/Makefile
+  tests/Makefile
+  tests/apttest/Makefile
+  tests/mpftest/Makefile
+  tests/mrcptest/Makefile
+  tests/rtsptest/Makefile
+  tests/strtablegen/Makefile
+  build/Makefile
+  build/pkgconfig/Makefile
+  build/pkgconfig/unimrcpclient.pc
+  build/pkgconfig/unimrcpserver.pc
+  build/pkgconfig/unimrcpplugin.pc
+])
+
+AC_OUTPUT
diff --git a/libs/unimrcp/data/demo.pcm b/libs/unimrcp/data/demo.pcm
new file mode 100644 (file)
index 0000000..7c5bf27
Binary files /dev/null and b/libs/unimrcp/data/demo.pcm differ
diff --git a/libs/unimrcp/data/grammar.xml b/libs/unimrcp/data/grammar.xml
new file mode 100644 (file)
index 0000000..3e84ebc
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>\r
+<grammar xmlns="http://www.w3.org/2001/06/grammar" xml:lang="en-US" version="1.0" mode="voice" root="digit">\r
+  <rule id="digit">\r
+    <one-of>\r
+      <item>one</item>\r
+      <item>two</item>\r
+      <item>three</item>\r
+    </one-of>\r
+  </rule>\r
+</grammar>
\ No newline at end of file
diff --git a/libs/unimrcp/data/one.pcm b/libs/unimrcp/data/one.pcm
new file mode 100644 (file)
index 0000000..92c1e92
Binary files /dev/null and b/libs/unimrcp/data/one.pcm differ
diff --git a/libs/unimrcp/data/result.xml b/libs/unimrcp/data/result.xml
new file mode 100644 (file)
index 0000000..e75c6e4
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>\r
+<result> \r
+  <interpretation grammar="session:request1@form-level.store" confidence="97">\r
+    <instance>one</instance>\r
+    <input mode="speech">one</input>\r
+  </interpretation>\r
+</result>
\ No newline at end of file
diff --git a/libs/unimrcp/data/speak.xml b/libs/unimrcp/data/speak.xml
new file mode 100644 (file)
index 0000000..e9a9ec3
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>\r
+<speak>\r
+  <paragraph>\r
+    <sentence>Hello World.</sentence>\r
+  </paragraph>\r
+</speak>
\ No newline at end of file
diff --git a/libs/unimrcp/docs/doxygen.conf b/libs/unimrcp/docs/doxygen.conf
new file mode 100644 (file)
index 0000000..32b0b23
--- /dev/null
@@ -0,0 +1,32 @@
+PROJECT_NAME="UniMRCP"
+
+INPUT=.
+QUIET=YES
+RECURSIVE=YES
+FILE_PATTERNS=*.h
+
+OUTPUT_DIRECTORY=docs/dox
+
+MACRO_EXPANSION=YES
+EXPAND_ONLY_PREDEF=YES
+
+PREDEFINED="APT_DECLARE(x)=x" \
+           "MPF_DECLARE(x)=x" \
+           "MRCP_DECLARE(x)=x" \
+           "RTSP_DECLARE(x)=x"
+
+OPTIMIZE_OUTPUT_FOR_C=YES
+STRIP_CODE_COMMENTS=NO
+
+FULL_PATH_NAMES=NO
+CASE_SENSE_NAMES=NO
+
+EXCLUDE_PATTERNS="*/acconfig.h" \
+                 "*/test/*" \
+                 "*/arch/*"
+
+GENERATE_HTML=YES
+GENERATE_LATEX=NO
+GENERATE_RTF=NO
+GENERATE_MAN=NO
+GENERATE_XML=NO
diff --git a/libs/unimrcp/libs/Makefile.am b/libs/unimrcp/libs/Makefile.am
new file mode 100644 (file)
index 0000000..ce33be3
--- /dev/null
@@ -0,0 +1,3 @@
+MAINTAINERCLEANFILES   = Makefile.in
+
+SUBDIRS                = apr-toolkit mpf mrcp mrcp-signaling mrcpv2-transport mrcp-engine mrcp-server mrcp-client uni-rtsp
diff --git a/libs/unimrcp/libs/apr-toolkit/Makefile.am b/libs/unimrcp/libs/apr-toolkit/Makefile.am
new file mode 100644 (file)
index 0000000..e2a065b
--- /dev/null
@@ -0,0 +1,43 @@
+MAINTAINERCLEANFILES    = Makefile.in
+
+INCLUDES                 = -I$(top_srcdir)/libs/apr-toolkit/include \
+                           $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+noinst_LTLIBRARIES       = libaprtoolkit.la
+
+include_HEADERS          = include/apt.h \
+                           include/apt_obj_list.h \
+                           include/apt_cyclic_queue.h \
+                           include/apt_task.h \
+                           include/apt_task_msg.h \
+                           include/apt_consumer_task.h \
+                           include/apt_net_server_task.h \
+                           include/apt_net_client_task.h \
+                           include/apt_pollset.h \
+                           include/apt_pool.h \
+                           include/apt_log.h \
+                           include/apt_pair.h \
+                           include/apt_string.h \
+                           include/apt_string_table.h \
+                           include/apt_text_stream.h \
+                           include/apt_net.h \
+                           include/apt_dir_layout.h \
+                           include/apt_test_suite.h
+
+libaprtoolkit_la_SOURCES = src/apt_obj_list.c \
+                           src/apt_cyclic_queue.c \
+                           src/apt_task.c \
+                           src/apt_task_msg.c \
+                           src/apt_consumer_task.c \
+                           src/apt_net_server_task.c \
+                           src/apt_net_client_task.c \
+                           src/apt_pollset.c \
+                           src/apt_pool.c \
+                           src/apt_log.c \
+                           src/apt_pair.c \
+                           src/apt_string_table.c \
+                           src/apt_text_stream.c \
+                           src/apt_net.c \
+                           src/apt_dir_layout.c \
+                           src/apt_test_suite.c
+                           
diff --git a/libs/unimrcp/libs/apr-toolkit/aprtoolkit.vcproj b/libs/unimrcp/libs/apr-toolkit/aprtoolkit.vcproj
new file mode 100644 (file)
index 0000000..9d39f55
--- /dev/null
@@ -0,0 +1,277 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="aprtoolkit"
+       ProjectGUID="{13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}"
+       RootNamespace="aprtoolkit"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\apt.vsprops"
+                       CharacterSet="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\apt.vsprops"
+                       CharacterSet="1"
+                       WholeProgramOptimization="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+                       <File
+                               RelativePath=".\include\apt.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\apt_consumer_task.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\apt_cyclic_queue.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\apt_dir_layout.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\apt_log.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\apt_net.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\apt_net_client_task.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\apt_net_server_task.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\apt_obj_list.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\apt_pair.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\apt_pollset.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\apt_pool.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\apt_string.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\apt_string_table.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\apt_task.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\apt_task_msg.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\apt_test_suite.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\apt_text_stream.h"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       >
+                       <File
+                               RelativePath=".\src\apt_consumer_task.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\apt_cyclic_queue.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\apt_dir_layout.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\apt_log.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\apt_net.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\apt_net_client_task.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\apt_net_server_task.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\apt_obj_list.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\apt_pair.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\apt_pollset.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\apt_pool.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\apt_string_table.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\apt_task.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\apt_task_msg.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\apt_test_suite.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\apt_text_stream.c"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt.h b/libs/unimrcp/libs/apr-toolkit/include/apt.h
new file mode 100644 (file)
index 0000000..2c03531
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __APT_H__
+#define __APT_H__
+
+/**
+ * @file apt.h
+ * @brief APR Toolkit Definitions
+ */ 
+
+#include <apr.h>
+#include <apr_pools.h>
+#include <apr_strings.h>
+
+#ifdef __cplusplus
+/** Begin of extern "C" block */
+#define APT_BEGIN_EXTERN_C       extern "C" {
+/** End of extern "C" block */
+#define APT_END_EXTERN_C         }
+#else
+/** Begin of extern "C" block */
+#define APT_BEGIN_EXTERN_C
+/** End of extern "C" block */
+#define APT_END_EXTERN_C
+#endif 
+
+/** Lib export/import defines (win32) */
+#ifdef WIN32
+#ifdef APT_STATIC_LIB
+#define APT_DECLARE(type)   type __stdcall
+#else
+#ifdef APT_LIB_EXPORT
+#define APT_DECLARE(type)   __declspec(dllexport) type __stdcall
+#else
+#define APT_DECLARE(type)   __declspec(dllimport) type __stdcall
+#endif
+#endif
+#else
+#define APT_DECLARE(type) type
+#endif
+
+/** Boolean value */
+typedef int apt_bool_t;
+
+#endif /*__APT_H__*/
diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_consumer_task.h b/libs/unimrcp/libs/apr-toolkit/include/apt_consumer_task.h
new file mode 100644 (file)
index 0000000..59eff40
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __APT_CONSUMER_TASK_H__
+#define __APT_CONSUMER_TASK_H__
+
+/**
+ * @file apt_consumer_task.h
+ * @brief Consumer Task Definition
+ */ 
+
+#include "apt_task.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque consumer task declaration */
+typedef struct apt_consumer_task_t apt_consumer_task_t;
+
+/**
+ * Create consumer task.
+ * @param obj the external object to associate with the task
+ * @param msg_pool the pool of task messages
+ * @param pool the pool to allocate memory from
+ */
+APT_DECLARE(apt_consumer_task_t*) apt_consumer_task_create(
+                                                                       void *obj,
+                                                                       apt_task_msg_pool_t *msg_pool,
+                                                                       apr_pool_t *pool);
+
+/**
+ * Get task base.
+ * @param task the consumer task to get base for
+ */
+APT_DECLARE(apt_task_t*) apt_consumer_task_base_get(apt_consumer_task_t *task);
+
+/**
+ * Get task vtable.
+ * @param task the consumer task to get vtable for
+ */
+APT_DECLARE(apt_task_vtable_t*) apt_consumer_task_vtable_get(apt_consumer_task_t *task);
+
+/**
+ * Get consumer task object.
+ * @param task the consumer task to get object from
+ */
+APT_DECLARE(void*) apt_consumer_task_object_get(apt_consumer_task_t *task);
+
+APT_END_EXTERN_C
+
+#endif /*__APT_CONSUMER_TASK_H__*/
diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_cyclic_queue.h b/libs/unimrcp/libs/apr-toolkit/include/apt_cyclic_queue.h
new file mode 100644 (file)
index 0000000..c36fcd2
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __APT_CYCLIC_QUEUE_H__
+#define __APT_CYCLIC_QUEUE_H__
+
+/**
+ * @file apt_cyclic_queue.h
+ * @brief Cyclic FIFO Queue of Opaque void* Objects
+ */ 
+
+#include "apt.h"
+
+APT_BEGIN_EXTERN_C
+
+#define CYCLIC_QUEUE_DEFAULT_SIZE      100
+
+/** Opaque cyclic queue declaration */
+typedef struct apt_cyclic_queue_t apt_cyclic_queue_t;
+
+/**
+ * Create cyclic queue.
+ * @param size the initial size of the queue
+ * @return the created queue
+ */
+APT_DECLARE(apt_cyclic_queue_t*) apt_cyclic_queue_create(apr_size_t size);
+
+/**
+ * Destroy cyclic queue.
+ * @param queue the queue to destroy
+ */
+APT_DECLARE(void) apt_cyclic_queue_destroy(apt_cyclic_queue_t *queue);
+
+/**
+ * Push object to the queue.
+ * @param queue the queue to push object to
+ * @param obj the object to push
+ */
+APT_DECLARE(apt_bool_t) apt_cyclic_queue_push(apt_cyclic_queue_t *queue, void *obj);
+
+/**
+ * Pop object from the queue.
+ * @param queue the queue to pop message from
+ */
+APT_DECLARE(void*) apt_cyclic_queue_pop(apt_cyclic_queue_t *queue);
+
+/**
+ * Clear the queue (remove all the elements from the queue).
+ * @param queue the queue to clear
+ */
+APT_DECLARE(void) apt_cyclic_queue_clear(apt_cyclic_queue_t *queue);
+
+/**
+ * Query whether the queue is empty.
+ * @param queue the queue to query
+ * @return TRUE if empty, otherwise FALSE
+ */
+APT_DECLARE(apt_bool_t) apt_cyclic_queue_is_empty(apt_cyclic_queue_t *queue);
+
+
+APT_END_EXTERN_C
+
+#endif /*__APT_CYCLIC_QUEUE_H__*/
diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_dir_layout.h b/libs/unimrcp/libs/apr-toolkit/include/apt_dir_layout.h
new file mode 100644 (file)
index 0000000..497265d
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __APT_DIR_LAYOUT_H__
+#define __APT_DIR_LAYOUT_H__
+
+/**
+ * @file apt_dir_layout.h
+ * @brief Directory Layout
+ */ 
+
+#include "apt.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Directory layout declaration */
+typedef struct apt_dir_layout_t apt_dir_layout_t;
+
+/** Directory layout */
+struct apt_dir_layout_t {
+       /** Path to config dir */
+       char *conf_dir_path;
+       /** Path to plugin dir */
+       char *plugin_dir_path;
+       /** Path to log dir */
+       char *log_dir_path;
+       /** Path to data dir */
+       char *data_dir_path;
+};
+
+/**
+ * Create (allocate) the structure of default directories layout.
+ */
+APT_DECLARE(apt_dir_layout_t*) apt_default_dir_layout_create(const char *root_dir_path, apr_pool_t *pool);
+
+/**
+ * Create (allocate) the structure of custom directories layout.
+ */
+APT_DECLARE(apt_dir_layout_t*) apt_custom_dir_layout_create(
+                                                                       const char *conf_dir_path,
+                                                                       const char *plugin_dir_path,
+                                                                       const char *log_dir_path,
+                                                                       const char *data_dir_path,
+                                                                       apr_pool_t *pool);
+
+/**
+ * Construct file path with the given file name relative to data dir.
+ */
+APT_DECLARE(char*) apt_datadir_filepath_get(const apt_dir_layout_t *dir_layout, const char *file_name, apr_pool_t *pool);
+
+
+APT_END_EXTERN_C
+
+#endif /*__APT_DIR_LAYOUT_H__*/
diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_log.h b/libs/unimrcp/libs/apr-toolkit/include/apt_log.h
new file mode 100644 (file)
index 0000000..d3b38ab
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __APT_LOG_H__
+#define __APT_LOG_H__
+
+/**
+ * @file apt_log.h
+ * @brief Basic Logger
+ */ 
+
+#include <stdio.h>
+#include <stdarg.h>
+#include "apt.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Default max size of the log file (8Mb) */
+#define MAX_LOG_FILE_SIZE (8 * 1024 * 1024)
+/** Default max number of rotated log files */
+#define MAX_LOG_FILE_COUNT 10
+
+/** File:line mark */
+#define APT_LOG_MARK   __FILE__,__LINE__
+
+/** Format to log pointer values */
+#define APT_PTR_FMT       "0x%x"
+/** Format to log string identifiers */
+#define APT_SID_FMT       "<%s>"
+/** Format to log string identifiers and resources */
+#define APT_SIDRES_FMT    "<%s@%s>"
+/** Format to log pointers and identifiers */
+#define APT_PTRSID_FMT    APT_PTR_FMT" "APT_SID_FMT
+/** Format to log pointers, identifiers and resources */
+#define APT_PTRSIDRES_FMT APT_PTR_FMT" "APT_SIDRES_FMT
+
+
+/** Priority of log messages ordered from highest priority to lowest (rfc3164) */
+typedef enum {
+       APT_PRIO_EMERGENCY, /**< system is unusable */
+       APT_PRIO_ALERT,     /**< action must be taken immediately */
+       APT_PRIO_CRITICAL,  /**< critical condition */
+       APT_PRIO_ERROR,     /**< error condition */
+       APT_PRIO_WARNING,   /**< warning condition */
+       APT_PRIO_NOTICE,    /**< normal, but significant condition */
+       APT_PRIO_INFO,      /**< informational message */
+       APT_PRIO_DEBUG,     /**< debug-level message */
+
+       APT_PRIO_COUNT          /**< number of priorities */
+} apt_log_priority_e;
+
+/** Header (format) of log messages */
+typedef enum {
+       APT_LOG_HEADER_NONE     = 0x00, /**< disable optional headers output */
+       APT_LOG_HEADER_DATE     = 0x01, /**< enable date output */
+       APT_LOG_HEADER_TIME     = 0x02, /**< enable time output */
+       APT_LOG_HEADER_PRIORITY = 0x04, /**< enable priority name output */
+       APT_LOG_HEADER_MARK     = 0x08, /**< enable file:line mark output */
+
+       APT_LOG_HEADER_DEFAULT  = APT_LOG_HEADER_DATE | APT_LOG_HEADER_TIME | APT_LOG_HEADER_PRIORITY
+} apt_log_header_e;
+
+/** Log output modes */
+typedef enum {
+       APT_LOG_OUTPUT_NONE     = 0x00, /**< disable logging */
+       APT_LOG_OUTPUT_CONSOLE  = 0x01, /**< enable console output */
+       APT_LOG_OUTPUT_FILE     = 0x02, /**< enable log file output */
+} apt_log_output_e;
+
+/** Opaque logger declaration */
+typedef struct apt_logger_t apt_logger_t;
+
+/** Prototype of extended log handler function */
+typedef apt_bool_t (*apt_log_ext_handler_f)(const char *file, int line, const char *id, 
+                                                                                       apt_log_priority_e priority, const char *format, va_list arg_ptr);
+
+/**
+ * Create the singleton instance of the logger.
+ * @param mode the log output mode
+ * @param priority the log priority level
+ * @param pool the memory pool to use
+ */
+APT_DECLARE(apt_bool_t) apt_log_instance_create(apt_log_output_e mode, apt_log_priority_e priority, apr_pool_t *pool);
+
+/**
+ * Destroy the singleton instance of the logger.
+ */
+APT_DECLARE(apt_bool_t) apt_log_instance_destroy();
+
+/**
+ * Get the singleton instance of the logger.
+ */
+APT_DECLARE(apt_logger_t*) apt_log_instance_get();
+
+/**
+ * Set the singleton instance of the logger.
+ */
+APT_DECLARE(apt_bool_t) apt_log_instance_set(apt_logger_t *logger);
+
+/**
+ * Open the log file.
+ * @param dir_path the path to the log directory
+ * @param file_name the name of the log file
+ * @param max_file_size the max size of the log file
+ * @param max_file_count the max number of files used in log rotation
+ * @param pool the memory pool to use
+ */
+APT_DECLARE(apt_bool_t) apt_log_file_open(
+                                                       const char *dir_path, 
+                                                       const char *file_name, 
+                                                       apr_size_t max_file_size, 
+                                                       apr_size_t max_file_count, 
+                                                       apr_pool_t *pool);
+
+/**
+ * Close the log file.
+ */
+APT_DECLARE(apt_bool_t) apt_log_file_close();
+
+/**
+ * Set the logging output.
+ * @param mode the mode to set
+ */
+APT_DECLARE(apt_bool_t) apt_log_output_mode_set(apt_log_output_e mode);
+
+/**
+ * Set the logging priority (log level).
+ * @param priority the priority to set
+ */
+APT_DECLARE(apt_bool_t) apt_log_priority_set(apt_log_priority_e priority);
+
+/**
+ * Set the header (format) for log messages.
+ * @param header the header to set (used as bitmask)
+ */
+APT_DECLARE(apt_bool_t) apt_log_header_set(int header);
+
+/**
+ * Set the extended external log handler.
+ * @param handler the handler to pass log events to
+ * @remark default logger is used to output the logs to stdout and/or log file,
+ *         if external log handler isn't set
+ */
+APT_DECLARE(apt_bool_t) apt_log_ext_handler_set(apt_log_ext_handler_f handler);
+
+/**
+ * Do logging.
+ * @param file the file name log entry is generated from
+ * @param line the line number log entry is generated from
+ * @param priority the priority of the entire log entry
+ * @param format the format of the entire log entry
+ */
+APT_DECLARE(apt_bool_t) apt_log(const char *file, int line, apt_log_priority_e priority, const char *format, ...);
+
+APT_END_EXTERN_C
+
+#endif /*__APT_LOG_H__*/
diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_net.h b/libs/unimrcp/libs/apr-toolkit/include/apt_net.h
new file mode 100644 (file)
index 0000000..d3792f2
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __APT_NET_H__
+#define __APT_NET_H__
+
+/**
+ * @file apt_net.h
+ * @brief Network Utilities
+ */ 
+
+#include "apt.h"
+
+APT_BEGIN_EXTERN_C
+
+/**
+ * Get the IP address (in numeric address string format) by hostname.
+ * @param addr the IP address
+ * @param pool the pool to allocate memory from
+ */
+apt_bool_t apt_ip_get(char **addr, apr_pool_t *pool);
+
+APT_END_EXTERN_C
+
+#endif /*__APT_NET_H__*/
diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_net_client_task.h b/libs/unimrcp/libs/apr-toolkit/include/apt_net_client_task.h
new file mode 100644 (file)
index 0000000..0cd9466
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __APT_NET_CLIENT_TASK_H__
+#define __APT_NET_CLIENT_TASK_H__
+
+/**
+ * @file apt_net_client_task.h
+ * @brief Network Client Task Base
+ */ 
+
+#include <apr_poll.h>
+#include "apt_task.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque network client task declaration */
+typedef struct apt_net_client_task_t apt_net_client_task_t;
+/** Network client connection declaration */
+typedef struct apt_net_client_connection_t apt_net_client_connection_t;
+/** Virtual table of network client events */
+typedef struct apt_net_client_vtable_t apt_net_client_vtable_t;
+
+/** Network client connection */
+struct apt_net_client_connection_t {
+       /** Memory pool */
+       apr_pool_t   *pool;
+       /** External object */
+       void         *obj;
+       /** Connected socket */
+       apr_socket_t *sock;
+       /** Socket poll descriptor */
+       apr_pollfd_t  sock_pfd;
+       /** String identifier used for traces */
+       const char   *id;
+};
+
+/** Virtual table of network client events */
+struct apt_net_client_vtable_t {
+       /** Message receive handler */
+       apt_bool_t (*on_receive)(apt_net_client_task_t *task, apt_net_client_connection_t *connection);
+};
+
+
+/**
+ * Create network client task.
+ * @param max_connection_count the number of max connections
+ * @param obj the external object
+ * @param client_vtable the table of virtual methods of the net client task
+ * @param msg_pool the pool of task messages
+ * @param pool the pool to allocate memory from
+ */
+APT_DECLARE(apt_net_client_task_t*) apt_net_client_task_create(
+                                                                               apr_size_t max_connection_count,
+                                                                               void *obj,
+                                                                               const apt_net_client_vtable_t *client_vtable,
+                                                                               apt_task_msg_pool_t *msg_pool,
+                                                                               apr_pool_t *pool);
+
+/**
+ * Destroy network client task.
+ * @param task the task to destroy
+ */
+APT_DECLARE(apt_bool_t) apt_net_client_task_destroy(apt_net_client_task_t *task);
+
+/**
+ * Start network client task and wait for incoming requests.
+ * @param task the task to start
+ */
+APT_DECLARE(apt_bool_t) apt_net_client_task_start(apt_net_client_task_t *task);
+
+/**
+ * Terminate connection task.
+ * @param task the task to terminate
+ */
+APT_DECLARE(apt_bool_t) apt_net_client_task_terminate(apt_net_client_task_t *task);
+
+/**
+ * Get task base.
+ * @param task the network client task to get task base from
+ */
+APT_DECLARE(apt_task_t*) apt_net_client_task_base_get(apt_net_client_task_t *task);
+
+/**
+ * Get task vtable.
+ * @param task the network client task to get vtable from
+ */
+APT_DECLARE(apt_task_vtable_t*) apt_net_client_task_vtable_get(apt_net_client_task_t *task);
+
+/**
+ * Get external object.
+ * @param task the task to get object from
+ */
+APT_DECLARE(void*) apt_net_client_task_object_get(apt_net_client_task_t *task);
+
+/**
+ * Create connection.
+ */
+APT_DECLARE(apt_net_client_connection_t*) apt_net_client_connect(apt_net_client_task_t *task, const char *ip, apr_port_t port);
+
+/**
+ * Close connection.
+ */
+APT_DECLARE(apt_bool_t) apt_net_client_connection_close(apt_net_client_task_t *task, apt_net_client_connection_t *connection);
+
+/**
+ * Close and destroy connection.
+ */
+APT_DECLARE(apt_bool_t) apt_net_client_disconnect(apt_net_client_task_t *task, apt_net_client_connection_t *connection);
+
+
+APT_END_EXTERN_C
+
+#endif /*__APT_NET_CLIENT_TASK_H__*/
diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_net_server_task.h b/libs/unimrcp/libs/apr-toolkit/include/apt_net_server_task.h
new file mode 100644 (file)
index 0000000..fa97836
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __APT_NET_SERVER_TASK_H__
+#define __APT_NET_SERVER_TASK_H__
+
+/**
+ * @file apt_net_server_task.h
+ * @brief Network Server Task Base
+ */ 
+
+#include <apr_poll.h>
+#include "apt_task.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque network server task declaration */
+typedef struct apt_net_server_task_t apt_net_server_task_t;
+/** Network server connection declaration */
+typedef struct apt_net_server_connection_t apt_net_server_connection_t;
+/** Virtual table of network server events */
+typedef struct apt_net_server_vtable_t apt_net_server_vtable_t;
+
+/** Network server connection */
+struct apt_net_server_connection_t {
+       /** Memory pool */
+       apr_pool_t   *pool;
+       /** External object */
+       void         *obj;
+       /** Client IP address */
+       char         *client_ip;
+       /** Accepted socket */
+       apr_socket_t *sock;
+       /** Socket poll descriptor */
+       apr_pollfd_t  sock_pfd;
+       /** String identifier used for traces */
+       const char   *id;
+};
+
+/** Virtual table of network server events */
+struct apt_net_server_vtable_t {
+       /** Connect event handler */
+       apt_bool_t (*on_connect)(apt_net_server_task_t *task, apt_net_server_connection_t *connection);
+       /** Disconnect event handler */
+       apt_bool_t (*on_disconnect)(apt_net_server_task_t *task, apt_net_server_connection_t *connection);
+       /** Message receive handler */
+       apt_bool_t (*on_receive)(apt_net_server_task_t *task, apt_net_server_connection_t *connection);
+};
+
+
+/**
+ * Create network server task.
+ * @param listen_ip the listen IP address
+ * @param listen_port the listen port
+ * @param max_connection_count the number of max connections to accept
+ * @param obj the external object
+ * @param server_vtable the table of virtual methods of the net server task
+ * @param msg_pool the pool of task messages
+ * @param pool the pool to allocate memory from
+ */
+APT_DECLARE(apt_net_server_task_t*) apt_net_server_task_create(
+                                                                               const char *listen_ip, 
+                                                                               apr_port_t listen_port, 
+                                                                               apr_size_t max_connection_count,
+                                                                               void *obj,
+                                                                               const apt_net_server_vtable_t *server_vtable,
+                                                                               apt_task_msg_pool_t *msg_pool,
+                                                                               apr_pool_t *pool);
+
+/**
+ * Destroy network server task.
+ * @param task the task to destroy
+ */
+APT_DECLARE(apt_bool_t) apt_net_server_task_destroy(apt_net_server_task_t *task);
+
+/**
+ * Start network server task and wait for incoming requests.
+ * @param task the task to start
+ */
+APT_DECLARE(apt_bool_t) apt_net_server_task_start(apt_net_server_task_t *task);
+
+/**
+ * Terminate connection task.
+ * @param task the task to terminate
+ */
+APT_DECLARE(apt_bool_t) apt_net_server_task_terminate(apt_net_server_task_t *task);
+
+/**
+ * Get task base.
+ * @param task the network server task to get task base from
+ */
+APT_DECLARE(apt_task_t*) apt_net_server_task_base_get(apt_net_server_task_t *task);
+
+/**
+ * Get task vtable.
+ * @param task the network server task to get vtable from
+ */
+APT_DECLARE(apt_task_vtable_t*) apt_net_server_task_vtable_get(apt_net_server_task_t *task);
+
+/**
+ * Get external object.
+ * @param task the task to get object from
+ */
+APT_DECLARE(void*) apt_net_server_task_object_get(apt_net_server_task_t *task);
+
+/**
+ * Close connection.
+ */
+APT_DECLARE(apt_bool_t) apt_net_server_connection_close(apt_net_server_task_t *task, apt_net_server_connection_t *connection);
+
+/**
+ * Destroy connection.
+ */
+APT_DECLARE(void) apt_net_server_connection_destroy(apt_net_server_connection_t *connection);
+
+
+APT_END_EXTERN_C
+
+#endif /*__APT_NET_SERVER_TASK_H__*/
diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_obj_list.h b/libs/unimrcp/libs/apr-toolkit/include/apt_obj_list.h
new file mode 100644 (file)
index 0000000..ed33595
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __APT_OBJ_LIST_H__
+#define __APT_OBJ_LIST_H__
+
+/**
+ * @file apt_obj_list.h
+ * @brief List of Opaque void* Objects
+ */ 
+
+#include "apt.h"
+
+APT_BEGIN_EXTERN_C
+
+
+/** Opaque list declaration */
+typedef struct apt_obj_list_t apt_obj_list_t;
+/** Opaque list element declaration */
+typedef struct apt_list_elem_t apt_list_elem_t;
+
+/**
+ * Create list.
+ * @param pool the pool to allocate list from
+ * @return the created list
+ */
+APT_DECLARE(apt_obj_list_t*) apt_list_create(apr_pool_t *pool);
+
+/**
+ * Destroy list.
+ * @param list the list to destroy
+ */
+APT_DECLARE(void) apt_list_destroy(apt_obj_list_t *list);
+
+/**
+ * Push object to the list as first in, first out.
+ * @param list the list to push object to
+ * @param obj the object to push
+ * @param pool the pool to allocate list element from
+ * @return the inserted element
+ */
+APT_DECLARE(apt_list_elem_t*) apt_list_push_back(apt_obj_list_t *list, void *obj, apr_pool_t *pool);
+
+/**
+ * Pop object from the list as first in, first out.
+ * @param list the list to pop message from
+ * @return the popped object (if any)
+ */
+APT_DECLARE(void*) apt_list_pop_front(apt_obj_list_t *list);
+
+/**
+ * Retrieve object of the first element in the list.
+ * @param list the list to retrieve from
+ */
+APT_DECLARE(void*) apt_list_head(apt_obj_list_t *list);
+
+/**
+ * Retrieve object of the last element in the list.
+ * @param list the list to retrieve from
+ */
+APT_DECLARE(void*) apt_obj_list_tail(apt_obj_list_t *list);
+
+
+/**
+ * Retrieve the first element of the list.
+ * @param list the list to retrieve from
+ */
+APT_DECLARE(apt_list_elem_t*) apt_list_first_elem_get(apt_obj_list_t *list);
+
+/**
+ * Retrieve the last element of the list.
+ * @param list the list to retrieve from
+ */
+APT_DECLARE(apt_list_elem_t*) apt_list_last_elem_get(apt_obj_list_t *list);
+
+/**
+ * Retrieve the next element of the list.
+ * @param list the list to retrieve from
+ * @param elem the element to retrieve next element from
+ */
+APT_DECLARE(apt_list_elem_t*) apt_list_next_elem_get(apt_obj_list_t *list, apt_list_elem_t *elem);
+
+/**
+ * Retrieve the prev element of the list.
+ * @param list the list to retrieve from
+ * @param elem the element to retrieve prev element from
+ */
+APT_DECLARE(apt_list_elem_t*) apt_list_prev_elem_get(apt_obj_list_t *list, apt_list_elem_t *elem);
+
+/**
+ * Insert element to the list.
+ * @param list the list to insert element to
+ * @param elem the element to insert before
+ * @param obj the object to insert
+ * @param pool the pool to allocate list element from
+ * @return the inserted element
+ */
+APT_DECLARE(apt_list_elem_t*) apt_list_elem_insert(apt_obj_list_t *list, apt_list_elem_t *elem, void *obj, apr_pool_t *pool);
+
+/**
+ * Remove element from the list.
+ * @param list the list to remove element from
+ * @param elem the element to remove
+ * @return the next element (if any)
+ */
+APT_DECLARE(apt_list_elem_t*) apt_list_elem_remove(apt_obj_list_t *list, apt_list_elem_t *elem);
+
+/**
+ * Query whether the list is empty.
+ * @param list the list to query
+ * @return TRUE if empty, otherwise FALSE
+ */
+APT_DECLARE(apt_bool_t) apt_list_is_empty(apt_obj_list_t *list);
+
+/**
+ * Retrieve the object associated with element.
+ * @param elem the element to retrieve object from
+ */
+APT_DECLARE(void*) apt_list_elem_object_get(apt_list_elem_t *elem);
+
+
+APT_END_EXTERN_C
+
+#endif /*__APT_OBJ_LIST_H__*/
diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_pair.h b/libs/unimrcp/libs/apr-toolkit/include/apt_pair.h
new file mode 100644 (file)
index 0000000..9921ae0
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __APT_PAIR_H__
+#define __APT_PAIR_H__
+
+/**
+ * @file apt_pair.h
+ * @brief Generic Name-Value Pair
+ */ 
+
+#include "apr_tables.h"
+#include "apt_string.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Name-value declaration */
+typedef struct apt_pair_t apt_pair_t;
+
+/** Generic name-value pair definition ("name:value") */
+struct apt_pair_t {
+       /** The name */
+       apt_str_t name;
+       /** The value */
+       apt_str_t value;
+};
+
+/** Dynamic array of name-value pairs */
+typedef apr_array_header_t apt_pair_arr_t;
+
+/** Initialize name-value pair */
+static APR_INLINE void apt_pair_init(apt_pair_t *pair)
+{
+       apt_string_reset(&pair->name);
+       apt_string_reset(&pair->value);
+}
+
+/** Copy name-value pair */
+static APR_INLINE void apt_pair_copy(apt_pair_t *pair, const apt_pair_t *src_pair, apr_pool_t *pool)
+{
+       apt_string_copy(&pair->name,&src_pair->name,pool);
+       apt_string_copy(&pair->value,&src_pair->value,pool);
+}
+
+/** Create array of name-value pairs */
+APT_DECLARE(apt_pair_arr_t*) apt_pair_array_create(apr_size_t initial_size, apr_pool_t *pool);
+/** Copy array of name-value pairs */
+APT_DECLARE(apt_pair_arr_t*) apt_pair_array_copy(const apt_pair_arr_t *src, apr_pool_t *pool);
+/** Append name-value pair */
+APT_DECLARE(apt_bool_t) apt_pair_array_append(apt_pair_arr_t *arr, const apt_str_t *name, const apt_str_t *value, apr_pool_t *pool);
+/** Find name-value pair by name */
+APT_DECLARE(const apt_pair_t*) apt_pair_array_find(const apt_pair_arr_t *arr, const apt_str_t *name);
+/** Get size of pair array */
+APT_DECLARE(int) apt_pair_array_size_get(const apt_pair_arr_t *arr);
+/** Get name-value pair by id */
+APT_DECLARE(const apt_pair_t*) apt_pair_array_get(const apt_pair_arr_t *arr, int id);
+
+APT_END_EXTERN_C
+
+#endif /*__APT_PAIR_H__*/
diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_pollset.h b/libs/unimrcp/libs/apr-toolkit/include/apt_pollset.h
new file mode 100644 (file)
index 0000000..05ba559
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __APT_POLLSET_H__
+#define __APT_POLLSET_H__
+
+/**
+ * @file apt_pollset.h
+ * @brief Interruptable APR-Pollset
+ */ 
+
+/**
+ * Wakeup builtin API of the pollset is introduced only in APR-1.4
+ * and it is not available for APR-1.2 and APR-1.3 versions. Thus
+ * apt_pollset_t is an extension of apr_pollset_t and provides
+ * pollset wakeup capabilities the similar way as it's implemented
+ * in APR-1.4 trunk
+ */
+
+#include <apr_poll.h>
+#include "apt.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque pollset declaration */
+typedef struct apt_pollset_t apt_pollset_t;
+
+/**
+ * Create interruptable pollset on top of APR pollset
+ * @param size the maximum number of descriptors pollset can hold
+ * @param pool the pool to allocate memory from
+ */
+APT_DECLARE(apt_pollset_t*) apt_pollset_create(apr_uint32_t size, apr_pool_t *pool);
+
+/**
+ * Destroy pollset.
+ * @param pollset the pollset to destroy
+ */
+APT_DECLARE(apt_bool_t) apt_pollset_destroy(apt_pollset_t *pollset);
+
+/**
+ * Add pollset descriptor to a pollset.
+ * @param pollset the pollset to add the descriptor to
+ * @param descriptor the descriptor to add
+ */
+APT_DECLARE(apt_bool_t) apt_pollset_add(apt_pollset_t *pollset, const apr_pollfd_t *descriptor);
+
+/**
+ * Remove pollset descriptor from a pollset.
+ * @param pollset the pollset to remove the descriptor from
+ * @param descriptor the descriptor to remove
+ */
+APT_DECLARE(apt_bool_t) apt_pollset_remove(apt_pollset_t *pollset, const apr_pollfd_t *descriptor);
+
+/**
+ * Block for activity on the descriptor(s) in a pollset.
+ * @param pollset the pollset to use
+ * @param timeout the timeout in microseconds
+ * @param num nthe umber of signalled descriptors (output parameter)
+ * @param descriptors the array of signalled descriptors (output parameter)
+ */
+APT_DECLARE(apr_status_t) apt_pollset_poll(
+                                                               apt_pollset_t *pollset,
+                                                               apr_interval_time_t timeout,
+                                                               apr_int32_t *num,
+                                                               const apr_pollfd_t **descriptors);
+
+/**
+ * Interrupt the blocked poll call.
+ * @param pollset the pollset to use
+ */
+APT_DECLARE(apt_bool_t) apt_pollset_wakeup(apt_pollset_t *pollset);
+
+/**
+ * Match against builtin wake up descriptor in a pollset.
+ * @param pollset the pollset to use
+ * @param descriptor the descriptor to match
+ */
+APT_DECLARE(apt_bool_t) apt_pollset_is_wakeup(apt_pollset_t *pollset, const apr_pollfd_t *descriptor);
+
+APT_END_EXTERN_C
+
+#endif /*__APT_POLLSET_H__*/
diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_pool.h b/libs/unimrcp/libs/apr-toolkit/include/apt_pool.h
new file mode 100644 (file)
index 0000000..085195b
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __APT_POOL_H__
+#define __APT_POOL_H__
+
+/**
+ * @file apt_pool.h
+ * @brief APR pool management
+ */ 
+
+/**
+ * Wrappers around APR pool creation 
+ * allow to control memory allocation policy project uses
+ */
+
+#include "apt.h"
+
+APT_BEGIN_EXTERN_C
+
+/**
+ * Create APR pool
+ */
+APT_DECLARE(apr_pool_t*) apt_pool_create();
+
+/**
+ * Create APR subpool pool
+ * @param parent the parent pool
+ */
+APT_DECLARE(apr_pool_t*) apt_subpool_create(apr_pool_t *parent);
+
+APT_END_EXTERN_C
+
+#endif /*__APT_POOL_H__*/
diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_string.h b/libs/unimrcp/libs/apr-toolkit/include/apt_string.h
new file mode 100644 (file)
index 0000000..9d0a7c9
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __APT_STRING_H__
+#define __APT_STRING_H__
+
+/**
+ * @file apt_string.h
+ * @brief String Representation
+ */ 
+
+#include "apt.h"
+
+APT_BEGIN_EXTERN_C
+
+/** String declaration */
+typedef struct apt_str_t apt_str_t;
+
+/** String representation */
+struct apt_str_t {
+       /** String buffer (might be not NULL terminated) */
+       char *buf;
+       /** Length of the string (not counting terminating NULL character if exists) */
+       apr_size_t  length;
+}; 
+
+/** Reset string. */
+static APR_INLINE void apt_string_reset(apt_str_t *str)
+{
+       str->buf = NULL;
+       str->length = 0;
+}
+
+/**
+ * Set NULL terminated string. 
+ * @param str the destination string
+ * @param src the NULL terminated string to set
+ */
+static APR_INLINE void apt_string_set(apt_str_t *str, const char *src)
+{
+       str->buf = (char*)src;
+       str->length = src ? strlen(src) : 0;
+}
+
+/**
+ * Assign (copy) NULL terminated string. 
+ * @param str the destination string
+ * @param src the NULL terminated string to copy
+ * @param pool the pool to allocate memory from
+ */
+static APR_INLINE void apt_string_assign(apt_str_t *str, const char *src, apr_pool_t *pool)
+{
+       str->buf = NULL;
+       str->length = src ? strlen(src) : 0;
+       if(str->length) {
+               str->buf = apr_pstrmemdup(pool,src,str->length);
+       }
+}
+
+/**
+ * Assign (copy) n characters from the src string. 
+ * @param str the destination string
+ * @param src the NULL terminated string to copy
+ * @param pool the pool to allocate memory from
+ */
+static APR_INLINE void apt_string_assign_n(apt_str_t *str, const char *src, apr_size_t length, apr_pool_t *pool)
+{
+       str->buf = NULL;
+       str->length = length;
+       if(str->length) {
+               str->buf = apr_pstrmemdup(pool,src,str->length);
+       }
+}
+
+/**
+ * Copy string. 
+ * @param dest_str the destination string
+ * @param src_str the source string
+ * @param pool the pool to allocate memory from
+ */
+static APR_INLINE void apt_string_copy(apt_str_t *str, const apt_str_t *src_str, apr_pool_t *pool)
+{
+       str->buf = NULL;
+       str->length = src_str->length;
+       if(str->length) {
+               str->buf = apr_pstrmemdup(pool,src_str->buf,src_str->length);
+       }
+}
+
+/**
+ * Compare two strings (case insensitive). 
+ * @param str1 the string to compare
+ * @param str2 the string to compare
+ * @return TRUE if equal, FALSE otherwise
+ */
+static APR_INLINE apt_bool_t apt_string_compare(const apt_str_t *str1, const apt_str_t *str2)
+{
+       if(str1->length != str2->length || !str1->length) {
+               return FALSE;
+       }
+       return (strncasecmp(str1->buf,str2->buf,str1->length) == 0) ? TRUE : FALSE;
+}
+
+APT_END_EXTERN_C
+
+#endif /*__APT_STRING_H__*/
diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_string_table.h b/libs/unimrcp/libs/apr-toolkit/include/apt_string_table.h
new file mode 100644 (file)
index 0000000..112bd6b
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __APT_STRING_TABLE_H__
+#define __APT_STRING_TABLE_H__
+
+/**
+ * @file apt_string_table.h
+ * @brief Generic String Table
+ */ 
+
+#include "apt_string.h"
+
+APT_BEGIN_EXTERN_C
+
+
+/** String table item declaration */
+typedef struct apt_str_table_item_t apt_str_table_item_t;
+
+/** String table item definition */
+struct apt_str_table_item_t {
+       /** String value associated with id */
+       apt_str_t  value;
+       /** Index of the unique (key) character to compare */
+       apr_size_t key;
+};
+
+
+/**
+ * Get the string by a given id.
+ * @param table the table to get string from
+ * @param size the size of the table
+ * @param id the id to get string by
+ * @return the string associated with the id, or NULL if the id is invalid
+ */
+APT_DECLARE(const apt_str_t*) apt_string_table_str_get(const apt_str_table_item_t table[], apr_size_t size, apr_size_t id);
+
+/**
+ * Find the id associated with a given string.
+ * @param table the table to search for the id
+ * @param size the size of the table
+ * @param value the string to search for
+ * @return the id associated with the string, or invalid id if string cannot be matched
+ */
+APT_DECLARE(apr_size_t) apt_string_table_id_find(const apt_str_table_item_t table[], apr_size_t size, const apt_str_t *value);
+
+
+APT_END_EXTERN_C
+
+#endif /*__APT_STRING_TABLE_H__*/
diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_task.h b/libs/unimrcp/libs/apr-toolkit/include/apt_task.h
new file mode 100644 (file)
index 0000000..a2117d7
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __APT_TASK_H__
+#define __APT_TASK_H__
+
+/**
+ * @file apt_task.h
+ * @brief Thread Execution Abstraction
+ */ 
+
+#include "apt.h"
+#include "apt_task_msg.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque task declaration */
+typedef struct apt_task_t apt_task_t;
+/** Opaque task virtual table declaration */
+typedef struct apt_task_vtable_t apt_task_vtable_t;
+/** Opaque task method declaration */
+typedef apt_bool_t (*apt_task_method_f)(apt_task_t *task);
+/** Opaque task event declaration */
+typedef void (*apt_task_event_f)(apt_task_t *task);
+
+
+/**
+ * Create task.
+ * @param obj the external object to associate with the task
+ * @param msg_pool the pool of task messages
+ * @param pool the pool to allocate memory from
+ */
+APT_DECLARE(apt_task_t*) apt_task_create(
+                                                               void *obj,
+                                                               apt_task_msg_pool_t *msg_pool,
+                                                               apr_pool_t *pool);
+
+/**
+ * Destroy task.
+ * @param task the task to destroy
+ */
+APT_DECLARE(apt_bool_t) apt_task_destroy(apt_task_t *task);
+
+/**
+ * Add slave task.
+ * @param task the task to add slave task to
+ * @param child_task the child task to add
+ */
+APT_DECLARE(apt_bool_t) apt_task_add(apt_task_t *task, apt_task_t *child_task);
+
+/**
+ * Start task.
+ * @param task the task to start
+ */
+APT_DECLARE(apt_bool_t) apt_task_start(apt_task_t *task);
+
+/**
+ * Terminate task.
+ * @param task the task to terminate
+ * @param wait_till_complete whether to wait for task to complete or
+ *                           process termination asynchronously
+ */
+APT_DECLARE(apt_bool_t) apt_task_terminate(apt_task_t *task, apt_bool_t wait_till_complete);
+
+/**
+ * Start child tasks.
+ * @param task the parent task
+ */
+APT_DECLARE(apt_bool_t) apt_task_child_start(apt_task_t *task);
+
+/**
+ * Terminate child tasks.
+ * @param task the parent task
+ */
+APT_DECLARE(apt_bool_t) apt_task_child_terminate(apt_task_t *task);
+
+/**
+ * Wait for task till complete.
+ * @param task the task to wait for
+ */
+APT_DECLARE(apt_bool_t) apt_task_wait_till_complete(apt_task_t *task);
+
+/**
+ * Get (acquire) task message.
+ * @param task the task to get task message from
+ */
+APT_DECLARE(apt_task_msg_t*) apt_task_msg_get(apt_task_t *task);
+
+/**
+ * Signal (post) message to the task.
+ * @param task the task to signal message to
+ * @param msg the message to signal
+ */
+APT_DECLARE(apt_bool_t) apt_task_msg_signal(apt_task_t *task, apt_task_msg_t *msg);
+
+/**
+ * Signal (post) message to the parent of the specified task.
+ * @param task the task to signal message to
+ * @param msg the message to signal
+ */
+APT_DECLARE(apt_bool_t) apt_task_msg_parent_signal(apt_task_t *task, apt_task_msg_t *msg);
+
+/**
+ * Process message signaled to the task.
+ * @param task the task to process message
+ * @param msg the message to process
+ */
+APT_DECLARE(apt_bool_t) apt_task_msg_process(apt_task_t *task, apt_task_msg_t *msg);
+
+/**
+ * Get parent (master) task.
+ * @param task the task to get parent from
+ */
+APT_DECLARE(apt_task_t*) apt_task_parent_get(apt_task_t *task);
+
+/**
+ * Get memory pool associated with task.
+ * @param task the task to get pool from
+ */
+APT_DECLARE(apr_pool_t*) apt_task_pool_get(apt_task_t *task);
+
+/**
+ * Get external object associated with the task.
+ * @param task the task to get object from
+ */
+APT_DECLARE(void*) apt_task_object_get(apt_task_t *task);
+
+/**
+ * Get task vtable.
+ * @param task the task to get vtable from
+ */
+APT_DECLARE(apt_task_vtable_t*) apt_task_vtable_get(apt_task_t *task);
+
+/**
+ * Give a name to the task.
+ * @param task the task to give name for
+ * @param name the name to set
+ */
+APT_DECLARE(void) apt_task_name_set(apt_task_t *task, const char *name);
+
+/**
+ * Get task name.
+ * @param task the task to get name from
+ */
+APT_DECLARE(const char*) apt_task_name_get(apt_task_t *task);
+
+/**
+ * Hold task execution.
+ * @param msec the time to hold
+ */
+APT_DECLARE(void) apt_task_delay(apr_size_t msec);
+
+
+/** Table of task virtual methods */
+struct apt_task_vtable_t {
+       /** Virtual destroy method */
+       apt_task_method_f destroy;
+       /** Virtual start method*/
+       apt_task_method_f start;
+       /** Virtual terminate method */
+       apt_task_method_f terminate;
+       /** Virtual run method*/
+       apt_task_method_f run;
+
+       /** Virtual signal method  */
+       apt_bool_t (*signal_msg)(apt_task_t *task, apt_task_msg_t *msg);
+       /** Virtual process method */
+       apt_bool_t (*process_msg)(apt_task_t *task, apt_task_msg_t *msg);
+
+       /** Virtual pre-run event handler */
+       apt_task_event_f on_pre_run;
+       /** Virtual post-run event handler */
+       apt_task_event_f on_post_run;
+       /** Virtual start-complete event handler */
+       apt_task_event_f on_start_complete;
+       /** Virtual terminate-complete event handler */
+       apt_task_event_f on_terminate_complete;
+};
+
+static APR_INLINE void apt_task_vtable_reset(apt_task_vtable_t *vtable)
+{
+       vtable->destroy = NULL;
+       vtable->start = NULL;
+       vtable->terminate = NULL;
+       vtable->run = NULL;
+       vtable->signal_msg = NULL;
+       vtable->process_msg = NULL;
+       vtable->on_pre_run = NULL;
+       vtable->on_post_run = NULL;
+       vtable->on_start_complete = NULL;
+       vtable->on_terminate_complete = NULL;
+}
+
+APT_END_EXTERN_C
+
+#endif /*__APT_TASK_H__*/
diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_task_msg.h b/libs/unimrcp/libs/apr-toolkit/include/apt_task_msg.h
new file mode 100644 (file)
index 0000000..4d43ee5
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __APT_TASK_MSG_H__
+#define __APT_TASK_MSG_H__
+
+/**
+ * @file apt_task_msg.h
+ * @brief Task Message Base Definition
+ */ 
+
+#include "apt.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Enumeration of task message types */
+typedef enum {
+       TASK_MSG_CORE,                   /**< core task message type */
+       TASK_MSG_USER                    /**< user defined task messages start from here */
+} apt_task_msg_type_e;
+
+/** Enumeration of core task messages */
+typedef enum {
+       CORE_TASK_MSG_NONE,              /**< indefinite message */
+       CORE_TASK_MSG_START_COMPLETE,    /**< start-complete message */
+       CORE_TASK_MSG_TERMINATE_REQUEST, /**< terminate-request message */
+       CORE_TASK_MSG_TERMINATE_COMPLETE /**< terminate-complete message */
+} apt_core_task_msg_type_e;
+
+/** Opaque task message declaration */
+typedef struct apt_task_msg_t apt_task_msg_t;
+/** Opaque task message pool declaration */
+typedef struct apt_task_msg_pool_t apt_task_msg_pool_t;
+
+/** Task message is used for inter task communication */
+struct apt_task_msg_t {
+       /** Message pool the task message is allocated from */
+       apt_task_msg_pool_t *msg_pool;
+       /** Task msg type */
+       apt_task_msg_type_e  type;
+       /** Task msg sub type */
+       int                  sub_type;
+       /** Context specific data */
+       char                 data[1];
+};
+
+
+/** Create pool of task messages with dynamic allocation of messages (no actual pool is created) */
+APT_DECLARE(apt_task_msg_pool_t*) apt_task_msg_pool_create_dynamic(apr_size_t msg_size, apr_pool_t *pool);
+
+/** Create pool of task messages with static allocation of messages */
+APT_DECLARE(apt_task_msg_pool_t*) apt_task_msg_pool_create_static(apr_size_t msg_size, apr_size_t msg_pool_size, apr_pool_t *pool);
+
+/** Destroy pool of task messages */
+APT_DECLARE(void) apt_task_msg_pool_destroy(apt_task_msg_pool_t *msg_pool);
+
+
+/** Acquire task message from task message pool */
+APT_DECLARE(apt_task_msg_t*) apt_task_msg_acquire(apt_task_msg_pool_t *task_msg_pool);
+
+/** Realese task message */
+APT_DECLARE(void) apt_task_msg_release(apt_task_msg_t *task_msg);
+
+
+APT_END_EXTERN_C
+
+#endif /*__APT_TASK_MSG_H__*/
diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_test_suite.h b/libs/unimrcp/libs/apr-toolkit/include/apt_test_suite.h
new file mode 100644 (file)
index 0000000..a703de7
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __APT_TEST_SUITE_H__
+#define __APT_TEST_SUITE_H__
+
+/**
+ * @file apt_test_suite.h
+ * @brief Test Suite and Framework Definitions
+ */ 
+
+#include "apt_string.h"
+
+APT_BEGIN_EXTERN_C
+
+
+/** Opaque test suite declaration */
+typedef struct apt_test_suite_t apt_test_suite_t;
+
+/** Prototype of test function */
+typedef apt_bool_t (*apt_test_f)(apt_test_suite_t *suite, int argc, const char * const *argv);
+
+/** Test suite as a base for all kind of tests */
+struct apt_test_suite_t {
+       /** Memory pool to allocate memory from */
+       apr_pool_t *pool;
+       /** Unique name of the test suite */
+       apt_str_t   name;
+       /** External object associated with the test suite */
+       void       *obj;
+       /** Test function to execute */
+       apt_test_f  tester;
+};
+
+/**
+ * Create test suite.
+ * @param pool the pool to allocate memory from
+ * @param name the unique name of the test suite
+ * @param obj the external object associated with the test suite
+ * @param tester the test function to execute
+ */
+APT_DECLARE(apt_test_suite_t*) apt_test_suite_create(apr_pool_t *pool, const char *name, 
+                                                     void *obj, apt_test_f tester);
+
+
+
+
+
+/** Opaque test framework declaration */
+typedef struct apt_test_framework_t apt_test_framework_t;
+
+/**
+ * Create test framework.
+ */
+APT_DECLARE(apt_test_framework_t*) apt_test_framework_create();
+
+/**
+ * Destroy test framework.
+ * @param framework the test framework to destroy
+ */
+APT_DECLARE(void) apt_test_framework_destroy(apt_test_framework_t *framework);
+
+/**
+ * Add test suite to framework.
+ * @param framework the test framework to add test suite to
+ * @param suite the test suite to add
+ */
+APT_DECLARE(apt_bool_t) apt_test_framework_suite_add(apt_test_framework_t *framework, apt_test_suite_t *suite);
+
+/**
+ * Run test suites.
+ * @param framework the test framework
+ * @param argc the number of arguments
+ * @param argv the array of arguments
+ */
+APT_DECLARE(apt_bool_t) apt_test_framework_run(apt_test_framework_t *framework, int argc, const char * const *argv);
+
+/**
+ * Retrieve the memory pool.
+ * @param framework the test framework to retrieve memory pool from
+ */
+APT_DECLARE(apr_pool_t*) apt_test_framework_pool_get(apt_test_framework_t *framework);
+
+APT_END_EXTERN_C
+
+#endif /*__APT_TEST_SUITE_H__*/
diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_text_stream.h b/libs/unimrcp/libs/apr-toolkit/include/apt_text_stream.h
new file mode 100644 (file)
index 0000000..f5fe1c3
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __APT_TEXT_STREAM_H__
+#define __APT_TEXT_STREAM_H__
+
+/**
+ * @file apt_text_stream.h
+ * @brief Text Stream Parse/Generate Routine
+ */ 
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "apt_string.h"
+#include "apt_pair.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Named tokens */
+
+/** Space */
+#define APT_TOKEN_SP ' '
+/** Carrige return */
+#define APT_TOKEN_CR 0x0D
+/** Line feed */
+#define APT_TOKEN_LF 0x0A
+
+/** Text stream declaration */
+typedef struct apt_text_stream_t apt_text_stream_t;
+
+/** Text stream is used for message parsing and generation */
+struct apt_text_stream_t {
+       /** Text stream */
+       apt_str_t text;
+       /** Current position in the buffer */
+       char     *pos;
+};
+
+/**
+ * Navigate through the lines of the text stream (message).
+ * @param stream the text stream to navigate
+ * @param line the read line to return
+ * @return TRUE if the length of the line > 0, otherwise FALSE
+ */
+APT_DECLARE(apt_bool_t) apt_text_line_read(apt_text_stream_t *stream, apt_str_t *line);
+
+/**
+ * Navigate through the headers (name:value pairs) of the text stream (message).
+ * @param stream the text stream to navigate
+ * @param pair the read pair to return
+ * @return TRUE if the length of the read name > 0, otherwise FALSE
+ */
+APT_DECLARE(apt_bool_t) apt_text_header_read(apt_text_stream_t *stream, apt_pair_t *pair);
+
+/**
+ * Navigate through the fields of the line.
+ * @param stream the text stream to navigate
+ * @param separator the field separator
+ * @param skip_spaces whether to skip spaces or not
+ * @param field the read field to return
+ * @return TRUE if the length of the field > 0, otherwise FALSE
+ */
+APT_DECLARE(apt_bool_t) apt_text_field_read(apt_text_stream_t *stream, char separator, apt_bool_t skip_spaces, apt_str_t *field);
+
+
+
+/** Generate header */
+APT_DECLARE(apt_bool_t) apt_text_header_generate(const apt_pair_t *pair, apt_text_stream_t *text_stream);
+
+/** Generate only the name ("name:") of the header */
+APT_DECLARE(apt_bool_t) apt_text_header_name_generate(const apt_str_t *name, apt_text_stream_t *text_stream);
+
+/** Parse array of name-value pairs */
+APT_DECLARE(apt_bool_t) apt_pair_array_parse(apt_pair_arr_t *arr, const apt_str_t *value, apr_pool_t *pool);
+/** Generate array of name-value pairs */
+APT_DECLARE(apt_bool_t) apt_pair_array_generate(apt_pair_arr_t *arr, apt_text_stream_t *text_stream);
+
+
+/** Parse boolean-value */
+APT_DECLARE(apt_bool_t) apt_boolean_value_parse(const apt_str_t *str, apt_bool_t *value);
+
+/** Generate boolean-value */
+APT_DECLARE(apt_bool_t) apt_boolean_value_generate(apt_bool_t value, apt_text_stream_t *str);
+
+
+/** Parse size_t value */
+static APR_INLINE apr_size_t apt_size_value_parse(const apt_str_t *str)
+{
+       return str->buf ? atol(str->buf) : 0;
+}
+
+/** Generate apr_size_t value */
+static APR_INLINE apt_bool_t apt_size_value_generate(apr_size_t value, apt_text_stream_t *stream)
+{
+       int length = sprintf(stream->pos, "%"APR_SIZE_T_FMT, value);
+       if(length <= 0) {
+               return FALSE;
+       }
+       stream->pos += length;
+       return TRUE;
+}
+
+/** Parse float value */
+static APR_INLINE float apt_float_value_parse(const apt_str_t *str)
+{
+       return str->buf ? (float)atof(str->buf) : 0;
+}
+
+/** Generate float value */
+static APR_INLINE apt_bool_t apt_float_value_generate(float value, apt_text_stream_t *stream)
+{
+       int length = sprintf(stream->pos,"%.1f",value);
+       if(length <= 0) {
+               return FALSE;
+       }
+       stream->pos += length;
+       return TRUE;
+}
+
+/** Generate string value */
+static APR_INLINE apt_bool_t apt_string_value_generate(const apt_str_t *str, apt_text_stream_t *stream)
+{
+       if(str->length) {
+               memcpy(stream->pos,str->buf,str->length);
+               stream->pos += str->length;
+       }
+       return TRUE;
+}
+
+/** Initialize text stream */
+static APR_INLINE void apt_text_stream_init(apt_text_stream_t *stream, char *buffer, apr_size_t size)
+{
+       stream->text.buf = buffer;
+       stream->text.length = size;
+       stream->pos = stream->text.buf;
+}
+
+/** Insert end of the line symbol(s) */
+static APR_INLINE void apt_text_eol_insert(apt_text_stream_t *stream)
+{
+       *stream->pos++ = APT_TOKEN_CR;
+       *stream->pos++ = APT_TOKEN_LF;
+}
+
+/** Insert character */
+static APR_INLINE void apt_text_char_insert(apt_text_stream_t *stream, char ch)
+{
+       *stream->pos++ = ch;
+}
+
+/** Insert space */
+static APR_INLINE void apt_text_space_insert(apt_text_stream_t *stream)
+{
+       *stream->pos++ = APT_TOKEN_SP;
+}
+
+/** Skip spaces */
+static APR_INLINE void apt_text_spaces_skip(apt_text_stream_t *stream)
+{
+       const char *end = stream->text.buf + stream->text.length;
+       while(stream->pos < end && *stream->pos == APT_TOKEN_SP) stream->pos++;
+}
+
+/** Skip specified character */
+static APR_INLINE void apt_text_char_skip(apt_text_stream_t *stream, char ch)
+{
+       const char *end = stream->text.buf + stream->text.length;
+       if(stream->pos < end && *stream->pos == ch) stream->pos++;
+}
+
+/** Check whether end of stream is reached */
+static APR_INLINE apt_bool_t apt_text_is_eos(const apt_text_stream_t *stream)
+{
+       const char *end = stream->text.buf + stream->text.length;
+       return (stream->pos >= end) ? TRUE : FALSE;
+}
+
+/** Scroll text stream */
+APT_DECLARE(apt_bool_t) apt_text_stream_scroll(apt_text_stream_t *stream);
+
+/** Parse id at resource string */
+APT_DECLARE(apt_bool_t) apt_id_resource_parse(const apt_str_t *str, char separator, apt_str_t *id, apt_str_t *resource, apr_pool_t *pool);
+
+/** Generate id at resource string */
+APT_DECLARE(apt_bool_t) apt_id_resource_generate(const apt_str_t *id, const apt_str_t *resource, char separator, apt_str_t *str, apr_pool_t *pool);
+
+/** Generate value plus the length (number of digits) of the value itself */
+APT_DECLARE(apt_bool_t) apt_var_length_value_generate(apr_size_t *value, apr_size_t max_count, apt_str_t *str);
+
+
+/**
+ * Generate unique identifier (hex string)
+ * @param id the id to generate
+ * @param length the length of hex string to generate
+ * @param pool the pool to allocate memory from
+ */
+APT_DECLARE(apt_bool_t) apt_unique_id_generate(apt_str_t *id, apr_size_t length, apr_pool_t *pool);
+
+
+APT_END_EXTERN_C
+
+#endif /*__APT_TEXT_STREAM_H__*/
diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_consumer_task.c b/libs/unimrcp/libs/apr-toolkit/src/apt_consumer_task.c
new file mode 100644 (file)
index 0000000..42a8754
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_queue.h>
+#include "apt_consumer_task.h"
+
+struct apt_consumer_task_t {
+       void        *obj;
+       apt_task_t  *base;
+       apr_queue_t *msg_queue;
+};
+
+static apt_bool_t apt_consumer_task_msg_signal(apt_task_t *task, apt_task_msg_t *msg);
+static apt_bool_t apt_consumer_task_run(apt_task_t *task);
+
+APT_DECLARE(apt_consumer_task_t*) apt_consumer_task_create(
+                                                                       void *obj,
+                                                                       apt_task_msg_pool_t *msg_pool,
+                                                                       apr_pool_t *pool)
+{
+       apt_task_vtable_t *vtable;
+       apt_consumer_task_t *consumer_task = apr_palloc(pool,sizeof(apt_consumer_task_t));
+       consumer_task->obj = obj;
+       consumer_task->msg_queue = NULL;
+       if(apr_queue_create(&consumer_task->msg_queue,1024,pool) != APR_SUCCESS) {
+               return NULL;
+       }
+       
+       consumer_task->base = apt_task_create(consumer_task,msg_pool,pool);
+       if(!consumer_task->base) {
+               return NULL;
+       }
+
+       vtable = apt_task_vtable_get(consumer_task->base);
+       if(vtable) {
+               vtable->run = apt_consumer_task_run;
+               vtable->signal_msg = apt_consumer_task_msg_signal;
+       }
+       return consumer_task;
+}
+
+APT_DECLARE(apt_task_t*) apt_consumer_task_base_get(apt_consumer_task_t *task)
+{
+       return task->base;
+}
+
+APT_DECLARE(apt_task_vtable_t*) apt_consumer_task_vtable_get(apt_consumer_task_t *task)
+{
+       return apt_task_vtable_get(task->base);
+}
+
+APT_DECLARE(void*) apt_consumer_task_object_get(apt_consumer_task_t *task)
+{
+       return task->obj;
+}
+
+static apt_bool_t apt_consumer_task_msg_signal(apt_task_t *task, apt_task_msg_t *msg)
+{
+       apt_consumer_task_t *consumer_task = apt_task_object_get(task);
+       return (apr_queue_push(consumer_task->msg_queue,msg) == APR_SUCCESS) ? TRUE : FALSE;
+}
+
+static apt_bool_t apt_consumer_task_run(apt_task_t *task)
+{
+       apr_status_t rv;
+       void *msg;
+       apt_bool_t running = TRUE;
+       apt_consumer_task_t *consumer_task;
+       consumer_task = apt_task_object_get(task);
+       if(!consumer_task) {
+               return FALSE;
+       }
+
+       while(running) {
+               rv = apr_queue_pop(consumer_task->msg_queue,&msg);
+               if(rv == APR_SUCCESS) {
+                       if(msg) {
+                               apt_task_msg_t *task_msg = msg;
+                               if(apt_task_msg_process(consumer_task->base,task_msg) == FALSE) {
+                                       running = FALSE;
+                               }
+                       }
+               }
+       }
+       return TRUE;
+}
diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_cyclic_queue.c b/libs/unimrcp/libs/apr-toolkit/src/apt_cyclic_queue.c
new file mode 100644 (file)
index 0000000..fff7de5
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include "apt_cyclic_queue.h"
+
+struct apt_cyclic_queue_t {
+       void       **data;
+       apr_size_t   max_size;
+       apr_size_t   actual_size;
+       apr_size_t   head;
+       apr_size_t   tail;
+};
+
+static apt_bool_t apt_cyclic_queue_resize(apt_cyclic_queue_t *queue);
+
+
+APT_DECLARE(apt_cyclic_queue_t*) apt_cyclic_queue_create(apr_size_t size)
+{
+       apt_cyclic_queue_t *queue = malloc(sizeof(apt_cyclic_queue_t));
+       queue->max_size = size;
+       queue->actual_size = 0;
+       queue->data = malloc(sizeof(void*) * queue->max_size);
+       queue->head = queue->tail = 0;
+       return queue;
+}
+
+APT_DECLARE(void) apt_cyclic_queue_destroy(apt_cyclic_queue_t *queue)
+{
+       if(queue->data) {
+               free(queue->data);
+               queue->data = NULL;
+       }
+       free(queue);
+}
+
+APT_DECLARE(apt_bool_t) apt_cyclic_queue_push(apt_cyclic_queue_t *queue, void *obj)
+{
+       if(queue->actual_size >= queue->max_size) {
+               if(apt_cyclic_queue_resize(queue) != TRUE) {
+                       return FALSE;
+               }
+       }
+       
+       queue->data[queue->head] = obj;
+       queue->head = (queue->head + 1) % queue->max_size;
+       queue->actual_size++;
+       return TRUE;
+}
+
+APT_DECLARE(void*) apt_cyclic_queue_pop(apt_cyclic_queue_t *queue)
+{
+       void *obj = NULL;
+       if(queue->actual_size) {
+               obj = queue->data[queue->tail];
+               queue->tail = (queue->tail + 1) % queue->max_size;
+               queue->actual_size--;
+       }
+       return obj;
+}
+
+APT_DECLARE(void) apt_cyclic_queue_clear(apt_cyclic_queue_t *queue)
+{
+       queue->actual_size = 0;
+       queue->head = queue->tail = 0;
+}
+
+APT_DECLARE(apt_bool_t) apt_cyclic_queue_is_empty(apt_cyclic_queue_t *queue)
+{
+       return queue->actual_size ? TRUE : FALSE;
+}
+
+static apt_bool_t apt_cyclic_queue_resize(apt_cyclic_queue_t *queue)
+{
+       apr_size_t new_size = queue->max_size + queue->max_size/2;
+       void **new_data = malloc(sizeof(void*) * new_size);
+       apr_size_t offset;
+
+       offset = queue->max_size - queue->head;
+       memcpy(new_data, queue->data + queue->head, sizeof(void*) * offset);
+       if(queue->head) {
+               memcpy(new_data + offset, queue->data, sizeof(void*) * queue->head);
+       }
+
+       queue->tail = 0;
+       queue->head = queue->max_size;
+       queue->max_size = new_size;
+       free(queue->data);
+       queue->data = new_data;
+       return TRUE;
+}
diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_dir_layout.c b/libs/unimrcp/libs/apr-toolkit/src/apt_dir_layout.c
new file mode 100644 (file)
index 0000000..9a527b6
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_file_info.h>
+#include "apt_dir_layout.h"
+
+static apt_dir_layout_t* apt_dir_layout_alloc(apr_pool_t *pool)
+{
+       apt_dir_layout_t *dir_layout = (apt_dir_layout_t*) apr_palloc(pool,sizeof(apt_dir_layout_t));
+       dir_layout->conf_dir_path = NULL;
+       dir_layout->plugin_dir_path = NULL;
+       dir_layout->log_dir_path = NULL;
+       dir_layout->data_dir_path = NULL;
+       return dir_layout;
+}
+
+APT_DECLARE(apt_dir_layout_t*) apt_default_dir_layout_create(const char *root_dir_path, apr_pool_t *pool)
+{
+       apt_dir_layout_t *dir_layout = apt_dir_layout_alloc(pool);
+       if(root_dir_path) {
+               apr_filepath_merge(&dir_layout->conf_dir_path,root_dir_path,"conf",0,pool);
+               apr_filepath_merge(&dir_layout->plugin_dir_path,root_dir_path,"plugin",0,pool);
+               apr_filepath_merge(&dir_layout->log_dir_path,root_dir_path,"log",0,pool);
+               apr_filepath_merge(&dir_layout->data_dir_path,root_dir_path,"data",0,pool);
+       }
+       return dir_layout;
+}
+
+APT_DECLARE(apt_dir_layout_t*) apt_custom_dir_layout_create(
+                                                                       const char *conf_dir_path,
+                                                                       const char *plugin_dir_path,
+                                                                       const char *log_dir_path,
+                                                                       const char *data_dir_path,
+                                                                       apr_pool_t *pool)
+{
+       apt_dir_layout_t *dir_layout = apt_dir_layout_alloc(pool);
+       if(conf_dir_path) {
+               dir_layout->conf_dir_path = apr_pstrdup(pool,conf_dir_path);
+       }
+       if(plugin_dir_path) {
+               dir_layout->plugin_dir_path = apr_pstrdup(pool,plugin_dir_path);
+       }
+       if(log_dir_path) {
+               dir_layout->log_dir_path = apr_pstrdup(pool,log_dir_path);
+       }
+       if(data_dir_path) {
+               dir_layout->data_dir_path = apr_pstrdup(pool,data_dir_path);
+       }
+       return dir_layout;
+}
+
+APT_DECLARE(char*) apt_datadir_filepath_get(const apt_dir_layout_t *dir_layout, const char *file_name, apr_pool_t *pool)
+{
+       if(dir_layout && dir_layout->data_dir_path && file_name) {
+               char *file_path = NULL;
+               if(apr_filepath_merge(&file_path,dir_layout->data_dir_path,file_name,0,pool) == APR_SUCCESS) {
+                       return file_path;
+               }
+       }
+       return NULL;
+}
diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_log.c b/libs/unimrcp/libs/apr-toolkit/src/apt_log.c
new file mode 100644 (file)
index 0000000..25a5abf
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_time.h>
+#include <apr_file_io.h>
+#include "apt_log.h"
+
+#define MAX_LOG_ENTRY_SIZE 4096
+#define MAX_PRIORITY_NAME_LENGTH 9
+
+static const char priority_snames[APT_PRIO_COUNT][MAX_PRIORITY_NAME_LENGTH+1] =
+{
+       "[EMERG]  ",
+       "[ALERT]  ",
+       "[CRITIC] ",
+       "[ERROR]  ",
+       "[WARN]   ",
+       "[NOTICE] ",
+       "[INFO]   ",
+       "[DEBUG]  "
+};
+
+typedef struct apt_log_file_data_t apt_log_file_data_t;
+
+struct apt_log_file_data_t {
+       const char           *log_dir_path;
+       const char           *log_file_name;
+       FILE                 *file;
+       apr_size_t            cur_size;
+       apr_size_t            max_size;
+       apr_size_t            cur_file_index;
+       apr_size_t            max_file_count;
+       apr_thread_mutex_t   *mutex;
+       apr_pool_t           *pool;
+};
+
+struct apt_logger_t {
+       apt_log_output_e      mode;
+       apt_log_priority_e    priority;
+       int                   header;
+       apt_log_ext_handler_f ext_handler;
+       apt_log_file_data_t  *file_data;
+};
+
+static apt_logger_t *apt_logger = NULL;
+
+static apt_bool_t apt_do_log(const char *file, int line, apt_log_priority_e priority, const char *format, va_list arg_ptr);
+
+static const char* apt_log_file_path_make(apt_log_file_data_t *file_data);
+static apt_bool_t apt_log_file_dump(apt_log_file_data_t *file_data, const char *log_entry, apr_size_t size);
+
+
+APT_DECLARE(apt_bool_t) apt_log_instance_create(apt_log_output_e mode, apt_log_priority_e priority, apr_pool_t *pool)
+{
+       if(apt_logger) {
+               return FALSE;
+       }
+       apt_logger = apr_palloc(pool,sizeof(apt_logger_t));
+       apt_logger->mode = mode;
+       apt_logger->priority = priority;
+       apt_logger->header = APT_LOG_HEADER_DEFAULT;
+       apt_logger->ext_handler = NULL;
+       apt_logger->file_data = NULL;
+       return TRUE;
+}
+
+APT_DECLARE(apt_bool_t) apt_log_instance_destroy()
+{
+       if(!apt_logger) {
+               return FALSE;
+       }
+
+       if(apt_logger->file_data) {
+               apt_log_file_close();
+       }
+       apt_logger = NULL;
+       return TRUE;
+}
+
+APT_DECLARE(apt_logger_t*) apt_log_instance_get()
+{
+       return apt_logger;
+}
+
+APT_DECLARE(apt_bool_t) apt_log_instance_set(apt_logger_t *logger)
+{
+       if(apt_logger){
+               return FALSE;
+       }
+       apt_logger = logger;
+       return TRUE;
+}
+
+APT_DECLARE(apt_bool_t) apt_log_file_open(const char *dir_path, const char *file_name, apr_size_t max_file_size, apr_size_t max_file_count, apr_pool_t *pool)
+{
+       const char *log_file_path;
+       apt_log_file_data_t *file_data;
+       if(!apt_logger || !dir_path || !file_name) {
+               return FALSE;
+       }
+
+       if(apt_logger->file_data) {
+               return FALSE;
+       }
+
+       file_data = apr_palloc(pool,sizeof(apt_log_file_data_t));
+       file_data->log_dir_path = dir_path;
+       file_data->log_file_name = file_name;
+       file_data->cur_file_index = 0;
+       file_data->cur_size = 0;
+       file_data->max_file_count = max_file_count;
+       file_data->max_size = max_file_size;
+       file_data->mutex = NULL;
+       file_data->pool = pool;
+
+       if(!file_data->max_size) {
+               file_data->max_file_count = MAX_LOG_FILE_SIZE;
+       }
+       if(!file_data->max_file_count) {
+               file_data->max_file_count = MAX_LOG_FILE_COUNT;
+       }
+
+       /* create mutex */
+       if(apr_thread_mutex_create(&file_data->mutex,APR_THREAD_MUTEX_DEFAULT,pool) != APR_SUCCESS) {
+               return FALSE;
+       }
+       /* open log file */
+       log_file_path = apt_log_file_path_make(file_data);
+       file_data->file = fopen(log_file_path,"wb");
+       if(!file_data->file) {
+               apr_thread_mutex_destroy(file_data->mutex);
+               return FALSE;
+       }
+
+       apt_logger->file_data = file_data;
+       return TRUE;
+}
+
+APT_DECLARE(apt_bool_t) apt_log_file_close()
+{
+       apt_log_file_data_t *file_data;
+       if(!apt_logger || !apt_logger->file_data) {
+               return FALSE;
+       }
+       file_data = apt_logger->file_data;
+       if(file_data->file) {
+               /* close log file */
+               fclose(file_data->file);
+               file_data->file = NULL;
+               /* destroy mutex */
+               apr_thread_mutex_destroy(file_data->mutex);
+               file_data->mutex = NULL;
+       }
+       apt_logger->file_data = NULL;
+       return TRUE;
+}
+
+APT_DECLARE(apt_bool_t) apt_log_output_mode_set(apt_log_output_e mode)
+{
+       if(!apt_logger) {
+               return FALSE;
+       }
+       apt_logger->mode = mode;
+       return TRUE;
+}
+
+APT_DECLARE(apt_bool_t) apt_log_priority_set(apt_log_priority_e priority)
+{
+       if(!apt_logger || priority >= APT_PRIO_COUNT) {
+               return FALSE;
+       }
+       apt_logger->priority = priority;
+       return TRUE;
+}
+
+APT_DECLARE(apt_bool_t) apt_log_header_set(int header)
+{
+       if(!apt_logger) {
+               return FALSE;
+       }
+       apt_logger->header = header;
+       return TRUE;
+}
+
+APT_DECLARE(apt_bool_t) apt_log_ext_handler_set(apt_log_ext_handler_f handler)
+{
+       if(!apt_logger) {
+               return FALSE;
+       }
+       apt_logger->ext_handler = handler;
+       return TRUE;
+}
+
+APT_DECLARE(apt_bool_t) apt_log(const char *file, int line, apt_log_priority_e priority, const char *format, ...)
+{
+       apt_bool_t status = TRUE;
+       if(!apt_logger) {
+               return FALSE;
+       }
+       if(priority <= apt_logger->priority) {
+               va_list arg_ptr;
+               va_start(arg_ptr, format);
+               if(apt_logger->ext_handler) {
+                       status = apt_logger->ext_handler(file,line,NULL,priority,format,arg_ptr);
+               }
+               else {
+                       status = apt_do_log(file,line,priority,format,arg_ptr);
+               }
+               va_end(arg_ptr); 
+       }
+       return status;
+}
+
+static apt_bool_t apt_do_log(const char *file, int line, apt_log_priority_e priority, const char *format, va_list arg_ptr)
+{
+       char log_entry[MAX_LOG_ENTRY_SIZE];
+       apr_size_t offset = 0;
+       apr_time_exp_t result;
+       apr_time_t now = apr_time_now();
+       apr_time_exp_lt(&result,now);
+
+       if(apt_logger->header & APT_LOG_HEADER_DATE) {
+               offset += apr_snprintf(log_entry+offset,MAX_LOG_ENTRY_SIZE-offset,"%4d-%02d-%02d ",
+                                                       result.tm_year+1900,
+                                                       result.tm_mon+1,
+                                                       result.tm_mday);
+       }
+       if(apt_logger->header & APT_LOG_HEADER_TIME) {
+               offset += apr_snprintf(log_entry+offset,MAX_LOG_ENTRY_SIZE-offset,"%02d:%02d:%02d:%06d ",
+                                                       result.tm_hour,
+                                                       result.tm_min,
+                                                       result.tm_sec,
+                                                       result.tm_usec);
+       }
+       if(apt_logger->header & APT_LOG_HEADER_MARK) {
+               offset += apr_snprintf(log_entry+offset,MAX_LOG_ENTRY_SIZE-offset,"%s:%03d ",file,line);
+       }
+       if(apt_logger->header & APT_LOG_HEADER_PRIORITY) {
+               memcpy(log_entry+offset,priority_snames[priority],MAX_PRIORITY_NAME_LENGTH);
+               offset += MAX_PRIORITY_NAME_LENGTH;
+       }
+
+       offset += apr_vsnprintf(log_entry+offset,MAX_LOG_ENTRY_SIZE-offset,format,arg_ptr);
+       log_entry[offset++] = '\n';
+       log_entry[offset] = '\0';
+       if((apt_logger->mode & APT_LOG_OUTPUT_CONSOLE) == APT_LOG_OUTPUT_CONSOLE) {
+               printf(log_entry);
+       }
+       
+       if((apt_logger->mode & APT_LOG_OUTPUT_FILE) == APT_LOG_OUTPUT_FILE && apt_logger->file_data) {
+               apt_log_file_dump(apt_logger->file_data,log_entry,offset);
+       }
+       return TRUE;
+}
+
+static const char* apt_log_file_path_make(apt_log_file_data_t *file_data)
+{
+       char *log_file_path = NULL;
+       const char *log_file_name = apr_psprintf(file_data->pool,"%s-%d.log",file_data->log_file_name,file_data->cur_file_index);
+       apr_filepath_merge(&log_file_path,file_data->log_dir_path,log_file_name,0,file_data->pool);
+       return log_file_path;
+}
+
+static apt_bool_t apt_log_file_dump(apt_log_file_data_t *file_data, const char *log_entry, apr_size_t size)
+{
+       apr_thread_mutex_lock(file_data->mutex);
+
+       file_data->cur_size += size;
+       if(file_data->cur_size > file_data->max_size) {
+               const char *log_file_path;
+               /* close current log file */
+               fclose(file_data->file);
+               /* roll over the next log file */
+               file_data->cur_file_index++;
+               file_data->cur_file_index %= file_data->max_file_count;
+               /* open log file */
+               log_file_path = apt_log_file_path_make(file_data);
+               file_data->file = fopen(log_file_path,"wb");
+               if(!file_data->file) {
+                       return FALSE;
+               }
+
+               file_data->cur_size = size;
+       }
+       /* write to log file */
+       fwrite(log_entry,1,size,file_data->file);
+       fflush(file_data->file);
+
+       apr_thread_mutex_unlock(file_data->mutex);
+       return TRUE;
+}
diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_net.c b/libs/unimrcp/libs/apr-toolkit/src/apt_net.c
new file mode 100644 (file)
index 0000000..bf5b8a9
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_network_io.h>
+#include "apt_net.h"
+
+/** Get the IP address (in numeric address string format) by hostname */
+apt_bool_t apt_ip_get(char **addr, apr_pool_t *pool)
+{
+       apr_sockaddr_t *sockaddr = NULL;
+       char *hostname = apr_palloc(pool,APRMAXHOSTLEN+1);
+       if(apr_gethostname(hostname,APRMAXHOSTLEN,pool) != APR_SUCCESS) {
+               return FALSE;
+       }
+       if(apr_sockaddr_info_get(&sockaddr,hostname,APR_INET,0,0,pool) != APR_SUCCESS) {
+               return FALSE;
+       }
+       if(apr_sockaddr_ip_get(addr,sockaddr) != APR_SUCCESS) {
+               return FALSE;
+       }
+       return TRUE;
+}
diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_net_client_task.c b/libs/unimrcp/libs/apr-toolkit/src/apt_net_client_task.c
new file mode 100644 (file)
index 0000000..eb7cf63
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apt_net_client_task.h"
+#include "apt_task.h"
+#include "apt_pool.h"
+#include "apt_pollset.h"
+#include "apt_cyclic_queue.h"
+#include "apt_log.h"
+
+
+/** Network client task */
+struct apt_net_client_task_t {
+       apr_pool_t                    *pool;
+       apt_task_t                    *base;
+       void                          *obj;
+
+       apr_size_t                     max_connection_count;
+
+       apr_thread_mutex_t            *guard;
+       apt_cyclic_queue_t            *msg_queue;
+       apt_pollset_t                 *pollset;
+
+       const apt_net_client_vtable_t *client_vtable;
+};
+
+static apt_bool_t apt_net_client_task_msg_signal(apt_task_t *task, apt_task_msg_t *msg);
+static apt_bool_t apt_net_client_task_run(apt_task_t *task);
+static apt_bool_t apt_net_client_task_on_destroy(apt_task_t *task);
+
+/** Create connection task */
+APT_DECLARE(apt_net_client_task_t*) apt_net_client_task_create(
+                                                                               apr_size_t max_connection_count,
+                                                                               void *obj,
+                                                                               const apt_net_client_vtable_t *client_vtable,
+                                                                               apt_task_msg_pool_t *msg_pool,
+                                                                               apr_pool_t *pool)
+{
+       apt_task_vtable_t *vtable;
+       apt_net_client_task_t *task;
+       
+       task = apr_palloc(pool,sizeof(apt_net_client_task_t));
+       task->pool = pool;
+       task->obj = obj;
+       task->pollset = NULL;
+       task->max_connection_count = max_connection_count;
+
+       if(!client_vtable || !client_vtable->on_receive) {
+               return NULL;
+       }
+       task->client_vtable = client_vtable;
+
+       task->base = apt_task_create(task,msg_pool,pool);
+       if(!task->base) {
+               return NULL;
+       }
+
+       vtable = apt_task_vtable_get(task->base);
+       if(vtable) {
+               vtable->run = apt_net_client_task_run;
+               vtable->destroy = apt_net_client_task_on_destroy;
+               vtable->signal_msg = apt_net_client_task_msg_signal;
+       }
+
+       task->msg_queue = apt_cyclic_queue_create(CYCLIC_QUEUE_DEFAULT_SIZE);
+       apr_thread_mutex_create(&task->guard,APR_THREAD_MUTEX_UNNESTED,pool);
+       return task;
+}
+
+/** Virtual destroy handler */
+static apt_bool_t apt_net_client_task_on_destroy(apt_task_t *base)
+{
+       apt_net_client_task_t *task = apt_task_object_get(base);
+       if(task->guard) {
+               apr_thread_mutex_destroy(task->guard);
+               task->guard = NULL;
+       }
+       if(task->msg_queue) {
+               apt_cyclic_queue_destroy(task->msg_queue);
+               task->msg_queue = NULL;
+       }
+       return TRUE;
+}
+
+/** Destroy connection task. */
+APT_DECLARE(apt_bool_t) apt_net_client_task_destroy(apt_net_client_task_t *task)
+{
+       return apt_task_destroy(task->base);
+}
+
+/** Start connection task. */
+APT_DECLARE(apt_bool_t) apt_net_client_task_start(apt_net_client_task_t *task)
+{
+       return apt_task_start(task->base);
+}
+
+/** Terminate connection task. */
+APT_DECLARE(apt_bool_t) apt_net_client_task_terminate(apt_net_client_task_t *task)
+{
+       return apt_task_terminate(task->base,TRUE);
+}
+
+/** Get task */
+APT_DECLARE(apt_task_t*) apt_net_client_task_base_get(apt_net_client_task_t *task)
+{
+       return task->base;
+}
+
+/** Get task vtable */
+APT_DECLARE(apt_task_vtable_t*) apt_net_client_task_vtable_get(apt_net_client_task_t *task)
+{
+       return apt_task_vtable_get(task->base);
+}
+
+/** Get external object */
+APT_DECLARE(void*) apt_net_client_task_object_get(apt_net_client_task_t *task)
+{
+       return task->obj;
+}
+
+/** Create connection */
+APT_DECLARE(apt_net_client_connection_t*) apt_net_client_connect(apt_net_client_task_t *task, const char *ip, apr_port_t port)
+{
+       char *local_ip = NULL;
+       char *remote_ip = NULL;
+       apr_sockaddr_t *l_sockaddr = NULL;
+       apr_sockaddr_t *r_sockaddr = NULL;
+       apt_net_client_connection_t *connection;
+       apr_pool_t *pool = apt_pool_create();
+       if(!pool) {
+               return NULL;
+       }
+       
+       connection = apr_palloc(pool,sizeof(apt_net_client_connection_t));
+       connection->pool = pool;
+       connection->obj = NULL;
+       connection->sock = NULL;
+
+       if(apr_sockaddr_info_get(&r_sockaddr,ip,APR_INET,port,0,connection->pool) != APR_SUCCESS) {
+               apr_pool_destroy(pool);
+               return NULL;
+       }
+
+       if(apr_socket_create(&connection->sock,r_sockaddr->family,SOCK_STREAM,APR_PROTO_TCP,connection->pool) != APR_SUCCESS) {
+               apr_pool_destroy(pool);
+               return NULL;
+       }
+
+       apr_socket_opt_set(connection->sock, APR_SO_NONBLOCK, 0);
+       apr_socket_timeout_set(connection->sock, -1);
+       apr_socket_opt_set(connection->sock, APR_SO_REUSEADDR, 1);
+
+       if(apr_socket_connect(connection->sock,r_sockaddr) != APR_SUCCESS) {
+               apr_socket_close(connection->sock);
+               apr_pool_destroy(pool);
+               return NULL;
+       }
+
+       if(apr_socket_addr_get(&l_sockaddr,APR_LOCAL,connection->sock) != APR_SUCCESS) {
+               apr_socket_close(connection->sock);
+               apr_pool_destroy(pool);
+               return NULL;
+       }
+
+       apr_sockaddr_ip_get(&local_ip,l_sockaddr);
+       apr_sockaddr_ip_get(&remote_ip,r_sockaddr);
+       connection->id = apr_psprintf(pool,"%s:%hu <-> %s:%hu",
+               local_ip,l_sockaddr->port,
+               remote_ip,r_sockaddr->port);
+
+       memset(&connection->sock_pfd,0,sizeof(apr_pollfd_t));
+       connection->sock_pfd.desc_type = APR_POLL_SOCKET;
+       connection->sock_pfd.reqevents = APR_POLLIN;
+       connection->sock_pfd.desc.s = connection->sock;
+       connection->sock_pfd.client_data = connection;
+       if(apt_pollset_add(task->pollset,&connection->sock_pfd) != TRUE) {
+               apr_socket_close(connection->sock);
+               apr_pool_destroy(pool);
+               return NULL;
+       }
+       
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Established TCP Connection %s",connection->id);
+       return connection;
+}
+
+/** Close connection */
+APT_DECLARE(apt_bool_t) apt_net_client_connection_close(apt_net_client_task_t *task, apt_net_client_connection_t *connection)
+{
+       if(connection->sock) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close TCP Connection %s",connection->id);
+               apt_pollset_remove(task->pollset,&connection->sock_pfd);
+               apr_socket_close(connection->sock);
+               connection->sock = NULL;
+       }
+       return TRUE;
+}
+
+/** Close and destroy connection */
+APT_DECLARE(apt_bool_t) apt_net_client_disconnect(apt_net_client_task_t *task, apt_net_client_connection_t *connection)
+{
+       apt_net_client_connection_close(task,connection);
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy TCP Connection %s",connection->id);
+       apr_pool_destroy(connection->pool);
+       return TRUE;
+}
+
+/** Create the pollset */
+static apt_bool_t apt_net_client_task_pollset_create(apt_net_client_task_t *task)
+{
+       /* create pollset */
+       task->pollset = apt_pollset_create((apr_uint32_t)task->max_connection_count, task->pool);
+       if(!task->pollset) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Pollset");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+/** Destroy the pollset */
+static void apt_net_client_task_pollset_destroy(apt_net_client_task_t *task)
+{
+       if(task->pollset) {
+               apt_pollset_destroy(task->pollset);
+               task->pollset = NULL;
+       }
+}
+
+static apt_bool_t apt_net_client_task_process(apt_net_client_task_t *task)
+{
+       apt_bool_t status = TRUE;
+       apt_bool_t running = TRUE;
+       apt_task_msg_t *msg;
+
+       do {
+               apr_thread_mutex_lock(task->guard);
+               msg = apt_cyclic_queue_pop(task->msg_queue);
+               apr_thread_mutex_unlock(task->guard);
+               if(msg) {
+                       status = apt_task_msg_process(task->base,msg);
+               }
+               else {
+                       running = FALSE;
+               }
+       }
+       while(running == TRUE);
+       return status;
+}
+
+static apt_bool_t apt_net_client_task_run(apt_task_t *base)
+{
+       apt_net_client_task_t *task = apt_task_object_get(base);
+       apt_bool_t running = TRUE;
+       apr_status_t status;
+       apr_int32_t num;
+       const apr_pollfd_t *ret_pfd;
+       int i;
+
+       if(!task) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Start Network Client Task");
+               return FALSE;
+       }
+
+       if(apt_net_client_task_pollset_create(task) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Pollset");
+               return FALSE;
+       }
+
+       while(running) {
+               status = apt_pollset_poll(task->pollset, -1, &num, &ret_pfd);
+               if(status != APR_SUCCESS) {
+                       continue;
+               }
+               for(i = 0; i < num; i++) {
+                       if(apt_pollset_is_wakeup(task->pollset,&ret_pfd[i])) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process Control Message");
+                               if(apt_net_client_task_process(task) == FALSE) {
+                                       running = FALSE;
+                                       break;
+                               }
+                               continue;
+                       }
+       
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process Message");
+                       task->client_vtable->on_receive(task,ret_pfd[i].client_data);
+               }
+       }
+
+       apt_net_client_task_pollset_destroy(task);
+
+       apt_task_child_terminate(task->base);
+       return TRUE;
+}
+
+static apt_bool_t apt_net_client_task_msg_signal(apt_task_t *base, apt_task_msg_t *msg)
+{
+       apt_bool_t status;
+       apt_net_client_task_t *task = apt_task_object_get(base);
+       apr_thread_mutex_lock(task->guard);
+       status = apt_cyclic_queue_push(task->msg_queue,msg);
+       apr_thread_mutex_unlock(task->guard);
+       if(apt_pollset_wakeup(task->pollset) != TRUE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Signal Control Message");
+               status = FALSE;
+       }
+       return status;
+}
diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_net_server_task.c b/libs/unimrcp/libs/apr-toolkit/src/apt_net_server_task.c
new file mode 100644 (file)
index 0000000..77c48b9
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apt_net_server_task.h"
+#include "apt_task.h"
+#include "apt_pool.h"
+#include "apt_pollset.h"
+#include "apt_cyclic_queue.h"
+#include "apt_log.h"
+
+
+/** Network server task */
+struct apt_net_server_task_t {
+       apr_pool_t                    *pool;
+       apt_task_t                    *base;
+       void                          *obj;
+
+       apr_size_t                     max_connection_count;
+
+       apr_thread_mutex_t            *guard;
+       apt_cyclic_queue_t            *msg_queue;
+       apt_pollset_t                 *pollset;
+
+       /* Listening socket descriptor */
+       apr_sockaddr_t                *sockaddr;
+       apr_socket_t                  *listen_sock;
+       apr_pollfd_t                   listen_sock_pfd;
+
+       const apt_net_server_vtable_t *server_vtable;
+};
+
+static apt_bool_t apt_net_server_task_msg_signal(apt_task_t *task, apt_task_msg_t *msg);
+static apt_bool_t apt_net_server_task_run(apt_task_t *task);
+static apt_bool_t apt_net_server_task_on_destroy(apt_task_t *task);
+
+/** Create connection task */
+APT_DECLARE(apt_net_server_task_t*) apt_net_server_task_create(
+                                                                               const char *listen_ip,
+                                                                               apr_port_t listen_port,
+                                                                               apr_size_t max_connection_count,
+                                                                               void *obj,
+                                                                               const apt_net_server_vtable_t *server_vtable,
+                                                                               apt_task_msg_pool_t *msg_pool,
+                                                                               apr_pool_t *pool)
+{
+       apt_task_vtable_t *vtable;
+       apt_net_server_task_t *task;
+       
+       task = apr_palloc(pool,sizeof(apt_net_server_task_t));
+       task->pool = pool;
+       task->obj = obj;
+       task->sockaddr = NULL;
+       task->listen_sock = NULL;
+       task->pollset = NULL;
+       task->max_connection_count = max_connection_count;
+
+       apr_sockaddr_info_get(&task->sockaddr,listen_ip,APR_INET,listen_port,0,task->pool);
+       if(!task->sockaddr) {
+               return NULL;
+       }
+
+       if(!server_vtable || !server_vtable->on_connect || 
+               !server_vtable->on_disconnect || !server_vtable->on_receive) {
+               return NULL;
+       }
+       task->server_vtable = server_vtable;
+
+       task->base = apt_task_create(task,msg_pool,pool);
+       if(!task->base) {
+               return NULL;
+       }
+
+       vtable = apt_task_vtable_get(task->base);
+       if(vtable) {
+               vtable->run = apt_net_server_task_run;
+               vtable->destroy = apt_net_server_task_on_destroy;
+               vtable->signal_msg = apt_net_server_task_msg_signal;
+       }
+
+       task->msg_queue = apt_cyclic_queue_create(CYCLIC_QUEUE_DEFAULT_SIZE);
+       apr_thread_mutex_create(&task->guard,APR_THREAD_MUTEX_UNNESTED,pool);
+       return task;
+}
+
+/** Virtual destroy handler */
+static apt_bool_t apt_net_server_task_on_destroy(apt_task_t *base)
+{
+       apt_net_server_task_t *task = apt_task_object_get(base);
+       if(task->guard) {
+               apr_thread_mutex_destroy(task->guard);
+               task->guard = NULL;
+       }
+       if(task->msg_queue) {
+               apt_cyclic_queue_destroy(task->msg_queue);
+               task->msg_queue = NULL;
+       }
+       return TRUE;
+}
+
+/** Destroy connection task. */
+APT_DECLARE(apt_bool_t) apt_net_server_task_destroy(apt_net_server_task_t *task)
+{
+       return apt_task_destroy(task->base);
+}
+
+/** Start connection task. */
+APT_DECLARE(apt_bool_t) apt_net_server_task_start(apt_net_server_task_t *task)
+{
+       return apt_task_start(task->base);
+}
+
+/** Terminate connection task. */
+APT_DECLARE(apt_bool_t) apt_net_server_task_terminate(apt_net_server_task_t *task)
+{
+       return apt_task_terminate(task->base,TRUE);
+}
+
+/** Get task */
+APT_DECLARE(apt_task_t*) apt_net_server_task_base_get(apt_net_server_task_t *task)
+{
+       return task->base;
+}
+
+/** Get task vtable */
+APT_DECLARE(apt_task_vtable_t*) apt_net_server_task_vtable_get(apt_net_server_task_t *task)
+{
+       return apt_task_vtable_get(task->base);
+}
+
+/** Get external object */
+APT_DECLARE(void*) apt_net_server_task_object_get(apt_net_server_task_t *task)
+{
+       return task->obj;
+}
+
+
+/** Create listening socket and add to pollset */
+static apt_bool_t apt_net_server_task_listen_socket_create(apt_net_server_task_t *task)
+{
+       apr_status_t status;
+       if(!task->sockaddr) {
+               return FALSE;
+       }
+
+       /* create listening socket */
+       status = apr_socket_create(&task->listen_sock, task->sockaddr->family, SOCK_STREAM, APR_PROTO_TCP, task->pool);
+       if(status != APR_SUCCESS) {
+               return FALSE;
+       }
+
+       apr_socket_opt_set(task->listen_sock, APR_SO_NONBLOCK, 0);
+       apr_socket_timeout_set(task->listen_sock, -1);
+       apr_socket_opt_set(task->listen_sock, APR_SO_REUSEADDR, 1);
+
+       status = apr_socket_bind(task->listen_sock, task->sockaddr);
+       if(status != APR_SUCCESS) {
+               apr_socket_close(task->listen_sock);
+               task->listen_sock = NULL;
+               return FALSE;
+       }
+       status = apr_socket_listen(task->listen_sock, SOMAXCONN);
+       if(status != APR_SUCCESS) {
+               apr_socket_close(task->listen_sock);
+               task->listen_sock = NULL;
+               return FALSE;
+       }
+
+       memset(&task->listen_sock_pfd,0,sizeof(apr_pollfd_t));
+       task->listen_sock_pfd.desc_type = APR_POLL_SOCKET;
+       task->listen_sock_pfd.reqevents = APR_POLLIN;
+       task->listen_sock_pfd.desc.s = task->listen_sock;
+       task->listen_sock_pfd.client_data = task->listen_sock;
+       if(apt_pollset_add(task->pollset, &task->listen_sock_pfd) != TRUE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Add Listen Socket to Pollset");
+               apr_socket_close(task->listen_sock);
+               task->listen_sock = NULL;
+       }
+
+       return TRUE;
+}
+
+/** Remove from pollset and destroy listening socket */
+static void apt_net_server_task_listen_socket_destroy(apt_net_server_task_t *task)
+{
+       apt_pollset_remove(task->pollset,&task->listen_sock_pfd);
+
+       if(task->listen_sock) {
+               apr_socket_close(task->listen_sock);
+               task->listen_sock = NULL;
+       }
+}
+
+/** Create the pollset */
+static apt_bool_t apt_net_server_task_pollset_create(apt_net_server_task_t *task)
+{
+       /* create pollset */
+       task->pollset = apt_pollset_create((apr_uint32_t)task->max_connection_count + 1, task->pool);
+       if(!task->pollset) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Pollset");
+               return FALSE;
+       }
+
+       /* create listening socket */
+       if(apt_net_server_task_listen_socket_create(task) != TRUE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Listen Socket");
+       }
+
+       return TRUE;
+}
+
+/** Destroy the pollset */
+static void apt_net_server_task_pollset_destroy(apt_net_server_task_t *task)
+{
+       apt_net_server_task_listen_socket_destroy(task);
+       if(task->pollset) {
+               apt_pollset_destroy(task->pollset);
+               task->pollset = NULL;
+       }
+}
+
+static apt_bool_t apt_net_server_task_process(apt_net_server_task_t *task)
+{
+       apt_bool_t status = TRUE;
+       apt_bool_t running = TRUE;
+       apt_task_msg_t *msg;
+
+       do {
+               apr_thread_mutex_lock(task->guard);
+               msg = apt_cyclic_queue_pop(task->msg_queue);
+               apr_thread_mutex_unlock(task->guard);
+               if(msg) {
+                       status = apt_task_msg_process(task->base,msg);
+               }
+               else {
+                       running = FALSE;
+               }
+       }
+       while(running == TRUE);
+       return status;
+}
+
+static apt_bool_t apt_net_server_task_accept(apt_net_server_task_t *task)
+{
+       char *local_ip = NULL;
+       char *remote_ip = NULL;
+       apr_sockaddr_t *l_sockaddr = NULL;
+       apr_sockaddr_t *r_sockaddr = NULL;
+       apt_net_server_connection_t *connection;
+       apr_pool_t *pool = apt_pool_create();
+       if(!pool) {
+               return FALSE;
+       }
+       
+       connection = apr_palloc(pool,sizeof(apt_net_server_connection_t));
+       connection->pool = pool;
+       connection->obj = NULL;
+       connection->sock = NULL;
+       connection->client_ip = NULL;
+
+       if(apr_socket_accept(&connection->sock,task->listen_sock,connection->pool) != APR_SUCCESS) {
+               apr_pool_destroy(pool);
+               return FALSE;
+       }
+
+       if(apr_socket_addr_get(&l_sockaddr,APR_LOCAL,connection->sock) != APR_SUCCESS ||
+               apr_socket_addr_get(&r_sockaddr,APR_REMOTE,connection->sock) != APR_SUCCESS) {
+               apr_pool_destroy(pool);
+               return FALSE;
+       }
+
+       apr_sockaddr_ip_get(&local_ip,l_sockaddr);
+       apr_sockaddr_ip_get(&remote_ip,r_sockaddr);
+       connection->client_ip = remote_ip;
+       connection->id = apr_psprintf(pool,"%s:%hu <-> %s:%hu",
+               local_ip,l_sockaddr->port,
+               remote_ip,r_sockaddr->port);
+
+       memset(&connection->sock_pfd,0,sizeof(apr_pollfd_t));
+       connection->sock_pfd.desc_type = APR_POLL_SOCKET;
+       connection->sock_pfd.reqevents = APR_POLLIN;
+       connection->sock_pfd.desc.s = connection->sock;
+       connection->sock_pfd.client_data = connection;
+       if(apt_pollset_add(task->pollset,&connection->sock_pfd) != TRUE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Add to Pollset");
+               apr_socket_close(connection->sock);
+               apr_pool_destroy(pool);
+               return FALSE;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Accepted TCP Connection %s",connection->id);
+       task->server_vtable->on_connect(task,connection);
+       return TRUE;
+}
+
+static apt_bool_t apt_net_server_task_run(apt_task_t *base)
+{
+       apt_net_server_task_t *task = apt_task_object_get(base);
+       apt_bool_t running = TRUE;
+       apr_status_t status;
+       apr_int32_t num;
+       const apr_pollfd_t *ret_pfd;
+       int i;
+
+       if(!task) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Start Network Server Task");
+               return FALSE;
+       }
+
+       if(apt_net_server_task_pollset_create(task) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Pollset");
+               return FALSE;
+       }
+
+       while(running) {
+               status = apt_pollset_poll(task->pollset, -1, &num, &ret_pfd);
+               if(status != APR_SUCCESS) {
+                       continue;
+               }
+               for(i = 0; i < num; i++) {
+                       if(ret_pfd[i].desc.s == task->listen_sock) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Accept Connection");
+                               apt_net_server_task_accept(task);
+                               continue;
+                       }
+                       if(apt_pollset_is_wakeup(task->pollset,&ret_pfd[i])) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process Control Message");
+                               if(apt_net_server_task_process(task) == FALSE) {
+                                       running = FALSE;
+                                       break;
+                               }
+                               continue;
+                       }
+       
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process Message");
+                       task->server_vtable->on_receive(task,ret_pfd[i].client_data);
+               }
+       }
+
+       apt_net_server_task_pollset_destroy(task);
+
+       apt_task_child_terminate(task->base);
+       return TRUE;
+}
+
+static apt_bool_t apt_net_server_task_msg_signal(apt_task_t *base, apt_task_msg_t *msg)
+{
+       apt_bool_t status;
+       apt_net_server_task_t *task = apt_task_object_get(base);
+       apr_thread_mutex_lock(task->guard);
+       status = apt_cyclic_queue_push(task->msg_queue,msg);
+       apr_thread_mutex_unlock(task->guard);
+       if(apt_pollset_wakeup(task->pollset) != TRUE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Signal Control Message");
+               status = FALSE;
+       }
+       return status;
+}
+
+
+/** Close connection */
+APT_DECLARE(apt_bool_t) apt_net_server_connection_close(apt_net_server_task_t *task, apt_net_server_connection_t *connection)
+{
+       if(connection->sock) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close TCP Connection %s",connection->id);
+               apt_pollset_remove(task->pollset,&connection->sock_pfd);
+               apr_socket_close(connection->sock);
+               connection->sock = NULL;
+               task->server_vtable->on_disconnect(task,connection);
+       }
+       return TRUE;
+}
+
+/** Destroy connection */
+APT_DECLARE(void) apt_net_server_connection_destroy(apt_net_server_connection_t *connection)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy TCP Connection %s",connection->id);
+       apr_pool_destroy(connection->pool);
+}
diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_obj_list.c b/libs/unimrcp/libs/apr-toolkit/src/apt_obj_list.c
new file mode 100644 (file)
index 0000000..a1d320a
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef WIN32
+#pragma warning(disable: 4127)
+#endif
+#include <apr_ring.h>
+#include "apt_obj_list.h"
+
+struct apt_list_elem_t {
+       APR_RING_ENTRY(apt_list_elem_t) link;
+       void                           *obj;
+};
+
+struct apt_obj_list_t {
+       APR_RING_HEAD(apt_list_head_t, apt_list_elem_t) head;
+       apr_pool_t                                     *pool;
+};
+
+
+
+APT_DECLARE(apt_obj_list_t*) apt_list_create(apr_pool_t *pool)
+{
+       apt_obj_list_t *list = apr_palloc(pool, sizeof(apt_obj_list_t));
+       list->pool = pool;
+       APR_RING_INIT(&list->head, apt_list_elem_t, link);
+       return list;
+}
+
+APT_DECLARE(void) apt_list_destroy(apt_obj_list_t *list)
+{
+       /* nothing to do, the list is allocated from the pool */
+}
+
+APT_DECLARE(apt_list_elem_t*) apt_list_push_back(apt_obj_list_t *list, void *obj, apr_pool_t *pool)
+{
+       apt_list_elem_t *elem = apr_palloc(pool,sizeof(apt_list_elem_t));
+       elem->obj = obj;
+
+       APR_RING_INSERT_TAIL(&list->head,elem,apt_list_elem_t,link);
+       return elem;
+}
+
+APT_DECLARE(void*) apt_list_pop_front(apt_obj_list_t *list)
+{
+       apt_list_elem_t *elem;
+       if(APR_RING_EMPTY(&list->head,apt_list_elem_t,link)) {
+               return NULL;
+       }
+       elem = APR_RING_FIRST(&list->head);
+       APR_RING_REMOVE(elem,link);
+       return elem->obj;
+}
+
+APT_DECLARE(void*) apt_list_head(apt_obj_list_t *list)
+{
+       apt_list_elem_t *elem;
+       if(APR_RING_EMPTY(&list->head,apt_list_elem_t,link)) {
+               return NULL;
+       }
+       elem = APR_RING_FIRST(&list->head);
+       return elem->obj;
+}
+
+APT_DECLARE(void*) apt_obj_list_tail(apt_obj_list_t *list)
+{
+       apt_list_elem_t *elem;
+       if(APR_RING_EMPTY(&list->head,apt_list_elem_t,link)) {
+               return NULL;
+       }
+       elem = APR_RING_LAST(&list->head);
+       return elem->obj;
+}
+
+APT_DECLARE(apt_list_elem_t*) apt_list_first_elem_get(apt_obj_list_t *list)
+{
+       if(APR_RING_EMPTY(&list->head,apt_list_elem_t,link)) {
+               return NULL;
+       }
+       return APR_RING_FIRST(&list->head);
+}
+
+APT_DECLARE(apt_list_elem_t*) apt_list_last_elem_get(apt_obj_list_t *list)
+{
+       if(APR_RING_EMPTY(&list->head,apt_list_elem_t,link)) {
+               return NULL;
+       }
+       return APR_RING_LAST(&list->head);
+}
+
+APT_DECLARE(apt_list_elem_t*) apt_list_next_elem_get(apt_obj_list_t *list, apt_list_elem_t *elem)
+{
+       apt_list_elem_t *next_elem = APR_RING_NEXT(elem,link);
+       if(next_elem == APR_RING_SENTINEL(&list->head,apt_list_elem_t,link)) {
+               next_elem = NULL;
+       }
+       return next_elem;
+}
+
+APT_DECLARE(apt_list_elem_t*) apt_list_prev_elem_get(apt_obj_list_t *list, apt_list_elem_t *elem)
+{
+       apt_list_elem_t *prev_elem = APR_RING_PREV(elem,link);
+       if(prev_elem == APR_RING_SENTINEL(&list->head,apt_list_elem_t,link)) {
+               prev_elem = NULL;
+       }
+       return prev_elem;
+}
+
+APT_DECLARE(apt_list_elem_t*) apt_list_elem_insert(apt_obj_list_t *list, apt_list_elem_t *elem, void *obj, apr_pool_t *pool)
+{
+       apt_list_elem_t *new_elem = apr_palloc(pool,sizeof(apt_list_elem_t));
+       new_elem->obj = obj;
+       APR_RING_INSERT_BEFORE(elem,new_elem,link);
+       return new_elem;
+}
+
+APT_DECLARE(apt_list_elem_t*) apt_list_elem_remove(apt_obj_list_t *list, apt_list_elem_t *elem)
+{
+       apt_list_elem_t *next_elem = APR_RING_NEXT(elem,link);
+       APR_RING_REMOVE(elem,link);
+       if(next_elem == APR_RING_SENTINEL(&list->head,apt_list_elem_t,link)) {
+               next_elem = NULL;
+       }
+       return next_elem;
+}
+
+APT_DECLARE(apt_bool_t) apt_list_is_empty(apt_obj_list_t *list)
+{
+       if(APR_RING_EMPTY(&list->head,apt_list_elem_t,link)) {
+               return TRUE;
+       }
+       return FALSE;
+}
+
+APT_DECLARE(void*) apt_list_elem_object_get(apt_list_elem_t *elem)
+{
+       return elem->obj;
+}
diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_pair.c b/libs/unimrcp/libs/apr-toolkit/src/apt_pair.c
new file mode 100644 (file)
index 0000000..816eea2
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apt_pair.h"
+
+/** Create array of name-value pairs */
+APT_DECLARE(apt_pair_arr_t*) apt_pair_array_create(apr_size_t initial_size, apr_pool_t *pool)
+{
+       return apr_array_make(pool,(int)initial_size,sizeof(apt_pair_t));
+}
+
+/** Copy array of name-value pairs */
+APT_DECLARE(apt_pair_arr_t*) apt_pair_array_copy(const apt_pair_arr_t *src_arr, apr_pool_t *pool)
+{
+       int i;
+       const apt_pair_t *src_pair;
+       apt_pair_t *pair;
+       apt_pair_arr_t *arr;
+       if(!src_arr) {
+               return NULL;
+       }
+       arr = apr_array_copy(pool,src_arr);
+       for(i=0; i<arr->nelts; i++) {
+               pair = (apt_pair_t*)arr->elts + i;
+               src_pair = (const apt_pair_t*)src_arr->elts + i;
+               apt_pair_copy(pair,src_pair,pool);
+       }
+       return arr;
+}
+
+
+/** Append name-value pair */
+APT_DECLARE(apt_bool_t) apt_pair_array_append(apt_pair_arr_t *arr, const apt_str_t *name, const apt_str_t *value, apr_pool_t *pool)
+{
+       apt_pair_t *pair = apr_array_push(arr);
+       apt_pair_init(pair);
+       if(name) {
+               apt_string_copy(&pair->name,name,pool);
+       }
+       if(value) {
+               apt_string_copy(&pair->value,value,pool);
+       }
+       return TRUE;
+}
+
+/** Find name-value pair by name */
+APT_DECLARE(const apt_pair_t*) apt_pair_array_find(const apt_pair_arr_t *arr, const apt_str_t *name)
+{
+       int i;
+       apt_pair_t *pair;
+       for(i=0; i<arr->nelts; i++) {
+               pair = (apt_pair_t*)arr->elts + i;
+               if(apt_string_compare(&pair->name,name) == TRUE) {
+                       return pair;
+               }
+       }
+       return NULL;
+}
+
+/** Get size of pair array */
+APT_DECLARE(int) apt_pair_array_size_get(const apt_pair_arr_t *arr)
+{
+       return arr->nelts;
+}
+
+/** Get name-value pair by id */
+APT_DECLARE(const apt_pair_t*) apt_pair_array_get(const apt_pair_arr_t *arr, int id)
+{
+       if(id < arr->nelts) {
+               return (apt_pair_t*)arr->elts + id;
+       }
+       return NULL;
+}
diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_pollset.c b/libs/unimrcp/libs/apr-toolkit/src/apt_pollset.c
new file mode 100644 (file)
index 0000000..87db7f8
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_poll.h>
+#include "apt_pollset.h"
+#include "apt_log.h"
+
+struct apt_pollset_t {
+       /** APR pollset */
+       apr_pollset_t *base;
+#ifdef WIN32
+       /** Socket descriptors used for wakeup */
+       apr_socket_t  *wakeup_pipe[2];
+#else
+       /** Pipe descriptors used for wakeup */
+       apr_file_t    *wakeup_pipe[2];
+#endif
+       /** Builtin wakeup poll descriptor */
+       apr_pollfd_t   wakeup_pfd;
+
+       /** Pool to allocate memory from */
+       apr_pool_t    *pool;
+};
+
+static apt_bool_t apt_wakeup_pipe_create(apt_pollset_t *pollset);
+static apt_bool_t apt_wakeup_pipe_destroy(apt_pollset_t *pollset);
+
+/** Create interruptable pollset on top of APR pollset */
+APT_DECLARE(apt_pollset_t*) apt_pollset_create(apr_uint32_t size, apr_pool_t *pool)
+{
+       apt_pollset_t *pollset = apr_palloc(pool,sizeof(apt_pollset_t));
+       pollset->pool = pool;
+       memset(&pollset->wakeup_pfd,0,sizeof(pollset->wakeup_pfd));
+       
+       /* create pollset with max number of descriptors size+1, 
+       where +1 is builtin wakeup descriptor */
+       if(apr_pollset_create(&pollset->base,size+1,pool,0) != APR_SUCCESS) {
+               return NULL;
+       }
+
+       /* create wakeup pipe */
+       if(apt_wakeup_pipe_create(pollset) != TRUE) {
+               apr_pollset_destroy(pollset->base);
+               return NULL;
+       }
+
+       /* add wakeup pipe to pollset */
+       if(apr_pollset_add(pollset->base,&pollset->wakeup_pfd) != APR_SUCCESS) {
+               apt_wakeup_pipe_destroy(pollset);
+               apr_pollset_destroy(pollset->base);
+               return NULL;
+       }
+       return pollset;
+}
+
+/** Destroy pollset */
+APT_DECLARE(apt_bool_t) apt_pollset_destroy(apt_pollset_t *pollset)
+{
+       /* remove wakeup pipe from pollset */
+       apr_pollset_remove(pollset->base,&pollset->wakeup_pfd);
+       /* destroy wakeup pipe */
+       apt_wakeup_pipe_destroy(pollset);
+       /* destroy pollset */
+       apr_pollset_destroy(pollset->base);
+       return TRUE;
+}
+
+/** Add pollset descriptor to a pollset */
+APT_DECLARE(apt_bool_t) apt_pollset_add(apt_pollset_t *pollset, const apr_pollfd_t *descriptor)
+{
+       return (apr_pollset_add(pollset->base,descriptor) == APR_SUCCESS) ? TRUE : FALSE;
+}
+
+/** Remove pollset descriptor from a pollset */
+APT_DECLARE(apt_bool_t) apt_pollset_remove(apt_pollset_t *pollset, const apr_pollfd_t *descriptor)
+{
+       return (apr_pollset_remove(pollset->base,descriptor) == APR_SUCCESS) ? TRUE : FALSE;
+}
+
+/** Block for activity on the descriptor(s) in a pollset */
+APT_DECLARE(apr_status_t) apt_pollset_poll(
+                                                               apt_pollset_t *pollset,
+                                                               apr_interval_time_t timeout,
+                                                               apr_int32_t *num,
+                                                               const apr_pollfd_t **descriptors)
+{
+       return apr_pollset_poll(pollset->base,timeout,num,descriptors);
+}
+
+/** Interrupt the blocked poll call */
+APT_DECLARE(apt_bool_t) apt_pollset_wakeup(apt_pollset_t *pollset)
+{
+       apt_bool_t status = TRUE;
+#ifdef WIN32
+       char tmp = 0;
+       apr_size_t len = sizeof(tmp);
+       if(apr_socket_send(pollset->wakeup_pipe[1],&tmp,&len) != APR_SUCCESS) {
+               status = FALSE;
+       }
+#else
+       if(apr_file_putc(1, pollset->wakeup_pipe[1]) != APR_SUCCESS) {
+               status = FALSE;
+       }
+#endif
+       return status;
+}
+
+/** Match against builtin wake up descriptor in a pollset */
+APT_DECLARE(apt_bool_t) apt_pollset_is_wakeup(apt_pollset_t *pollset, const apr_pollfd_t *descriptor)
+{
+       apt_bool_t status = FALSE;
+#ifdef WIN32
+       if(descriptor->desc.s == pollset->wakeup_pipe[0]) {
+               char rb[512];
+               apr_size_t nr = sizeof(rb);
+
+               /* simply read out from the input side of the pipe all the data. */
+               while(apr_socket_recv(pollset->wakeup_pipe[0], rb, &nr) == APR_SUCCESS) {
+                       if(nr != sizeof(rb)) {
+                               break;
+                       }
+               }
+               status = TRUE;
+       }
+#else
+       if(descriptor->desc.f == pollset->wakeup_pipe[0]) {
+               char rb[512];
+               apr_size_t nr = sizeof(rb);
+
+               /* simply read out from the input side of the pipe all the data. */
+               while(apr_file_read(pollset->wakeup_pipe[0], rb, &nr) == APR_SUCCESS) {
+                       if(nr != sizeof(rb)) {
+                               break;
+                       }
+               }
+               status = TRUE;
+       }
+#endif
+       return status;
+}
+
+#ifdef WIN32
+static apr_status_t socket_pipe_create(apr_socket_t **rd, apr_socket_t **wr, apr_pool_t *pool)
+{
+       static int id = 0;
+
+       apr_socket_t *ls = NULL;
+       apr_sockaddr_t *pa = NULL;
+       apr_sockaddr_t *ca = NULL;
+       apr_size_t nrd;
+       int uid[2];
+       int iid[2];
+
+       /* Create the unique socket identifier
+        * so that we know the connection originated
+        * from us.
+        */
+       uid[0] = getpid();
+       uid[1] = id++;
+       if(apr_socket_create(&ls, AF_INET, SOCK_STREAM, APR_PROTO_TCP, pool) != APR_SUCCESS) {
+               return apr_get_netos_error();
+       }
+       apr_socket_opt_set(ls, APR_SO_REUSEADDR, 1);
+
+       if(apr_sockaddr_info_get(&pa,"127.0.0.1",APR_INET,0,0,pool) != APR_SUCCESS) {
+               apr_socket_close(ls);
+               return apr_get_netos_error();
+       }
+
+       if(apr_socket_bind(ls, pa) != APR_SUCCESS) {
+               apr_socket_close(ls);
+               return apr_get_netos_error();
+       }
+       
+       if(apr_socket_addr_get(&ca,APR_LOCAL,ls) != APR_SUCCESS) {
+               apr_socket_close(ls);
+               return apr_get_netos_error();
+       }
+
+       if(apr_socket_listen(ls,1) != APR_SUCCESS) {
+               apr_socket_close(ls);
+               return apr_get_netos_error();
+       }
+
+       if(apr_socket_create(wr, AF_INET, SOCK_STREAM, APR_PROTO_TCP, pool) != APR_SUCCESS) {
+               apr_socket_close(ls);
+               return apr_get_netos_error();
+       }
+       apr_socket_opt_set(*wr, APR_SO_REUSEADDR, 1);
+
+       if(apr_socket_connect(*wr, ca) != APR_SUCCESS) {
+               apr_socket_close(ls);
+               apr_socket_close(*wr);
+               return apr_get_netos_error();
+       }
+       nrd = sizeof(uid);
+       if(apr_socket_send(*wr, (char *)uid, &nrd) != APR_SUCCESS) {
+               apr_socket_close(ls);
+               apr_socket_close(*wr);
+               return apr_get_netos_error();
+       }
+       
+       apr_socket_opt_set(ls, APR_SO_NONBLOCK, 0);
+       /* Listening socket is blocking by now. The accept should 
+        * return immediatelly because we connected already.
+        */
+       if(apr_socket_accept(rd, ls, pool) != APR_SUCCESS) {
+               apr_socket_close(ls);
+               apr_socket_close(*wr);
+               return apr_get_netos_error();
+       }
+
+       /* Put read side of the pipe to the blocking mode */
+       apr_socket_opt_set(*rd, APR_SO_NONBLOCK, 0);
+
+       for (;;) {
+               /* Verify the connection by reading the sent identification */
+               nrd = sizeof(iid);
+               if(apr_socket_recv(*rd, (char *)iid, &nrd) != APR_SUCCESS) {
+                       apr_socket_close(ls);
+                       apr_socket_close(*wr);
+                       apr_socket_close(*rd);
+                       return apr_get_netos_error();
+               }
+               if(nrd == sizeof(iid)) {
+                       if(memcmp(uid, iid, sizeof(uid)) == 0) {
+                               /* Wow, we recived what we sent */
+                               break;
+                       }
+               }
+       }
+
+       /* We don't need the listening socket any more */
+       apr_socket_close(ls);
+       return APR_SUCCESS;
+}
+
+/** Create a dummy wakeup pipe for interrupting the poller */
+static apt_bool_t apt_wakeup_pipe_create(apt_pollset_t *pollset)
+{
+       apr_socket_t *rd = NULL;
+       apr_socket_t *wr = NULL;
+       apr_status_t rv;
+       rv = socket_pipe_create(&rd,&wr,pollset->pool);
+       if(rv != APR_SUCCESS) {
+               char err_str[256];
+               apr_strerror(rv,err_str,sizeof(err_str));
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Wakeup Pipe: %s",err_str);
+               return FALSE;
+       }
+       pollset->wakeup_pfd.reqevents = APR_POLLIN;
+       pollset->wakeup_pfd.desc_type = APR_POLL_SOCKET;
+       pollset->wakeup_pfd.desc.s = rd;
+       
+       pollset->wakeup_pipe[0] = rd;
+       pollset->wakeup_pipe[1] = wr;
+       return TRUE;
+}
+
+/** Destroy wakeup pipe */
+static apt_bool_t apt_wakeup_pipe_destroy(apt_pollset_t *pollset)
+{
+       /* Close both sides of the wakeup pipe */
+       if(pollset->wakeup_pipe[0]) {
+               apr_socket_close(pollset->wakeup_pipe[0]);
+               pollset->wakeup_pipe[0] = NULL;
+       }
+       if(pollset->wakeup_pipe[1]) {
+               apr_socket_close(pollset->wakeup_pipe[1]);
+               pollset->wakeup_pipe[1] = NULL;
+       }
+       return TRUE;
+}
+
+#else 
+
+/** Create a dummy wakeup pipe for interrupting the poller */
+static apt_bool_t apt_wakeup_pipe_create(apt_pollset_t *pollset)
+{
+       apr_file_t *file_in = NULL;
+       apr_file_t *file_out = NULL;
+
+       if(apr_file_pipe_create(&file_in,&file_out,pollset->pool) != APR_SUCCESS) {
+               return FALSE;
+       }
+       pollset->wakeup_pfd.reqevents = APR_POLLIN;
+       pollset->wakeup_pfd.desc_type = APR_POLL_FILE;
+       pollset->wakeup_pfd.desc.f = file_in;
+       
+       pollset->wakeup_pipe[0] = file_in;
+       pollset->wakeup_pipe[1] = file_out;
+       return TRUE;
+}
+
+/** Destroy wakeup pipe */
+static apt_bool_t apt_wakeup_pipe_destroy(apt_pollset_t *pollset)
+{
+       /* Close both sides of the wakeup pipe */
+       if(pollset->wakeup_pipe[0]) {
+               apr_file_close(pollset->wakeup_pipe[0]);
+               pollset->wakeup_pipe[0] = NULL;
+       }
+       if(pollset->wakeup_pipe[1]) {
+               apr_file_close(pollset->wakeup_pipe[1]);
+               pollset->wakeup_pipe[1] = NULL;
+       }
+       return TRUE;
+}
+
+#endif
diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_pool.c b/libs/unimrcp/libs/apr-toolkit/src/apt_pool.c
new file mode 100644 (file)
index 0000000..9de0e3f
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apt_pool.h"
+
+//#define OWN_ALLOCATOR_PER_POOL
+
+APT_DECLARE(apr_pool_t*) apt_pool_create()
+{
+       apr_pool_t *pool = NULL;
+
+#ifdef OWN_ALLOCATOR_PER_POOL
+       apr_allocator_t *allocator = NULL;
+       apr_thread_mutex_t *mutex = NULL;
+
+       if(apr_allocator_create(&allocator) == APR_SUCCESS) {
+               if(apr_pool_create_ex(&pool,NULL,NULL,allocator) == APR_SUCCESS) {
+                       apr_allocator_owner_set(allocator,pool);
+                       apr_thread_mutex_create(&mutex,APR_THREAD_MUTEX_NESTED,pool);
+                       apr_allocator_mutex_set(allocator,mutex);
+               }
+       }
+#else
+       apr_pool_create(&pool,NULL);
+#endif
+       return pool;
+}
+
+APT_DECLARE(apr_pool_t*) apt_subpool_create(apr_pool_t *parent)
+{
+       apr_pool_t *pool = NULL;
+       apr_pool_create(&pool,parent);
+       return pool;
+}
diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_string_table.c b/libs/unimrcp/libs/apr-toolkit/src/apt_string_table.c
new file mode 100644 (file)
index 0000000..cc0c6be
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ctype.h>
+#include "apt_string_table.h"
+
+/* Get the string by a given id. */
+APT_DECLARE(const apt_str_t*) apt_string_table_str_get(const apt_str_table_item_t table[], apr_size_t size, apr_size_t id)
+{
+       if(id < size) {
+               return &table[id].value;
+       }
+       return NULL;
+}
+
+/* Find the id associated with a given string from the table */
+APT_DECLARE(apr_size_t) apt_string_table_id_find(const apt_str_table_item_t table[], apr_size_t size, const apt_str_t *value)
+{
+       /* Key character is stored within each apt_string_table_item.
+       At first, key characters must be matched in a loop crossing the items.
+       Then whole strings should be compared only for the matched item.
+       Key characters should be automatically generated once for a given string table. */
+
+       apr_size_t i;
+       const apt_str_table_item_t *item;
+       for(i=0; i<size; i++) {
+               item = &table[i];
+               if(item->value.length != value->length) {
+                       /* lengths of th strings differ, just contninue */
+                       continue;
+               }
+               /* check whether key is available */
+               if(item->key < value->length) {
+                       /* check whether values are matched by key (using no case compare) */
+                       if(value->length == item->value.length && 
+                               tolower(item->value.buf[item->key]) == tolower(value->buf[item->key])) {
+                               /* whole strings must be compared to ensure, should be done only once for each lookup */
+                               if(apt_string_compare(&item->value,value) == TRUE) {
+                                       return i;
+                               }
+                       }
+               }
+               else {
+                       /* no key available, just compare whole strings */
+                       if(apt_string_compare(&item->value,value) == TRUE) {
+                               return i;
+                       }
+               }
+       }
+
+       /* no match found, return invalid id */
+       return size;
+}
diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_task.c b/libs/unimrcp/libs/apr-toolkit/src/apt_task.c
new file mode 100644 (file)
index 0000000..0c8f3d0
--- /dev/null
@@ -0,0 +1,417 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_thread_proc.h>
+#include <apr_thread_cond.h>
+#include "apt_task.h"
+#include "apt_obj_list.h"
+#include "apt_log.h"
+
+/** Internal states of the task */
+typedef enum {
+       TASK_STATE_IDLE,               /**< no task activity */
+       TASK_STATE_START_REQUESTED,    /**< task start is requested and is in progress */
+       TASK_STATE_RUNNING,            /**< task is running */
+       TASK_STATE_TERMINATE_REQUESTED /**< task termination is requested and is in progress */
+} apt_task_state_t;
+
+struct apt_task_t {
+       void                *obj;           /* external object associated with the task */
+       apr_pool_t          *pool;          /* memory pool to allocate task data from */
+       apt_task_msg_pool_t *msg_pool;      /* message pool to allocate task messages from */
+       apr_thread_mutex_t  *data_guard;    /* mutex to protect task data */
+       apr_thread_t        *thread_handle; /* thread handle */
+       apt_task_state_t     state;         /* current task state */
+       apt_task_vtable_t    vtable;        /* table of virtual methods */
+       apt_task_t          *parent_task;   /* parent (master) task */
+       apt_obj_list_t      *child_tasks;   /* list of the child (slave) tasks */
+       apr_size_t           pending_start; /* number of pending start requests */
+       apr_size_t           pending_term;  /* number of pending terminate requests */
+       const char          *name;          /* name of the task */
+};
+
+static void* APR_THREAD_FUNC apt_task_run(apr_thread_t *thread_handle, void *data);
+static apt_bool_t apt_task_terminate_request(apt_task_t *task);
+
+
+APT_DECLARE(apt_task_t*) apt_task_create(
+                                                               void *obj,
+                                                               apt_task_msg_pool_t *msg_pool,
+                                                               apr_pool_t *pool)
+{
+       apt_task_t *task = apr_palloc(pool,sizeof(apt_task_t));
+       task->obj = obj;
+       task->pool = pool;
+       task->msg_pool = msg_pool;
+
+       if(!task->msg_pool) {
+               task->msg_pool = apt_task_msg_pool_create_dynamic(0,pool);
+       }
+
+       task->state = TASK_STATE_IDLE;
+       task->thread_handle = NULL;
+       if(apr_thread_mutex_create(&task->data_guard, APR_THREAD_MUTEX_DEFAULT, task->pool) != APR_SUCCESS) {
+               return NULL;
+       }
+
+       /* reset and copy vtable */
+       apt_task_vtable_reset(&task->vtable);
+       task->vtable.terminate = apt_task_terminate_request;
+       
+       task->parent_task = NULL;
+       task->child_tasks = apt_list_create(pool);
+       task->pending_start = 0;
+       task->pending_term = 0;
+       task->name = "Task";
+       return task;
+}
+
+APT_DECLARE(apt_bool_t) apt_task_destroy(apt_task_t *task)
+{
+       apt_task_t *child_task = NULL;
+       apt_list_elem_t *elem = apt_list_first_elem_get(task->child_tasks);
+       /* walk through the list of the child tasks and destroy them */
+       while(elem) {
+               child_task = apt_list_elem_object_get(elem);
+               if(child_task) {
+                       apt_task_destroy(child_task);
+               }
+               elem = apt_list_next_elem_get(task->child_tasks,elem);
+       }
+
+       if(task->state != TASK_STATE_IDLE) {
+               apt_task_wait_till_complete(task);
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Destroy %s",task->name);
+       if(task->vtable.destroy) {
+               task->vtable.destroy(task);
+       }
+       
+       apr_thread_mutex_destroy(task->data_guard);
+       return TRUE;
+}
+
+APT_DECLARE(apt_bool_t) apt_task_add(apt_task_t *task, apt_task_t *child_task)
+{
+       child_task->parent_task = task;
+       return (apt_list_push_back(task->child_tasks,child_task, child_task->pool) ? TRUE : FALSE);
+}
+
+APT_DECLARE(apt_bool_t) apt_task_start(apt_task_t *task)
+{
+       apt_bool_t status = TRUE;
+       apr_thread_mutex_lock(task->data_guard);
+       if(task->state == TASK_STATE_IDLE) {
+               apr_status_t rv;
+               task->state = TASK_STATE_START_REQUESTED;
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Start %s",task->name);
+               if(task->vtable.start) {
+                       /* raise virtual start method */
+                       task->vtable.start(task);
+               }
+               else {
+                       /* start new thread by default */
+                       rv = apr_thread_create(&task->thread_handle,NULL,apt_task_run,task,task->pool);
+                       if(rv != APR_SUCCESS) {
+                               task->state = TASK_STATE_IDLE;
+                               status = FALSE;
+                       }
+               }
+       }
+       else {
+               status = FALSE;
+       }
+       apr_thread_mutex_unlock(task->data_guard);
+       return status;
+}
+
+APT_DECLARE(apt_bool_t) apt_task_terminate(apt_task_t *task, apt_bool_t wait_till_complete)
+{
+       apt_bool_t status = FALSE;
+       apr_thread_mutex_lock(task->data_guard);
+       if(task->state == TASK_STATE_START_REQUESTED || task->state == TASK_STATE_RUNNING) {
+               task->state = TASK_STATE_TERMINATE_REQUESTED;
+       }
+       apr_thread_mutex_unlock(task->data_guard);
+
+       if(task->state == TASK_STATE_TERMINATE_REQUESTED) {
+               /* raise virtual terminate method */
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Terminate %s",task->name);
+               if(task->vtable.terminate) {
+                       status = task->vtable.terminate(task);
+               }
+
+               if(wait_till_complete == TRUE && status == TRUE) {
+                       apt_task_wait_till_complete(task);
+               }
+       }
+
+       return status;
+}
+
+APT_DECLARE(apt_bool_t) apt_task_wait_till_complete(apt_task_t *task)
+{
+       if(task->thread_handle) {
+               apr_status_t s;
+               apr_thread_join(&s,task->thread_handle);
+               task->thread_handle = NULL;
+       }
+       return TRUE;
+}
+
+APT_DECLARE(void) apt_task_delay(apr_size_t msec)
+{
+       apr_sleep(1000*msec);
+}
+
+APT_DECLARE(apt_task_t*) apt_task_parent_get(apt_task_t *task)
+{
+       return task->parent_task;
+}
+
+APT_DECLARE(apr_pool_t*) apt_task_pool_get(apt_task_t *task)
+{
+       return task->pool;
+}
+
+APT_DECLARE(void*) apt_task_object_get(apt_task_t *task)
+{
+       return task->obj;
+}
+
+APT_DECLARE(apt_task_vtable_t*) apt_task_vtable_get(apt_task_t *task)
+{
+       return &task->vtable;
+}
+
+APT_DECLARE(void) apt_task_name_set(apt_task_t *task, const char *name)
+{
+       task->name = name;
+}
+
+APT_DECLARE(const char*) apt_task_name_get(apt_task_t *task)
+{
+       return task->name;
+}
+
+APT_DECLARE(apt_task_msg_t*) apt_task_msg_get(apt_task_t *task)
+{
+       if(task->msg_pool) {
+               return apt_task_msg_acquire(task->msg_pool);
+       }
+       return NULL;
+}
+
+APT_DECLARE(apt_bool_t) apt_task_msg_signal(apt_task_t *task, apt_task_msg_t *msg)
+{
+       if(task->vtable.signal_msg) {
+               return task->vtable.signal_msg(task,msg);
+       }
+       return FALSE;
+}
+
+APT_DECLARE(apt_bool_t) apt_task_msg_parent_signal(apt_task_t *task, apt_task_msg_t *msg)
+{
+       apt_task_t *parent_task = task->parent_task;
+       if(parent_task) {
+               if(parent_task->vtable.signal_msg) {
+                       return parent_task->vtable.signal_msg(parent_task,msg);
+               }
+       }
+       return FALSE;
+}
+
+
+APT_DECLARE(apt_bool_t) apt_core_task_msg_process(apt_task_t *task, apt_task_msg_t *msg)
+{
+       apt_bool_t running = TRUE;
+       switch(msg->sub_type) {
+               case CORE_TASK_MSG_START_COMPLETE: 
+               {
+                       if(!task->pending_start) {
+                               /* error case, no pending start */
+                               break;
+                       }
+                       task->pending_start--;
+                       if(!task->pending_start) {
+                               if(task->vtable.on_start_complete) {
+                                       task->vtable.on_start_complete(task);
+                               }
+                               if(task->parent_task) {
+                                       /* signal start-complete message */
+                                       apt_task_msg_signal(task->parent_task,msg);
+                               }
+                       }
+                       break;
+               }
+               case CORE_TASK_MSG_TERMINATE_REQUEST:
+               {
+                       apt_task_child_terminate(task);
+                       if(!task->pending_term) {
+                               running = FALSE;
+                       }
+                       break;
+               }
+               case CORE_TASK_MSG_TERMINATE_COMPLETE:
+               {
+                       if(!task->pending_term) {
+                               /* error case, no pending terminate */
+                               break;
+                       }
+                       task->pending_term--;
+                       if(!task->pending_term) {
+                               if(task->vtable.on_terminate_complete) {
+                                       task->vtable.on_terminate_complete(task);
+                               }
+                               if(task->parent_task) {
+                                       /* signal terminate-complete message */
+                                       apt_task_msg_signal(task->parent_task,msg);
+                               }
+                               running = FALSE;
+                       }
+                       break;
+               }
+               default: break;
+       }
+       return running;
+}
+
+APT_DECLARE(apt_bool_t) apt_task_msg_process(apt_task_t *task, apt_task_msg_t *msg)
+{
+       apt_bool_t running = TRUE;
+       if(msg->type == TASK_MSG_CORE) {
+               running = apt_core_task_msg_process(task,msg);
+       }
+       else {
+               if(task->vtable.process_msg) {
+                       task->vtable.process_msg(task,msg);
+               }
+       }
+       
+       apt_task_msg_release(msg);
+       return running;
+}
+
+static apt_bool_t apt_task_terminate_request(apt_task_t *task)
+{
+       if(task->msg_pool) {
+               apt_task_msg_t *msg = apt_task_msg_acquire(task->msg_pool);
+               /* signal terminate-request message */
+               msg->type = TASK_MSG_CORE;
+               msg->sub_type = CORE_TASK_MSG_TERMINATE_REQUEST;
+               return apt_task_msg_signal(task,msg);
+       }
+       return FALSE;
+}
+
+APT_DECLARE(apt_bool_t) apt_task_child_start(apt_task_t *task)
+{
+       apt_task_t *child_task = NULL;
+       apt_list_elem_t *elem = apt_list_first_elem_get(task->child_tasks);
+       task->pending_start = 0;
+       /* walk through the list of the child tasks and start them */
+       while(elem) {
+               child_task = apt_list_elem_object_get(elem);
+               if(child_task) {
+                       if(apt_task_start(child_task) == TRUE) {
+                               task->pending_start++;
+                       }
+               }
+               elem = apt_list_next_elem_get(task->child_tasks,elem);
+       }
+
+       if(!task->pending_start) {
+               /* no child task to start, just raise start-complete event */
+               if(task->vtable.on_start_complete) {
+                       task->vtable.on_start_complete(task);
+               }
+               if(task->parent_task) {
+                       if(task->msg_pool) {
+                               apt_task_msg_t *msg = apt_task_msg_acquire(task->msg_pool);
+                               /* signal start-complete message */
+                               msg->type = TASK_MSG_CORE;
+                               msg->sub_type = CORE_TASK_MSG_START_COMPLETE;
+                               apt_task_msg_signal(task->parent_task,msg);
+                       }
+               }
+       }
+       return TRUE;
+}
+
+APT_DECLARE(apt_bool_t) apt_task_child_terminate(apt_task_t *task)
+{
+       apt_task_t *child_task = NULL;
+       apt_list_elem_t *elem = apt_list_first_elem_get(task->child_tasks);
+       task->pending_term = 0;
+       /* walk through the list of the child tasks and terminate them */
+       while(elem) {
+               child_task = apt_list_elem_object_get(elem);
+               if(child_task) {
+                       if(apt_task_terminate(child_task,FALSE) == TRUE) {
+                               task->pending_term++;
+                       }
+               }
+               elem = apt_list_next_elem_get(task->child_tasks,elem);
+       }
+
+       if(!task->pending_term) {
+               /* no child task to terminate, just raise terminate-complete event */
+               if(task->vtable.on_terminate_complete) {
+                       task->vtable.on_terminate_complete(task);
+               }
+               if(task->parent_task) {
+                       if(task->msg_pool) {
+                               apt_task_msg_t *msg = apt_task_msg_acquire(task->msg_pool);
+                               /* signal terminate-complete message */
+                               msg->type = TASK_MSG_CORE;
+                               msg->sub_type = CORE_TASK_MSG_TERMINATE_COMPLETE;
+                               apt_task_msg_signal(task->parent_task,msg);
+                       }
+               }
+       }
+       return TRUE;
+}
+
+static void* APR_THREAD_FUNC apt_task_run(apr_thread_t *thread_handle, void *data)
+{
+       apt_task_t *task = data;
+       
+       /* raise pre-run event */
+       if(task->vtable.on_pre_run) {
+               task->vtable.on_pre_run(task);
+       }
+       apr_thread_mutex_lock(task->data_guard);
+       task->state = TASK_STATE_RUNNING;
+       apr_thread_mutex_unlock(task->data_guard);
+
+       /* start child tasks (if any) */
+       apt_task_child_start(task);
+
+       /* run task */
+       if(task->vtable.run) {
+               task->vtable.run(task);
+       }
+
+       apr_thread_mutex_lock(task->data_guard);
+       task->state = TASK_STATE_IDLE;
+       apr_thread_mutex_unlock(task->data_guard);
+       /* raise post-run event */
+       if(task->vtable.on_post_run) {
+               task->vtable.on_post_run(task);
+       }
+       return NULL;
+}
diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_task_msg.c b/libs/unimrcp/libs/apr-toolkit/src/apt_task_msg.c
new file mode 100644 (file)
index 0000000..fdff519
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include "apt_task_msg.h"
+
+/** Abstract pool of task messages to allocate task messages from */
+struct apt_task_msg_pool_t {
+       void (*destroy)(apt_task_msg_pool_t *pool);
+
+       apt_task_msg_t* (*acquire_msg)(apt_task_msg_pool_t *pool);
+       void (*release_msg)(apt_task_msg_t *task_msg);
+
+       void       *obj;
+       apr_pool_t *pool;
+};
+
+
+/** Dynamic allocation of messages (no actual pool exist)*/
+typedef struct apt_msg_pool_dynamic_t apt_msg_pool_dynamic_t;
+
+struct apt_msg_pool_dynamic_t {
+       apr_size_t size;
+};
+
+static apt_task_msg_t* dynamic_pool_acquire_msg(apt_task_msg_pool_t *task_msg_pool)
+{
+       apt_msg_pool_dynamic_t *dynamic_pool = task_msg_pool->obj;
+       apt_task_msg_t *task_msg = malloc(dynamic_pool->size);
+       task_msg->msg_pool = task_msg_pool;
+       task_msg->type = TASK_MSG_USER;
+       task_msg->sub_type = 0;
+       return task_msg;
+}
+
+static void dynamic_pool_release_msg(apt_task_msg_t *task_msg)
+{
+       if(task_msg) {
+               free(task_msg);
+       }
+}
+
+static void dynamic_pool_destroy(apt_task_msg_pool_t *task_msg_pool)
+{
+       /* nothing to do */
+}
+
+APT_DECLARE(apt_task_msg_pool_t*) apt_task_msg_pool_create_dynamic(apr_size_t msg_size, apr_pool_t *pool)
+{
+       apt_task_msg_pool_t *task_msg_pool = apr_palloc(pool,sizeof(apt_task_msg_pool_t));
+       apt_msg_pool_dynamic_t *dynamic_pool = apr_palloc(pool,sizeof(apt_msg_pool_dynamic_t));
+       dynamic_pool->size = msg_size + sizeof(apt_task_msg_t) - 1;
+
+       task_msg_pool->pool = pool;
+       task_msg_pool->obj = dynamic_pool;
+       task_msg_pool->acquire_msg = dynamic_pool_acquire_msg;
+       task_msg_pool->release_msg = dynamic_pool_release_msg;
+       task_msg_pool->destroy = dynamic_pool_destroy;
+       return task_msg_pool;
+}
+
+
+/** Static allocation of messages from message pool (not implemented yet) */
+APT_DECLARE(apt_task_msg_pool_t*) apt_task_msg_pool_create_static(apr_size_t msg_size, apr_size_t pool_size, apr_pool_t *pool)
+{
+       return NULL;
+}
+
+
+
+APT_DECLARE(void) apt_task_msg_pool_destroy(apt_task_msg_pool_t *msg_pool)
+{
+       if(msg_pool->destroy) {
+               msg_pool->destroy(msg_pool);
+       }
+}
+
+APT_DECLARE(apt_task_msg_t*) apt_task_msg_acquire(apt_task_msg_pool_t *task_msg_pool)
+{
+       if(!task_msg_pool->acquire_msg)
+               return NULL;
+       return task_msg_pool->acquire_msg(task_msg_pool);
+}
+
+APT_DECLARE(void) apt_task_msg_release(apt_task_msg_t *task_msg)
+{
+       apt_task_msg_pool_t *task_msg_pool = task_msg->msg_pool;
+       if(task_msg_pool->release_msg)
+               task_msg_pool->release_msg(task_msg);
+}
diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_test_suite.c b/libs/unimrcp/libs/apr-toolkit/src/apt_test_suite.c
new file mode 100644 (file)
index 0000000..6a5d18a
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apt_pool.h"
+#include "apt_obj_list.h"
+#include "apt_test_suite.h"
+#include "apt_log.h"
+
+struct apt_test_framework_t{
+       apr_pool_t     *pool;
+       apt_obj_list_t *suites;
+};
+
+APT_DECLARE(apt_test_suite_t*) apt_test_suite_create(apr_pool_t *pool, const char *name, 
+                                                                                                        void *obj, apt_test_f tester)
+{
+       apt_test_suite_t *suite = apr_palloc(pool,sizeof(apt_test_suite_t));
+       suite->pool = pool;
+       apt_string_assign(&suite->name,name,pool);
+       suite->obj = obj;
+       suite->tester = tester;
+       return suite;
+}
+
+APT_DECLARE(apt_test_framework_t*) apt_test_framework_create()
+{
+       apt_test_framework_t *framework;
+       apr_pool_t* pool = apt_pool_create();
+       framework = apr_palloc(pool,sizeof(apt_test_framework_t));
+       framework->pool = pool;
+       framework->suites = apt_list_create(pool);
+
+       apt_log_instance_create(APT_LOG_OUTPUT_CONSOLE,APT_PRIO_INFO,pool);
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create Test Framework");
+       return framework;
+}
+
+APT_DECLARE(void) apt_test_framework_destroy(apt_test_framework_t *framework)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy Test Framework");
+       apt_log_instance_destroy();
+       apr_pool_destroy(framework->pool);
+}
+
+APT_DECLARE(apt_bool_t) apt_test_framework_suite_add(apt_test_framework_t *framework, apt_test_suite_t *suite)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Add Test Suite [%s]",suite->name);
+       return (apt_list_push_back(framework->suites,suite,suite->pool) ? TRUE : FALSE);
+}
+
+APT_DECLARE(apr_pool_t*) apt_test_framework_pool_get(apt_test_framework_t *framework)
+{
+       return framework->pool;
+}
+
+static apt_bool_t apt_test_framework_suite_run(apt_test_framework_t *framework, apt_test_suite_t *suite,
+                                                                                          int argc, const char * const *argv)
+{
+       apt_bool_t status = FALSE;
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"----- Run Test Suite [%s] -----",suite->name);
+       if(suite->tester) {
+               status = suite->tester(suite,argc,argv);
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"---- Status [%s] ----\n",(status == TRUE) ? "OK" : "Failure");
+       return status;
+}
+
+APT_DECLARE(apt_bool_t) apt_test_framework_run(apt_test_framework_t *framework, int argc, const char * const *argv)
+{
+       apt_test_suite_t *suite = NULL;
+       apt_list_elem_t *elem = apt_list_first_elem_get(framework->suites);
+       if(argc == 1) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Run All Test Suites");
+               /* walk through the list of test suites and run all of them */
+               while(elem) {
+                       suite = apt_list_elem_object_get(elem);
+                       if(suite) {
+                               /* run test suite with the default arguments */
+                               apt_test_framework_suite_run(framework,suite,0,NULL);
+                       }
+                       elem = apt_list_next_elem_get(framework->suites,elem);
+               }
+       }
+       else {
+               /* walk through the list of test suites find appropriate one and run it */
+               apt_bool_t found = FALSE;
+               apt_str_t name;
+               apt_string_set(&name,argv[1]);
+               while(elem) {
+                       suite = apt_list_elem_object_get(elem);
+                       if(suite && apt_string_compare(&suite->name,&name) == TRUE) {
+                               found = TRUE;
+                               break;
+                       }
+                       elem = apt_list_next_elem_get(framework->suites,elem);
+               }
+               if(found == TRUE) {
+                       /* run test suite with remaining arguments */
+                       apt_test_framework_suite_run(framework,suite,argc-2,&argv[2]);
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Such Test Suite [%s] to Run", argv[1]);
+               }
+       }
+       return TRUE;
+}
diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_text_stream.c b/libs/unimrcp/libs/apr-toolkit/src/apt_text_stream.c
new file mode 100644 (file)
index 0000000..2735337
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_uuid.h>
+#include "apt_text_stream.h"
+
+#define TOKEN_TRUE  "true"
+#define TOKEN_FALSE "false"
+#define TOKEN_TRUE_LENGTH  (sizeof(TOKEN_TRUE)-1)
+#define TOKEN_FALSE_LENGTH (sizeof(TOKEN_FALSE)-1)
+
+
+/** Navigate through the lines of the text stream (message) */
+APT_DECLARE(apt_bool_t) apt_text_line_read(apt_text_stream_t *stream, apt_str_t *line)
+{
+       char *pos = stream->pos;
+       const char *end = stream->text.buf + stream->text.length;
+       apt_bool_t eol = FALSE;
+       line->length = 0;
+       line->buf = pos;
+       /* while not end of stream */
+       while(pos < end) {
+               if(*pos == APT_TOKEN_CR) {
+                       /* end of line detected */
+                       line->length = pos - line->buf;
+                       pos++;
+                       if(pos < end && *pos == APT_TOKEN_LF) {
+                               pos++;
+                       }
+                       eol = TRUE;
+                       break;
+               }
+               else if(*pos == APT_TOKEN_LF) {
+                       /* end of line detected */
+                       line->length = pos - line->buf;
+                       pos++;
+                       eol = TRUE;
+                       break;
+               }
+               pos++;
+       }
+
+       stream->pos = pos;
+       return eol;
+}
+
+/** Navigate through the headers (name:value pairs) of the text stream (message) 
+       Valid headers are:
+               name:value<CRLF>
+               name: value<CRLF>
+               name:    value<CRLF>
+               name: value<LF>
+               name:<CRLF>              (only name, no value)
+               <CRLF>                   (empty header)
+       Malformed headers are:
+               name:value               (missing end of line <CRLF>)
+               name<CRLF>               (missing separator ':')
+*/
+APT_DECLARE(apt_bool_t) apt_text_header_read(apt_text_stream_t *stream, apt_pair_t *pair)
+{
+       char *pos = stream->pos;
+       const char *end = stream->text.buf + stream->text.length;
+       apt_bool_t eol = FALSE;
+       apt_string_reset(&pair->name);
+       apt_string_reset(&pair->value);
+       /* while not end of stream */
+       while(pos < end) {
+               if(*pos == APT_TOKEN_CR) {
+                       /* end of line detected */
+                       if(pair->value.buf) {
+                               /* set length of the value */
+                               pair->value.length = pos - pair->value.buf;
+                       }
+                       pos++;
+                       if(pos < end && *pos == APT_TOKEN_LF) {
+                               pos++;
+                       }
+                       eol = TRUE;
+                       break;
+               }
+               else if(*pos == APT_TOKEN_LF) {
+                       /* end of line detected */
+                       if(pair->value.buf) {
+                               /* set length of the value */
+                               pair->value.length = pos - pair->value.buf;
+                       }
+                       pos++;
+                       eol = TRUE;
+                       break;
+               }
+               else if(!pair->name.length) {
+                       /* skip initial spaces and read name */
+                       if(!pair->name.buf && *pos != APT_TOKEN_SP) {
+                               pair->name.buf = pos;
+                       }
+                       if(*pos == ':') {
+                               /* set length of the name */
+                               pair->name.length = pos - pair->name.buf;
+                       }
+               }
+               else if(!pair->value.length) {
+                       /* skip initial spaces and read value */
+                       if(!pair->value.buf && *pos != APT_TOKEN_SP) {
+                               pair->value.buf = pos;
+                       }
+               }
+               pos++;
+       }
+
+       stream->pos = pos;
+       /* if length == 0 && buf -> header is malformed */
+       return (eol && (pair->name.length || !pair->name.buf));
+}
+
+
+/** Navigate through the fields of the line */
+APT_DECLARE(apt_bool_t) apt_text_field_read(apt_text_stream_t *stream, char separator, apt_bool_t skip_spaces, apt_str_t *field)
+{
+       char *pos = stream->pos;
+       const char *end = stream->text.buf + stream->text.length;
+       if(skip_spaces == TRUE) {
+               while(pos < end && *pos == APT_TOKEN_SP) pos++;
+       }
+
+       field->buf = pos;
+       field->length = 0;
+       while(pos < end && *pos != separator) pos++;
+
+       field->length = pos - field->buf;
+       if(pos < end) {
+               /* skip the separator */
+               pos++;
+       }
+
+       stream->pos = pos;
+       return field->length ? TRUE : FALSE;
+}
+
+/** Scroll text stream */
+APT_DECLARE(apt_bool_t) apt_text_stream_scroll(apt_text_stream_t *stream)
+{
+       apr_size_t remaining_length = stream->text.buf + stream->text.length - stream->pos;
+       if(!remaining_length || remaining_length == stream->text.length) {
+               stream->pos = stream->text.buf + remaining_length;
+               return FALSE;
+       }
+       memmove(stream->text.buf,stream->pos,remaining_length);
+       stream->pos = stream->text.buf + remaining_length;
+       stream->text.length = remaining_length;
+       *stream->pos = '\0';
+       return TRUE;
+}
+
+/** Parse id@resource string */
+APT_DECLARE(apt_bool_t) apt_id_resource_parse(const apt_str_t *str, char separator, apt_str_t *id, apt_str_t *resource, apr_pool_t *pool)
+{
+       apt_str_t field = *str;
+       const char *pos = strchr(str->buf,separator);
+       if(!pos) {
+               return FALSE;
+       }
+
+       field.length = pos - field.buf;
+       if(field.length >= str->length) {
+               return FALSE;
+       }
+       apt_string_copy(id,&field,pool);
+       field.buf += field.length + 1;
+       field.length = str->length - (field.length + 1);
+       apt_string_copy(resource,&field,pool);
+       return TRUE;
+}
+
+/** Generate id@resource string */
+APT_DECLARE(apt_bool_t) apt_id_resource_generate(const apt_str_t *id, const apt_str_t *resource, char separator, apt_str_t *str, apr_pool_t *pool)
+{
+       apr_size_t length = id->length+resource->length+1;
+       char *buf = apr_palloc(pool,length+1);
+       memcpy(buf,id->buf,id->length);
+       buf[id->length] = separator;
+       memcpy(buf+id->length+1,resource->buf,resource->length);
+       buf[length] = '\0';
+       str->buf = buf;
+       str->length = length;
+       return TRUE;
+}
+
+/** Generate only the name ("name":) of the header */
+APT_DECLARE(apt_bool_t) apt_text_header_name_generate(const apt_str_t *name, apt_text_stream_t *stream)
+{
+       char *pos = stream->pos;
+       memcpy(pos,name->buf,name->length);
+       pos += name->length;
+       *pos++ = ':';
+       *pos++ = ' ';
+       stream->pos = pos;
+       return TRUE;
+}
+
+/** Parse name=value pair */
+static apt_bool_t apt_pair_parse(apt_pair_t *pair, const apt_str_t *field, apr_pool_t *pool)
+{
+       apt_text_stream_t stream;
+       stream.text = *field;
+       stream.pos = stream.text.buf;
+
+       /* read name */
+       if(apt_text_field_read(&stream,'=',TRUE,&pair->name) == FALSE) {
+               return FALSE;
+       }
+
+       /* read value */
+       apt_text_field_read(&stream,';',TRUE,&pair->value);
+       return TRUE;
+}
+
+/** Parse array of name-value pairs */
+APT_DECLARE(apt_bool_t) apt_pair_array_parse(apt_pair_arr_t *arr, const apt_str_t *value, apr_pool_t *pool)
+{
+       apt_str_t field;
+       apt_pair_t *pair;
+       apt_text_stream_t stream;
+       if(!arr || !value) {
+               return FALSE;
+       }
+
+       stream.text = *value;
+       stream.pos = stream.text.buf;
+       /* read name-value pairs */
+       while(apt_text_field_read(&stream,';',TRUE,&field) == TRUE) {
+               pair = apr_array_push(arr);
+               apt_pair_parse(pair,&field,pool);
+       }
+       return TRUE;
+}
+
+/** Generate array of name-value pairs */
+APT_DECLARE(apt_bool_t) apt_pair_array_generate(apt_pair_arr_t *arr, apt_text_stream_t *stream)
+{
+       int i;
+       apt_pair_t *pair;
+       char *pos = stream->pos;
+       if(!arr) {
+               return FALSE;
+       }
+
+       for(i=0; i<arr->nelts; i++) {
+               pair = (apt_pair_t*)arr->elts + i;
+               if(i != 0) {
+                       *pos++ = ';';
+               }
+               if(pair->name.length) {
+                       memcpy(pos,pair->name.buf,pair->name.length);
+                       pos += pair->name.length;
+                       if(pair->value.length) {
+                               *pos++ = '=';
+                               memcpy(pos,pair->value.buf,pair->value.length);
+                               pos += pair->value.length;
+                       }
+               }
+       }
+       stream->pos = pos;
+       return TRUE;
+}
+
+/** Parse boolean-value */
+APT_DECLARE(apt_bool_t) apt_boolean_value_parse(const apt_str_t *str, apt_bool_t *value)
+{
+       if(!str->buf) {
+               return FALSE;
+       }
+       if(strncasecmp(str->buf,TOKEN_TRUE,TOKEN_TRUE_LENGTH) == 0) {
+               *value = TRUE;
+               return TRUE;
+       }
+       if(strncasecmp(str->buf,TOKEN_FALSE,TOKEN_FALSE_LENGTH) == 0) {
+               *value = FALSE;
+               return TRUE;
+       }
+       return FALSE;
+}
+
+/** Generate boolean-value */
+APT_DECLARE(apt_bool_t) apt_boolean_value_generate(apt_bool_t value, apt_text_stream_t *stream)
+{
+       if(value == TRUE) {
+               memcpy(stream->pos,TOKEN_TRUE,TOKEN_TRUE_LENGTH);
+               stream->pos += TOKEN_TRUE_LENGTH;
+       }
+       else {
+               memcpy(stream->pos,TOKEN_FALSE,TOKEN_FALSE_LENGTH);
+               stream->pos += TOKEN_FALSE_LENGTH;
+       }
+       return TRUE;
+}
+
+
+/** Generate value plus the length (number of digits) of the value itself. */
+APT_DECLARE(apt_bool_t) apt_var_length_value_generate(apr_size_t *value, apr_size_t max_count, apt_str_t *str)
+{
+       /* (N >= (10^M-M)) ? N+M+1 : N+M */
+       apr_size_t temp;
+       apr_size_t count; /* M */
+       apr_size_t bounds; /* 10^M */
+       int length;
+
+       /* calculate count */
+       temp = *value;
+       count = 0;
+       do{count++; temp /= 10;} while(temp);
+
+       /* calculate bounds */
+       temp = count;
+       bounds = 1;
+       do{bounds *= 10; temp--;} while(temp);
+
+       if(*value >= bounds - count) {
+               count++;
+       }
+
+       *value += count;
+       if(count > max_count) {
+               return FALSE;
+       }
+
+       str->length = 0;
+       length = sprintf(str->buf, "%"APR_SIZE_T_FMT, *value);
+       if(length <= 0) {
+               return FALSE;
+       }
+       str->length = length;
+       return TRUE;
+}
+
+
+/** Generate unique identifier (hex string) */
+APT_DECLARE(apt_bool_t) apt_unique_id_generate(apt_str_t *id, apr_size_t length, apr_pool_t *pool)
+{
+       char *hex_str;
+       apr_size_t i;
+       apr_size_t count;
+       apr_uuid_t uuid;
+       apr_uuid_get(&uuid);
+       
+       hex_str = apr_palloc(pool,length+1);
+       
+       count = length / 2;
+       if(count > sizeof(uuid)) {
+               count = sizeof(uuid);
+       }
+       for(i=0; i<count; i++) {
+               sprintf(hex_str+i*2,"%02x",uuid.data[i]);
+       }
+       hex_str[length] = '\0';
+
+       id->buf = hex_str;
+       id->length = length;
+       return TRUE;
+}
diff --git a/libs/unimrcp/libs/mpf/Makefile.am b/libs/unimrcp/libs/mpf/Makefile.am
new file mode 100644 (file)
index 0000000..65f1493
--- /dev/null
@@ -0,0 +1,63 @@
+MAINTAINERCLEANFILES    = Makefile.in
+
+INCLUDES                 = -I$(top_srcdir)/libs/mpf/codecs \
+                           -I$(top_srcdir)/libs/mpf/include \
+                           -I$(top_srcdir)/libs/apr-toolkit/include \
+                           $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+noinst_LTLIBRARIES       = libmpf.la
+
+include_HEADERS          = codecs/g711/g711.h \
+                           include/mpf.h \
+                           include/mpf_activity_detector.h \
+                           include/mpf_audio_file_descriptor.h \
+                           include/mpf_audio_file_stream.h \
+                           include/mpf_bridge.h \
+                           include/mpf_buffer.h \
+                           include/mpf_codec.h \
+                           include/mpf_codec_descriptor.h \
+                           include/mpf_codec_manager.h \
+                           include/mpf_context.h \
+                           include/mpf_engine.h \
+                           include/mpf_frame.h \
+                           include/mpf_message.h \
+                           include/mpf_object.h \
+                           include/mpf_stream.h \
+                           include/mpf_stream_mode.h \
+                           include/mpf_termination.h \
+                           include/mpf_rtp_termination_factory.h \
+                           include/mpf_file_termination_factory.h \
+                           include/mpf_timer.h \
+                           include/mpf_types.h \
+                           include/mpf_encoder.h \
+                           include/mpf_decoder.h \
+                           include/mpf_jitter_buffer.h \
+                           include/mpf_rtp_header.h \
+                           include/mpf_rtp_descriptor.h \
+                           include/mpf_rtp_stream.h \
+                           include/mpf_rtp_stat.h \
+                           include/mpf_rtp_defs.h \
+                           include/mpf_rtp_attribs.h \
+                           include/mpf_media_descriptor.h \
+                           include/mpf_user.h
+
+libmpf_la_SOURCES        = codecs/g711/g711.c \
+                           src/mpf_activity_detector.c \
+                           src/mpf_audio_file_stream.c \
+                           src/mpf_bridge.c \
+                           src/mpf_buffer.c \
+                           src/mpf_codec_descriptor.c \
+                           src/mpf_codec_g711.c \
+                           src/mpf_codec_linear.c \
+                           src/mpf_codec_manager.c \
+                           src/mpf_context.c \
+                           src/mpf_engine.c \
+                           src/mpf_termination.c \
+                           src/mpf_rtp_termination_factory.c \
+                           src/mpf_file_termination_factory.c \
+                           src/mpf_timer.c \
+                           src/mpf_encoder.c \
+                           src/mpf_decoder.c \
+                           src/mpf_jitter_buffer.c \
+                           src/mpf_rtp_stream.c \
+                           src/mpf_rtp_attribs.c
diff --git a/libs/unimrcp/libs/mpf/codecs/g711/g711.c b/libs/unimrcp/libs/mpf/codecs/g711/g711.c
new file mode 100644 (file)
index 0000000..be9ab7b
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * g711.c - A-law and u-law transcoding routines
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2006 Steve Underwood
+ *
+ *  Despite my general liking of the GPL, I place this code in the
+ *  public domain for the benefit of all mankind - even the slimy
+ *  ones who might try to proprietize my work and use it to my
+ *  detriment.
+ *
+ */
+
+/*! \file */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#ifndef _MSC_VER
+#include <inttypes.h>
+#ifdef HAVE_TGMATH_H
+#include <tgmath.h>
+#endif
+#endif
+
+#include "g711.h"
+
+/* Copied from the CCITT G.711 specification */
+static const uint8_t ulaw_to_alaw_table[256] =
+{
+     42,  43,  40,  41,  46,  47,  44,  45,  34,  35,  32,  33,  38,  39,  36,  37,
+     58,  59,  56,  57,  62,  63,  60,  61,  50,  51,  48,  49,  54,  55,  52,  53,
+     10,  11,   8,   9,  14,  15,  12,  13,   2,   3,   0,   1,   6,   7,   4,  26,
+     27,  24,  25,  30,  31,  28,  29,  18,  19,  16,  17,  22,  23,  20,  21, 106,
+    104, 105, 110, 111, 108, 109,  98,  99,  96,  97, 102, 103, 100, 101, 122, 120,
+    126, 127, 124, 125, 114, 115, 112, 113, 118, 119, 116, 117,  75,  73,  79,  77,
+     66,  67,  64,  65,  70,  71,  68,  69,  90,  91,  88,  89,  94,  95,  92,  93,
+     82,  82,  83,  83,  80,  80,  81,  81,  86,  86,  87,  87,  84,  84,  85,  85,
+    170, 171, 168, 169, 174, 175, 172, 173, 162, 163, 160, 161, 166, 167, 164, 165,
+    186, 187, 184, 185, 190, 191, 188, 189, 178, 179, 176, 177, 182, 183, 180, 181,
+    138, 139, 136, 137, 142, 143, 140, 141, 130, 131, 128, 129, 134, 135, 132, 154,
+    155, 152, 153, 158, 159, 156, 157, 146, 147, 144, 145, 150, 151, 148, 149, 234,
+    232, 233, 238, 239, 236, 237, 226, 227, 224, 225, 230, 231, 228, 229, 250, 248,
+    254, 255, 252, 253, 242, 243, 240, 241, 246, 247, 244, 245, 203, 201, 207, 205,
+    194, 195, 192, 193, 198, 199, 196, 197, 218, 219, 216, 217, 222, 223, 220, 221,
+    210, 210, 211, 211, 208, 208, 209, 209, 214, 214, 215, 215, 212, 212, 213, 213
+};
+
+/* These transcoding tables are copied from the CCITT G.711 specification. To achieve
+   optimal results, do not change them. */
+
+static const uint8_t alaw_to_ulaw_table[256] =
+{
+     42,  43,  40,  41,  46,  47,  44,  45,  34,  35,  32,  33,  38,  39,  36,  37,
+     57,  58,  55,  56,  61,  62,  59,  60,  49,  50,  47,  48,  53,  54,  51,  52,
+     10,  11,   8,   9,  14,  15,  12,  13,   2,   3,   0,   1,   6,   7,   4,   5,
+     26,  27,  24,  25,  30,  31,  28,  29,  18,  19,  16,  17,  22,  23,  20,  21,
+     98,  99,  96,  97, 102, 103, 100, 101,  93,  93,  92,  92,  95,  95,  94,  94,
+    116, 118, 112, 114, 124, 126, 120, 122, 106, 107, 104, 105, 110, 111, 108, 109,
+     72,  73,  70,  71,  76,  77,  74,  75,  64,  65,  63,  63,  68,  69,  66,  67,
+     86,  87,  84,  85,  90,  91,  88,  89,  79,  79,  78,  78,  82,  83,  80,  81,
+    170, 171, 168, 169, 174, 175, 172, 173, 162, 163, 160, 161, 166, 167, 164, 165,
+    185, 186, 183, 184, 189, 190, 187, 188, 177, 178, 175, 176, 181, 182, 179, 180,
+    138, 139, 136, 137, 142, 143, 140, 141, 130, 131, 128, 129, 134, 135, 132, 133,
+    154, 155, 152, 153, 158, 159, 156, 157, 146, 147, 144, 145, 150, 151, 148, 149,
+    226, 227, 224, 225, 230, 231, 228, 229, 221, 221, 220, 220, 223, 223, 222, 222,
+    244, 246, 240, 242, 252, 254, 248, 250, 234, 235, 232, 233, 238, 239, 236, 237,
+    200, 201, 198, 199, 204, 205, 202, 203, 192, 193, 191, 191, 196, 197, 194, 195,
+    214, 215, 212, 213, 218, 219, 216, 217, 207, 207, 206, 206, 210, 211, 208, 209
+};
+
+uint8_t alaw_to_ulaw(uint8_t alaw)
+{
+    return alaw_to_ulaw_table[alaw];
+}
+/*- End of function --------------------------------------------------------*/
+
+uint8_t ulaw_to_alaw(uint8_t ulaw)
+{
+    return ulaw_to_alaw_table[ulaw];
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/
diff --git a/libs/unimrcp/libs/mpf/codecs/g711/g711.h b/libs/unimrcp/libs/mpf/codecs/g711/g711.h
new file mode 100644 (file)
index 0000000..a8a0e92
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * g711.h - In line A-law and u-law conversion routines
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2001 Steve Underwood
+ *
+ *  Despite my general liking of the GPL, I place this code in the
+ *  public domain for the benefit of all mankind - even the slimy
+ *  ones who might try to proprietize my work and use it to my
+ *  detriment.
+ *
+ */
+
+/*! \file */
+
+/*! \page g711_page A-law and mu-law handling
+Lookup tables for A-law and u-law look attractive, until you consider the impact
+on the CPU cache. If it causes a substantial area of your processor cache to get
+hit too often, cache sloshing will severely slow things down. The main reason
+these routines are slow in C, is the lack of direct access to the CPU's "find
+the first 1" instruction. A little in-line assembler fixes that, and the
+conversion routines can be faster than lookup tables, in most real world usage.
+A "find the first 1" instruction is available on most modern CPUs, and is a
+much underused feature. 
+
+If an assembly language method of bit searching is not available, these routines
+revert to a method that can be a little slow, so the cache thrashing might not
+seem so bad :(
+
+Feel free to submit patches to add fast "find the first 1" support for your own
+favourite processor.
+
+Look up tables are used for transcoding between A-law and u-law, since it is
+difficult to achieve the precise transcoding procedure laid down in the G.711
+specification by other means.
+*/
+
+#if !defined(_G711_H_)
+#define _G711_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+typedef unsigned __int8 uint8_t;
+typedef __int16 int16_t;
+typedef __int32 int32_t;
+typedef unsigned __int16 uint16_t;
+#endif
+
+#if defined(__i386__)
+/*! \brief Find the bit position of the highest set bit in a word
+    \param bits The word to be searched
+    \return The bit number of the highest set bit, or -1 if the word is zero. */
+static __inline__ int top_bit(unsigned int bits)
+{
+    int res;
+
+    __asm__ __volatile__(" movl $-1,%%edx;\n"
+                         " bsrl %%eax,%%edx;\n"
+                         : "=d" (res)
+                         : "a" (bits));
+    return res;
+}
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Find the bit position of the lowest set bit in a word
+    \param bits The word to be searched
+    \return The bit number of the lowest set bit, or -1 if the word is zero. */
+static __inline__ int bottom_bit(unsigned int bits)
+{
+    int res;
+
+    __asm__ __volatile__(" movl $-1,%%edx;\n"
+                         " bsfl %%eax,%%edx;\n"
+                         : "=d" (res)
+                         : "a" (bits));
+    return res;
+}
+/*- End of function --------------------------------------------------------*/
+#elif defined(__x86_64__)
+static __inline__ int top_bit(unsigned int bits)
+{
+    int res;
+
+    __asm__ __volatile__(" movq $-1,%%rdx;\n"
+                         " bsrq %%rax,%%rdx;\n"
+                         : "=d" (res)
+                         : "a" (bits));
+    return res;
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ int bottom_bit(unsigned int bits)
+{
+    int res;
+
+    __asm__ __volatile__(" movq $-1,%%rdx;\n"
+                         " bsfq %%rax,%%rdx;\n"
+                         : "=d" (res)
+                         : "a" (bits));
+    return res;
+}
+/*- End of function --------------------------------------------------------*/
+#else
+static __inline__ int top_bit(unsigned int bits)
+{
+    int i;
+    
+    if (bits == 0)
+        return -1;
+    i = 0;
+    if (bits & 0xFFFF0000)
+    {
+        bits &= 0xFFFF0000;
+        i += 16;
+    }
+    if (bits & 0xFF00FF00)
+    {
+        bits &= 0xFF00FF00;
+        i += 8;
+    }
+    if (bits & 0xF0F0F0F0)
+    {
+        bits &= 0xF0F0F0F0;
+        i += 4;
+    }
+    if (bits & 0xCCCCCCCC)
+    {
+        bits &= 0xCCCCCCCC;
+        i += 2;
+    }
+    if (bits & 0xAAAAAAAA)
+    {
+        bits &= 0xAAAAAAAA;
+        i += 1;
+    }
+    return i;
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ int bottom_bit(unsigned int bits)
+{
+    int i;
+    
+    if (bits == 0)
+        return -1;
+    i = 32;
+    if (bits & 0x0000FFFF)
+    {
+        bits &= 0x0000FFFF;
+        i -= 16;
+    }
+    if (bits & 0x00FF00FF)
+    {
+        bits &= 0x00FF00FF;
+        i -= 8;
+    }
+    if (bits & 0x0F0F0F0F)
+    {
+        bits &= 0x0F0F0F0F;
+        i -= 4;
+    }
+    if (bits & 0x33333333)
+    {
+        bits &= 0x33333333;
+        i -= 2;
+    }
+    if (bits & 0x55555555)
+    {
+        bits &= 0x55555555;
+        i -= 1;
+    }
+    return i;
+}
+/*- End of function --------------------------------------------------------*/
+#endif
+
+/* N.B. It is tempting to use look-up tables for A-law and u-law conversion.
+ *      However, you should consider the cache footprint.
+ *
+ *      A 64K byte table for linear to x-law and a 512 byte table for x-law to
+ *      linear sound like peanuts these days, and shouldn't an array lookup be
+ *      real fast? No! When the cache sloshes as badly as this one will, a tight
+ *      calculation may be better. The messiest part is normally finding the
+ *      segment, but a little inline assembly can fix that on an i386, x86_64 and
+ *      many other modern processors.
+ */
+/*
+ * Mu-law is basically as follows:
+ *
+ *      Biased Linear Input Code        Compressed Code
+ *      ------------------------        ---------------
+ *      00000001wxyza                   000wxyz
+ *      0000001wxyzab                   001wxyz
+ *      000001wxyzabc                   010wxyz
+ *      00001wxyzabcd                   011wxyz
+ *      0001wxyzabcde                   100wxyz
+ *      001wxyzabcdef                   101wxyz
+ *      01wxyzabcdefg                   110wxyz
+ *      1wxyzabcdefgh                   111wxyz
+ *
+ * Each biased linear code has a leading 1 which identifies the segment
+ * number. The value of the segment number is equal to 7 minus the number
+ * of leading 0's. The quantization interval is directly available as the
+ * four bits wxyz.  * The trailing bits (a - h) are ignored.
+ *
+ * Ordinarily the complement of the resulting code word is used for
+ * transmission, and so the code word is complemented before it is returned.
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+
+//#define ULAW_ZEROTRAP                 /* turn on the trap as per the MIL-STD */
+#define ULAW_BIAS        0x84           /* Bias for linear code. */
+
+/*! \brief Encode a linear sample to u-law
+    \param linear The sample to encode.
+    \return The u-law value.
+*/
+static __inline__ uint8_t linear_to_ulaw(int linear)
+{
+    uint8_t u_val;
+    int mask;
+    int seg;
+
+    /* Get the sign and the magnitude of the value. */
+    if (linear < 0)
+    {
+        linear = ULAW_BIAS - linear;
+        mask = 0x7F;
+    }
+    else
+    {
+        linear = ULAW_BIAS + linear;
+        mask = 0xFF;
+    }
+
+    seg = top_bit(linear | 0xFF) - 7;
+
+    /*
+     * Combine the sign, segment, quantization bits,
+     * and complement the code word.
+     */
+    if (seg >= 8)
+        u_val = (uint8_t) (0x7F ^ mask);
+    else
+        u_val = (uint8_t) (((seg << 4) | ((linear >> (seg + 3)) & 0xF)) ^ mask);
+#ifdef ULAW_ZEROTRAP
+    /* Optional ITU trap */
+    if (u_val == 0)
+        u_val = 0x02;
+#endif
+    return  u_val;
+}
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Decode an u-law sample to a linear value.
+    \param ulaw The u-law sample to decode.
+    \return The linear value.
+*/
+static __inline__ int16_t ulaw_to_linear(uint8_t ulaw)
+{
+    int t;
+    
+    /* Complement to obtain normal u-law value. */
+    ulaw = ~ulaw;
+    /*
+     * Extract and bias the quantization bits. Then
+     * shift up by the segment number and subtract out the bias.
+     */
+    t = (((ulaw & 0x0F) << 3) + ULAW_BIAS) << (((int) ulaw & 0x70) >> 4);
+    return  (int16_t) ((ulaw & 0x80)  ?  (ULAW_BIAS - t)  :  (t - ULAW_BIAS));
+}
+/*- End of function --------------------------------------------------------*/
+
+/*
+ * A-law is basically as follows:
+ *
+ *      Linear Input Code        Compressed Code
+ *      -----------------        ---------------
+ *      0000000wxyza             000wxyz
+ *      0000001wxyza             001wxyz
+ *      000001wxyzab             010wxyz
+ *      00001wxyzabc             011wxyz
+ *      0001wxyzabcd             100wxyz
+ *      001wxyzabcde             101wxyz
+ *      01wxyzabcdef             110wxyz
+ *      1wxyzabcdefg             111wxyz
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+
+#define ALAW_AMI_MASK       0x55
+
+/*! \brief Encode a linear sample to A-law
+    \param linear The sample to encode.
+    \return The A-law value.
+*/
+static __inline__ uint8_t linear_to_alaw(int linear)
+{
+    int mask;
+    int seg;
+    
+    if (linear >= 0)
+    {
+        /* Sign (bit 7) bit = 1 */
+        mask = ALAW_AMI_MASK | 0x80;
+    }
+    else
+    {
+        /* Sign (bit 7) bit = 0 */
+        mask = ALAW_AMI_MASK;
+        linear = -linear - 8;
+    }
+
+    /* Convert the scaled magnitude to segment number. */
+    seg = top_bit(linear | 0xFF) - 7;
+    if (seg >= 8)
+    {
+        if (linear >= 0)
+        {
+            /* Out of range. Return maximum value. */
+            return (uint8_t) (0x7F ^ mask);
+        }
+        /* We must be just a tiny step below zero */
+        return (uint8_t) (0x00 ^ mask);
+    }
+    /* Combine the sign, segment, and quantization bits. */
+    return (uint8_t) (((seg << 4) | ((linear >> ((seg)  ?  (seg + 3)  :  4)) & 0x0F)) ^ mask);
+}
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Decode an A-law sample to a linear value.
+    \param alaw The A-law sample to decode.
+    \return The linear value.
+*/
+static __inline__ int16_t alaw_to_linear(uint8_t alaw)
+{
+    int i;
+    int seg;
+
+    alaw ^= ALAW_AMI_MASK;
+    i = ((alaw & 0x0F) << 4);
+    seg = (((int) alaw & 0x70) >> 4);
+    if (seg)
+        i = (i + 0x108) << (seg - 1);
+    else
+        i += 8;
+    return (int16_t) ((alaw & 0x80)  ?  i  :  -i);
+}
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Transcode from A-law to u-law, using the procedure defined in G.711.
+    \param alaw The A-law sample to transcode.
+    \return The best matching u-law value.
+*/
+uint8_t alaw_to_ulaw(uint8_t alaw);
+
+/*! \brief Transcode from u-law to A-law, using the procedure defined in G.711.
+    \param alaw The u-law sample to transcode.
+    \return The best matching A-law value.
+*/
+uint8_t ulaw_to_alaw(uint8_t ulaw);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/*- End of file ------------------------------------------------------------*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf.h b/libs/unimrcp/libs/mpf/include/mpf.h
new file mode 100644 (file)
index 0000000..7edc0da
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_H__
+#define __MPF_H__
+
+/**
+ * @file mpf.h
+ * @brief Media Processing Framework Definitions
+ */ 
+
+#include <apt.h>
+
+/** lib export/import defines (win32) */
+#ifdef WIN32
+#ifdef MPF_STATIC_LIB
+#define MPF_DECLARE(type)   type __stdcall
+#else
+#ifdef MPF_LIB_EXPORT
+#define MPF_DECLARE(type)   __declspec(dllexport) type __stdcall
+#else
+#define MPF_DECLARE(type)   __declspec(dllimport) type __stdcall
+#endif
+#endif
+#else
+#define MPF_DECLARE(type) type
+#endif
+
+#endif /*__MPF_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_activity_detector.h b/libs/unimrcp/libs/mpf/include/mpf_activity_detector.h
new file mode 100644 (file)
index 0000000..8fcb1b4
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_ACTIVITY_DETECTOR_H__
+#define __MPF_ACTIVITY_DETECTOR_H__
+
+/**
+ * @file mpf_activity_detector.h
+ * @brief MPF Voice Activity Detector
+ */ 
+
+#include "mpf_frame.h"
+#include "mpf_codec.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque (voice) activity detector */
+typedef struct mpf_activity_detector_t mpf_activity_detector_t;
+
+/** Events of activity detector */
+typedef enum {
+       MPF_DETECTOR_EVENT_NONE,       /**< no event occurred */
+       MPF_DETECTOR_EVENT_ACTIVITY,   /**< voice activity (transition to activity from inactivity state) */
+       MPF_DETECTOR_EVENT_INACTIVITY, /**< voice inactivity (transition to inactivity from activity state) */
+       MPF_DETECTOR_EVENT_NOINPUT     /**< noinput event occurred */
+} mpf_detector_event_e;
+
+
+/** Create activity detector */
+MPF_DECLARE(mpf_activity_detector_t*) mpf_activity_detector_create(apr_pool_t *pool);
+
+/** Set threshold of voice activity (silence) level */
+MPF_DECLARE(void) mpf_activity_detector_level_set(mpf_activity_detector_t *detector, apr_size_t level_threshold);
+
+/** Set noinput timeout */
+MPF_DECLARE(void) mpf_activity_detector_noinput_timeout_set(mpf_activity_detector_t *detector, apr_size_t noinput_timeout);
+
+/** Set transition complete timeout */
+MPF_DECLARE(void) mpf_activity_detector_complete_timeout_set(mpf_activity_detector_t *detector, apr_size_t complete_timeout);
+
+/** Process current frame, return detected event if any */
+MPF_DECLARE(mpf_detector_event_e) mpf_activity_detector_process(mpf_activity_detector_t *detector, const mpf_frame_t *frame);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_ACTIVITY_DETECTOR_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_audio_file_descriptor.h b/libs/unimrcp/libs/mpf/include/mpf_audio_file_descriptor.h
new file mode 100644 (file)
index 0000000..4dfb6d3
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_AUDIO_FILE_DESCRIPTOR_H__
+#define __MPF_AUDIO_FILE_DESCRIPTOR_H__
+
+/**
+ * @file mpf_audio_file_descriptor.h
+ * @brief MPF Audio File Descriptor
+ */ 
+
+#include <stdio.h>
+#include "mpf_stream_mode.h"
+#include "mpf_codec_descriptor.h"
+
+APT_BEGIN_EXTERN_C
+
+/** FILE_READER is defined as STREAM_MODE_RECEIVE */
+#define FILE_READER STREAM_MODE_RECEIVE
+/** FILE_WRITER is defined as STREAM_MODE_SEND */
+#define FILE_WRITER STREAM_MODE_SEND
+
+/** Audio file descriptor declaration */
+typedef struct mpf_audio_file_descriptor_t mpf_audio_file_descriptor_t;
+
+/** Audio file descriptor */
+struct mpf_audio_file_descriptor_t {
+       /** Indicate what descriptor for (reader and/or write) */
+       mpf_stream_mode_e      mask;
+       /** Codec descriptor to use for audio file read/write */
+       mpf_codec_descriptor_t codec_descriptor;
+       /** File handle to read audio stream */
+       FILE                  *read_handle;
+       /** File handle to write audio stream */
+       FILE                  *write_handle;
+       /** Max size of file  */
+       apr_size_t             max_write_size;
+};
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_AUDIO_FILE_DESCRIPTOR_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_audio_file_stream.h b/libs/unimrcp/libs/mpf/include/mpf_audio_file_stream.h
new file mode 100644 (file)
index 0000000..f117fbf
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_AUDIO_FILE_STREAM_H__
+#define __MPF_AUDIO_FILE_STREAM_H__
+
+/**
+ * @file mpf_audio_file_stream.h
+ * @brief MPF Audio FIle Stream
+ */ 
+
+#include "mpf_stream.h"
+#include "mpf_audio_file_descriptor.h"
+
+APT_BEGIN_EXTERN_C
+
+/**
+ * Create file stream.
+ * @param termination the back pointer to hold
+ * @param pool the pool to allocate memory from
+ */
+MPF_DECLARE(mpf_audio_stream_t*) mpf_file_stream_create(mpf_termination_t *termination, apr_pool_t *pool);
+
+/**
+ * Modify file stream.
+ * @param stream file stream to modify
+ * @param descriptor the descriptor to modify stream according
+ */
+MPF_DECLARE(apt_bool_t) mpf_file_stream_modify(mpf_audio_stream_t *stream, mpf_audio_file_descriptor_t *descriptor);
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_AUDIO_FILE_STREAM_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_bridge.h b/libs/unimrcp/libs/mpf/include/mpf_bridge.h
new file mode 100644 (file)
index 0000000..ceb0071
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_BRIDGE_H__
+#define __MPF_BRIDGE_H__
+
+/**
+ * @file mpf_bridge.h
+ * @brief MPF Stream Bridge
+ */ 
+
+#include "mpf_object.h"
+
+APT_BEGIN_EXTERN_C
+
+/**
+ * Create bridge of audio streams.
+ * @param source the source audio stream
+ * @param sink the sink audio stream
+ * @param pool the pool to allocate memory from
+ */
+MPF_DECLARE(mpf_object_t*) mpf_bridge_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, apr_pool_t *pool);
+
+/**
+ * Create bridge of audio streams with the same codec descriptor.
+ * @param source the source audio stream
+ * @param sink the sink audio stream
+ * @param pool the pool to allocate memory from
+ */
+MPF_DECLARE(mpf_object_t*) mpf_null_bridge_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, apr_pool_t *pool);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_BRIDGE_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_buffer.h b/libs/unimrcp/libs/mpf/include/mpf_buffer.h
new file mode 100644 (file)
index 0000000..6dd22f3
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_BUFFER_H__
+#define __MPF_BUFFER_H__
+
+/**
+ * @file mpf_buffer.h
+ * @brief Buffer of Media Chunks
+ */ 
+
+#include "mpf_frame.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque media buffer declaration */
+typedef struct mpf_buffer_t mpf_buffer_t;
+
+
+/** Create buffer */
+mpf_buffer_t* mpf_buffer_create(apr_pool_t *pool);
+
+/** Destroy buffer */
+void mpf_buffer_destroy(mpf_buffer_t *buffer);
+
+/** Restart buffer */
+apt_bool_t mpf_buffer_restart(mpf_buffer_t *buffer);
+
+/** Write audio chunk to buffer */
+apt_bool_t mpf_buffer_audio_write(mpf_buffer_t *buffer, void *data, apr_size_t size);
+
+/** Write event to buffer */
+apt_bool_t mpf_buffer_event_write(mpf_buffer_t *buffer, mpf_frame_type_e event_type);
+
+/** Read media frame from buffer */
+apt_bool_t mpf_buffer_frame_read(mpf_buffer_t *buffer, mpf_frame_t *media_frame);
+
+/** Get size of buffer **/
+apr_size_t mpf_buffer_get_size(mpf_buffer_t *buffer);
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_BUFFER_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_codec.h b/libs/unimrcp/libs/mpf/include/mpf_codec.h
new file mode 100644 (file)
index 0000000..8c9c4b9
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_CODEC_H__
+#define __MPF_CODEC_H__
+
+/**
+ * @file mpf_codec.h
+ * @brief MPF Codec
+ */ 
+
+#include "mpf_codec_descriptor.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Codec virtual table declaration */
+typedef struct mpf_codec_vtable_t mpf_codec_vtable_t;
+/** Codec declaration*/
+typedef struct mpf_codec_t mpf_codec_t;
+
+/** Codec */
+struct mpf_codec_t {
+       /** Codec manipulators (encode, decode, dissect) */
+       const mpf_codec_vtable_t     *vtable;
+       /** Codec attributes (capabilities) */
+       const mpf_codec_attribs_t    *attribs;
+       /** Optional static codec descriptor (pt < 96) */
+       const mpf_codec_descriptor_t *static_descriptor;
+       
+       /** Negotiated codec descriptor */
+       mpf_codec_descriptor_t       *descriptor;
+};
+
+/** Table of codec virtual methods */
+struct mpf_codec_vtable_t {
+       /** Virtual open method */
+       apt_bool_t (*open)(mpf_codec_t *codec);
+       /** Virtual close method */
+       apt_bool_t (*close)(mpf_codec_t *codec);
+
+       /** Virtual encode method */
+       apt_bool_t (*encode)(mpf_codec_t *codec, const mpf_codec_frame_t *frame_in, mpf_codec_frame_t *frame_out);
+       /** Virtual decode method */
+       apt_bool_t (*decode)(mpf_codec_t *codec, const mpf_codec_frame_t *frame_in, mpf_codec_frame_t *frame_out);
+
+       /** Virtual dissect method */
+       apt_bool_t (*dissect)(mpf_codec_t *codec, void **buffer, apr_size_t *size, mpf_codec_frame_t *frame);
+};
+
+/**
+ * Create codec.
+ * @param vtable the table of virtual mthods
+ * @param attribs the codec attributes
+ * @param descriptor the codec descriptor
+ * @param pool the pool to allocate memory from
+ */
+static APR_INLINE mpf_codec_t* mpf_codec_create(
+                                                                       const mpf_codec_vtable_t *vtable, 
+                                                                       const mpf_codec_attribs_t *attribs, 
+                                                                       const mpf_codec_descriptor_t *descriptor, 
+                                                                       apr_pool_t *pool)
+{
+       mpf_codec_t *codec = (mpf_codec_t*)apr_palloc(pool,sizeof(mpf_codec_t));
+       codec->vtable = vtable;
+       codec->attribs = attribs;
+       codec->static_descriptor = descriptor;
+       codec->descriptor = NULL;
+       return codec;
+}
+
+/**
+ * Close codec.
+ * @param src_codec the source (original) codec to clone
+ * @param pool the pool to allocate memory from
+ */
+static APR_INLINE mpf_codec_t* mpf_codec_clone(mpf_codec_t *src_codec, apr_pool_t *pool)
+{
+       mpf_codec_t *codec = (mpf_codec_t*)apr_palloc(pool,sizeof(mpf_codec_t));
+       codec->vtable = src_codec->vtable;
+       codec->attribs = src_codec->attribs;
+       codec->static_descriptor = src_codec->static_descriptor;
+       codec->descriptor = src_codec->descriptor;
+       return codec;
+}
+
+/** Open codec */
+static APR_INLINE apt_bool_t mpf_codec_open(mpf_codec_t *codec)
+{
+       apt_bool_t rv = TRUE;
+       if(codec->descriptor) {
+               if(codec->vtable->open) {
+                       rv = codec->vtable->open(codec);
+               }
+       }
+       else {
+               rv = FALSE;
+       }
+       return rv;
+}
+
+/** Close codec */
+static APR_INLINE apt_bool_t mpf_codec_close(mpf_codec_t *codec)
+{
+       apt_bool_t rv = TRUE;
+       if(codec->vtable->close) {
+               rv = codec->vtable->close(codec);
+       }
+       return rv;
+}
+
+/** Encode codec frame */
+static APR_INLINE apt_bool_t mpf_codec_encode(mpf_codec_t *codec, const mpf_codec_frame_t *frame_in, mpf_codec_frame_t *frame_out)
+{
+       apt_bool_t rv = TRUE;
+       if(codec->vtable->encode) {
+               rv = codec->vtable->encode(codec,frame_in,frame_out);
+       }
+       return rv;
+}
+
+/** Decode codec frame */
+static APR_INLINE apt_bool_t mpf_codec_decode(mpf_codec_t *codec, const mpf_codec_frame_t *frame_in, mpf_codec_frame_t *frame_out)
+{
+       apt_bool_t rv = TRUE;
+       if(codec->vtable->decode) {
+               rv = codec->vtable->decode(codec,frame_in,frame_out);
+       }
+       return rv;
+}
+
+/** Dissect codec frame (navigate through codec frames in a buffer, which may contain multiple frames) */
+static APR_INLINE apt_bool_t mpf_codec_dissect(mpf_codec_t *codec, void **buffer, apr_size_t *size, mpf_codec_frame_t *frame)
+{
+       apt_bool_t rv = TRUE;
+       if(codec->vtable->dissect) {
+               /* custom dissector for codecs like G.729, G.723 */
+               rv = codec->vtable->dissect(codec,buffer,size,frame);
+       }
+       else {
+               /* default dissector */
+               if(*size >= frame->size && frame->size) {
+                       memcpy(frame->buffer,*buffer,frame->size);
+                       
+                       *buffer = (apr_byte_t*)*buffer + frame->size;
+                       *size = *size - frame->size;
+               }
+               else {
+                       rv = FALSE;
+               }
+       }
+       return rv;
+}
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_CODEC_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_codec_descriptor.h b/libs/unimrcp/libs/mpf/include/mpf_codec_descriptor.h
new file mode 100644 (file)
index 0000000..29adb7b
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_CODEC_DESCRIPTOR_H__
+#define __MPF_CODEC_DESCRIPTOR_H__
+
+/**
+ * @file mpf_codec_descriptor.h
+ * @brief MPF Codec Descriptor
+ */ 
+
+#include <apr_tables.h>
+#include "apt_string.h"
+#include "mpf.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Codec frame time base in msec */
+#define CODEC_FRAME_TIME_BASE 10
+/** Bytes per sample for linear pcm */
+#define BYTES_PER_SAMPLE 2
+/** Bits per sample for linear pcm */
+#define BITS_PER_SAMPLE 16
+
+/** Supported sampling rates */
+typedef enum {
+       MPF_SAMPLE_RATE_NONE  = 0x00,
+       MPF_SAMPLE_RATE_8000  = 0x01,
+       MPF_SAMPLE_RATE_16000 = 0x02
+} mpf_sample_rates_e;
+
+/** Codec descriptor declaration */
+typedef struct mpf_codec_descriptor_t mpf_codec_descriptor_t;
+/** Codec list declaration */
+typedef struct mpf_codec_list_t mpf_codec_list_t;
+/** Codec frame declaration */
+typedef struct mpf_codec_frame_t mpf_codec_frame_t;
+/** Codec attributes declaration */
+typedef struct mpf_codec_attribs_t mpf_codec_attribs_t;
+
+
+/** Codec descriptor */
+struct mpf_codec_descriptor_t {
+       /** Payload type used in RTP packet */
+       apr_byte_t   payload_type;
+       /** Codec name */
+       apt_str_t    name;
+       /** Sampling rate */
+       apr_uint16_t sampling_rate;
+       /** Channel count */
+       apr_byte_t   channel_count;
+       /** Codec dependent additional format */
+       const char  *format;
+       /**  Enabled/disabled state */
+       apt_bool_t   enabled;
+};
+
+/** List of codec descriptors */
+struct mpf_codec_list_t {
+       /** Dynamic array of mpf_codec_descriptor_t */
+       apr_array_header_t     *descriptor_arr;
+       /** Preffered codec descriptor */
+       mpf_codec_descriptor_t *preffered;
+};
+
+/** Codec frame */
+struct mpf_codec_frame_t {
+       /** Raw buffer, which may contain encoded or decoded data */
+       void      *buffer;
+       /** Buffer size */
+       apr_size_t size;
+};
+
+/** Codec attributes */
+struct mpf_codec_attribs_t {
+       /** Codec name */
+       apt_str_t  name;
+       /** Bits per sample */
+       apr_byte_t bits_per_samples;
+       /** Supported sampling rates (mpf_sample_rates_e) */
+       int        sample_rates;
+};
+
+
+/** Initialize codec descriptor */
+static APR_INLINE void mpf_codec_descriptor_init(mpf_codec_descriptor_t *descriptor)
+{
+       descriptor->payload_type = 0;
+       apt_string_reset(&descriptor->name);
+       descriptor->sampling_rate = 0;
+       descriptor->channel_count = 0;
+       descriptor->format = NULL;
+       descriptor->enabled = TRUE;
+}
+
+/** Calculate encoded frame size in bytes */
+static APR_INLINE apr_size_t mpf_codec_frame_size_calculate(const mpf_codec_descriptor_t *descriptor, const mpf_codec_attribs_t *attribs)
+{
+       return descriptor->channel_count * attribs->bits_per_samples * CODEC_FRAME_TIME_BASE * 
+                       descriptor->sampling_rate / 1000 / 8; /* 1000 - msec per sec, 8 - bits per byte */
+}
+
+/** Calculate samples of the frame (ts) */
+static APR_INLINE apr_size_t mpf_codec_frame_samples_calculate(const mpf_codec_descriptor_t *descriptor)
+{
+       return descriptor->channel_count * CODEC_FRAME_TIME_BASE * descriptor->sampling_rate / 1000;
+}
+
+/** Calculate linear frame size in bytes */
+static APR_INLINE apr_size_t mpf_codec_linear_frame_size_calculate(apr_uint16_t sampling_rate, apr_byte_t channel_count)
+{
+       return channel_count * BYTES_PER_SAMPLE * CODEC_FRAME_TIME_BASE * sampling_rate / 1000;
+}
+
+/** Reset list of codec descriptors */
+static APR_INLINE void mpf_codec_list_reset(mpf_codec_list_t *codec_list)
+{
+       codec_list->descriptor_arr = NULL;
+       codec_list->preffered = NULL;
+}
+
+/** Initialize list of codec descriptors */
+static APR_INLINE void mpf_codec_list_init(mpf_codec_list_t *codec_list, apr_size_t initial_count, apr_pool_t *pool)
+{
+       codec_list->descriptor_arr = apr_array_make(pool,(int)initial_count, sizeof(mpf_codec_descriptor_t));
+}
+
+/** Copy list of codec descriptors */
+static APR_INLINE void mpf_codec_list_copy(mpf_codec_list_t *codec_list, const mpf_codec_list_t *src_codec_list, apr_pool_t *pool)
+{
+       codec_list->descriptor_arr = apr_array_copy(pool,src_codec_list->descriptor_arr);
+}
+
+/** Increment number of codec descriptors in the list and return the descriptor to fill */
+static APR_INLINE mpf_codec_descriptor_t* mpf_codec_list_add(mpf_codec_list_t *codec_list)
+{
+       mpf_codec_descriptor_t* descriptor = (mpf_codec_descriptor_t*)apr_array_push(codec_list->descriptor_arr);
+       mpf_codec_descriptor_init(descriptor);
+       return descriptor;
+}
+
+/** Determine if codec list is empty */
+static APR_INLINE apt_bool_t mpf_codec_list_is_empty(const mpf_codec_list_t *codec_list)
+{
+       return apr_is_empty_array(codec_list->descriptor_arr);
+}
+
+/** Get codec descriptor by index */
+static APR_INLINE mpf_codec_descriptor_t* mpf_codec_get(const mpf_codec_list_t *codec_list, apr_size_t id)
+{
+       mpf_codec_descriptor_t *descriptor;
+       if(id >= (apr_size_t)codec_list->descriptor_arr->nelts) {
+               return NULL;
+       }
+       descriptor = (mpf_codec_descriptor_t*)codec_list->descriptor_arr->elts;
+       return descriptor + id;
+}
+
+/** Match two codec descriptors */
+MPF_DECLARE(apt_bool_t) mpf_codec_descriptor_match(const mpf_codec_descriptor_t *descriptor1, const mpf_codec_descriptor_t *descriptor2);
+/** Intersect two codec lists */
+MPF_DECLARE(apt_bool_t) mpf_codec_list_intersect(mpf_codec_list_t *codec_list1, mpf_codec_list_t *codec_list2);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_CODEC_DESCRIPTOR_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_codec_manager.h b/libs/unimrcp/libs/mpf/include/mpf_codec_manager.h
new file mode 100644 (file)
index 0000000..2b14070
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_CODEC_MANAGER_H__
+#define __MPF_CODEC_MANAGER_H__
+
+/**
+ * @file mpf_codec_manager.h
+ * @brief MPF Codec Manager
+ */ 
+
+#include "mpf_types.h"
+#include "mpf_codec.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Create codec manager */
+MPF_DECLARE(mpf_codec_manager_t*) mpf_codec_manager_create(apr_size_t codec_count, apr_pool_t *pool);
+
+/** Destroy codec manager */
+MPF_DECLARE(void) mpf_codec_manager_destroy(mpf_codec_manager_t *codec_manager);
+
+/** Register codec in codec manager */
+MPF_DECLARE(apt_bool_t) mpf_codec_manager_codec_register(mpf_codec_manager_t *codec_manager, mpf_codec_t *codec);
+
+/** Get (allocate) codec by codec descriptor */
+MPF_DECLARE(mpf_codec_t*) mpf_codec_manager_codec_get(const mpf_codec_manager_t *codec_manager, mpf_codec_descriptor_t *descriptor, apr_pool_t *pool);
+
+/** Get (allocate) list of available codecs */
+MPF_DECLARE(apt_bool_t) mpf_codec_manager_codec_list_get(const mpf_codec_manager_t *codec_manager, mpf_codec_list_t *codec_list, apr_pool_t *pool);
+
+/** Load (allocate) list of codecs  */
+MPF_DECLARE(apt_bool_t) mpf_codec_manager_codec_list_load(const mpf_codec_manager_t *codec_manager, mpf_codec_list_t *codec_list, const char *str, apr_pool_t *pool);
+
+/** Find codec by name  */
+MPF_DECLARE(const mpf_codec_t*) mpf_codec_manager_codec_find(const mpf_codec_manager_t *codec_manager, const apt_str_t *codec_name);
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_CODEC_MANAGER_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_context.h b/libs/unimrcp/libs/mpf/include/mpf_context.h
new file mode 100644 (file)
index 0000000..49f99e2
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_CONTEXT_H__
+#define __MPF_CONTEXT_H__
+
+/**
+ * @file mpf_context.h
+ * @brief MPF Context
+ */ 
+
+#include "mpf_object.h"
+#include "apt_obj_list.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Definition of table item used in context */
+typedef void* table_item_t;
+
+/** Media processing context */
+struct mpf_context_t {
+    /** Pool to allocate memory from */
+       apr_pool_t        *pool;
+    /** External object */
+       void              *obj;
+    /** Set when context is addded to the list to ensure quick find on delete */
+       apt_list_elem_t   *elem;
+
+       /** Max number of terminations */
+       apr_size_t          max_termination_count;
+       /** Current number of terminations */
+       apr_size_t          termination_count;
+       /** Table, which holds terminations and topology */
+       table_item_t      **table;
+};
+
+
+/**
+ * Add termination to context.
+ * @param context the context to add termination to
+ * @param termination the termination to add
+ */
+MPF_DECLARE(apt_bool_t) mpf_context_termination_add(mpf_context_t *context, mpf_termination_t *termination);
+
+/**
+ * Subtract termination from context.
+ * @param context the context to subtract termination from
+ * @param termination the termination to subtract
+ */
+MPF_DECLARE(apt_bool_t) mpf_context_termination_subtract(mpf_context_t *context, mpf_termination_t *termination);
+
+/**
+ * Apply topology.
+ * @param context the context which holds the termination
+ * @param termination the termination to apply toplogy for
+ */
+MPF_DECLARE(apt_bool_t) mpf_context_topology_apply(mpf_context_t *context, mpf_termination_t *termination);
+
+/**
+ * Destroy topology.
+ * @param context the context which holds the termination
+ * @param termination the termination to destroy toplogy for
+ */
+MPF_DECLARE(apt_bool_t) mpf_context_topology_destroy(mpf_context_t *context, mpf_termination_t *termination);
+
+/**
+ * Process context.
+ * @param context the context
+ */
+MPF_DECLARE(apt_bool_t) mpf_context_process(mpf_context_t *context);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_CONTEXT_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_decoder.h b/libs/unimrcp/libs/mpf/include/mpf_decoder.h
new file mode 100644 (file)
index 0000000..0d40bd3
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_DECODER_H__
+#define __MPF_DECODER_H__
+
+/**
+ * @file mpf_decoder.h
+ * @brief MPF Stream Decoder
+ */ 
+
+#include "mpf_stream.h"
+
+APT_BEGIN_EXTERN_C
+
+/**
+ * Create audio stream decoder.
+ * @param source the source to get encoded stream from
+ * @param pool the pool to allocate memory from
+ */
+MPF_DECLARE(mpf_audio_stream_t*) mpf_decoder_create(mpf_audio_stream_t *source, apr_pool_t *pool);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_ENCODER_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_encoder.h b/libs/unimrcp/libs/mpf/include/mpf_encoder.h
new file mode 100644 (file)
index 0000000..36a819d
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_ENCODER_H__
+#define __MPF_ENCODER_H__
+
+/**
+ * @file mpf_encoder.h
+ * @brief MPF Stream Encoder
+ */ 
+
+#include "mpf_stream.h"
+
+APT_BEGIN_EXTERN_C
+
+/**
+ * Create audio stream encoder.
+ * @param sink the sink to write encoded stream to
+ * @param pool the pool to allocate memory from
+ */
+MPF_DECLARE(mpf_audio_stream_t*) mpf_encoder_create(mpf_audio_stream_t *sink, apr_pool_t *pool);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_ENCODER_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_engine.h b/libs/unimrcp/libs/mpf/include/mpf_engine.h
new file mode 100644 (file)
index 0000000..d1d38a6
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_ENGINE_H__
+#define __MPF_ENGINE_H__
+
+/**
+ * @file mpf_engine.h
+ * @brief Media Processing Framework Engine
+ */ 
+
+#include "apt_task.h"
+#include "mpf_message.h"
+
+APT_BEGIN_EXTERN_C
+
+/**
+ * Create MPF engine.
+ * @param pool the pool to allocate memory from
+ */
+MPF_DECLARE(mpf_engine_t*) mpf_engine_create(apr_pool_t *pool);
+
+/**
+ * Create MPF codec manager.
+ * @param pool the pool to allocate memory from
+ */
+MPF_DECLARE(mpf_codec_manager_t*) mpf_engine_codec_manager_create(apr_pool_t *pool);
+
+/**
+ * Register MPF codec manager.
+ * @param engine the engine to register codec manager for
+ * @param codec_manager the codec manager to register
+ */
+MPF_DECLARE(apt_bool_t) mpf_engine_codec_manager_register(mpf_engine_t *engine, const mpf_codec_manager_t *codec_manager);
+
+/**
+ * Get task.
+ * @param engine the engine to get task from
+ */
+MPF_DECLARE(apt_task_t*) mpf_task_get(mpf_engine_t *engine);
+
+/**
+ * Set task msg type to send responses and events with.
+ * @param engine the engine to set task msg type for
+ * @param type the type to set
+ */
+MPF_DECLARE(void) mpf_engine_task_msg_type_set(mpf_engine_t *engine, apt_task_msg_type_e type);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_ENGINE_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_file_termination_factory.h b/libs/unimrcp/libs/mpf/include/mpf_file_termination_factory.h
new file mode 100644 (file)
index 0000000..f824328
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_FILE_TERMINATION_FACTORY_H__
+#define __MPF_FILE_TERMINATION_FACTORY_H__
+
+/**
+ * @file mpf_file_termination_factory.h
+ * @brief MPF File Termination Factory
+ */ 
+
+#include "mpf_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/**
+ * Create file termination factory.
+ */
+MPF_DECLARE(mpf_termination_factory_t*) mpf_file_termination_factory_create(apr_pool_t *pool);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_RTP_TERMINATION_FACTORY_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_frame.h b/libs/unimrcp/libs/mpf/include/mpf_frame.h
new file mode 100644 (file)
index 0000000..b1c8c43
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_FRAME_H__
+#define __MPF_FRAME_H__
+
+/**
+ * @file mpf_frame.h
+ * @brief MPF Audio/Video/Named-event Frame
+ */ 
+
+#include "mpf_codec_descriptor.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Media frame types */
+typedef enum {
+       MEDIA_FRAME_TYPE_NONE  = 0x0, /**< none */
+       MEDIA_FRAME_TYPE_AUDIO = 0x1, /**< audio frame */
+       MEDIA_FRAME_TYPE_VIDEO = 0x2, /**< video frame */
+       MEDIA_FRAME_TYPE_EVENT = 0x4  /**< named event frame (RFC2833) */
+} mpf_frame_type_e;
+
+/** Named event declaration */
+typedef struct mpf_named_event_frame_t mpf_named_event_frame_t;
+/** Media frame declaration */
+typedef struct mpf_frame_t mpf_frame_t;
+
+
+/** Named event (RFC2833, out-of-band DTMF) */
+struct mpf_named_event_frame_t {
+       /** event (DTMF, tone) identifier */
+       apr_uint32_t event_id: 8;
+#if (APR_IS_BIGENDIAN == 1)
+       /** end of event */
+       apr_uint32_t edge:     1;
+       /** reserved */
+       apr_uint32_t reserved: 1;
+       /** tone volume */
+       apr_uint32_t volume:   6;
+#else
+       /** tone volume */
+       apr_uint32_t volume:   6;
+       /** reserved */
+       apr_uint32_t reserved: 1;
+       /** end of event */
+       apr_uint32_t edge:     1;
+#endif
+       /** event duration */
+       apr_uint32_t duration: 16;
+};
+
+/** Media frame */
+struct mpf_frame_t {
+       /** frame type (audio/video/named-event) mpf_frame_type_e */
+       int                     type;
+       /** codec frame */
+       mpf_codec_frame_t       codec_frame;
+       /** named-event frame */
+       mpf_named_event_frame_t event_frame;
+};
+
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_FRAME_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_jitter_buffer.h b/libs/unimrcp/libs/mpf/include/mpf_jitter_buffer.h
new file mode 100644 (file)
index 0000000..d638439
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_JITTER_BUFFER_H__
+#define __MPF_JITTER_BUFFER_H__
+
+/**
+ * @file mpf_jitter_buffer.h
+ * @brief Jitter Buffer
+ */ 
+
+#include "mpf_frame.h"
+#include "mpf_codec.h"
+#include "mpf_rtp_descriptor.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Jitter buffer write result */
+typedef enum {
+       JB_OK,                   /**< successful write */
+       JB_DISCARD_NOT_ALLIGNED, /**< discarded write (frame isn't alligned to CODEC_FRAME_TIME_BASE) */
+       JB_DISCARD_TOO_LATE,     /**< discarded write (frame is arrived too late) */
+       JB_DISCARD_TOO_EARLY,    /**< discarded write (frame is arrived too early, buffer is full) */
+} jb_result_t;
+
+/** Opaque jitter buffer declaration */
+typedef struct mpf_jitter_buffer_t mpf_jitter_buffer_t;
+
+
+/** Create jitter buffer */
+mpf_jitter_buffer_t* mpf_jitter_buffer_create(mpf_jb_config_t *jb_config, mpf_codec_t *codec, apr_pool_t *pool);
+
+/** Destroy jitter buffer */
+void mpf_jitter_buffer_destroy(mpf_jitter_buffer_t *jb);
+
+/** Restart jitter buffer */
+apt_bool_t mpf_jitter_buffer_restart(mpf_jitter_buffer_t *jb);
+
+/** Write audio data to jitter buffer */
+jb_result_t mpf_jitter_buffer_write(mpf_jitter_buffer_t *jb, mpf_codec_t *codec, void *buffer, apr_size_t size, apr_uint32_t ts);
+
+/** Write named event to jitter buffer */
+jb_result_t mpf_jitter_buffer_write_named_event(mpf_jitter_buffer_t *jb, mpf_named_event_frame_t *named_event, apr_uint32_t ts);
+
+/** Read media frame from jitter buffer */
+apt_bool_t mpf_jitter_buffer_read(mpf_jitter_buffer_t *jb, mpf_frame_t *media_frame);
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_JITTER_BUFFER_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_media_descriptor.h b/libs/unimrcp/libs/mpf/include/mpf_media_descriptor.h
new file mode 100644 (file)
index 0000000..af54224
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_MEDIA_DESCRIPTOR_H__
+#define __MPF_MEDIA_DESCRIPTOR_H__
+
+/**
+ * @file mpf_media_descriptor.h
+ * @brief Media Descriptor Base
+ */ 
+
+#include <apr_network_io.h>
+#include "apt_string.h"
+
+APT_BEGIN_EXTERN_C
+
+/** MPF media state */
+typedef enum {
+       MPF_MEDIA_DISABLED, /**< disabled media */
+       MPF_MEDIA_ENABLED   /**< enabled media */
+} mpf_media_state_e;
+
+/** MPF media descriptor declaration */
+typedef struct mpf_media_descriptor_t mpf_media_descriptor_t;
+
+/** MPF media descriptor */
+struct mpf_media_descriptor_t {
+       /** Media state (disabled/enabled)*/
+       mpf_media_state_e state;
+
+       /** Ip address */
+       apt_str_t          ip;
+       /** External (NAT) Ip address */
+       apt_str_t          ext_ip;
+       /** Port */
+       apr_port_t         port;
+       /** Identifier (0,1,...) */
+       apr_size_t         id;
+};
+
+/** Initialize MPF media descriptor */
+static APR_INLINE void mpf_media_descriptor_init(mpf_media_descriptor_t *descriptor)
+{
+       descriptor->state = MPF_MEDIA_DISABLED;
+       apt_string_reset(&descriptor->ip);
+       apt_string_reset(&descriptor->ext_ip);
+       descriptor->port = 0;
+       descriptor->id = 0;
+}
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_MEDIA_DESCRIPTOR_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_message.h b/libs/unimrcp/libs/mpf/include/mpf_message.h
new file mode 100644 (file)
index 0000000..ae69638
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_MESSAGE_H__
+#define __MPF_MESSAGE_H__
+
+/**
+ * @file mpf_message.h
+ * @brief Media Processing Framework Message Definitions
+ */ 
+
+#include "mpf_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Enumeration of MPF message types */
+typedef enum {
+       MPF_MESSAGE_TYPE_REQUEST,  /**< request message */
+       MPF_MESSAGE_TYPE_RESPONSE, /**< response message */
+       MPF_MESSAGE_TYPE_EVENT     /**< event message */
+} mpf_message_type_e;
+
+/** Enumeration of MPF status codes */
+typedef enum {
+       MPF_STATUS_CODE_SUCCESS,  /**< indicates success */
+       MPF_STATUS_CODE_FAILURE   /**< indicates failure */
+} mpf_status_code_e;
+
+
+/** Enumeration of commands */
+typedef enum {
+       MPF_COMMAND_ADD,     /**< add termination to context */
+       MPF_COMMAND_MODIFY,  /**< modify termination properties */
+       MPF_COMMAND_SUBTRACT,/**< subtract termination from context */ 
+       MPF_COMMAND_MOVE     /**< move termination to another context */
+} mpf_command_type_e;
+
+/** MPF message declaration */
+typedef struct mpf_message_t mpf_message_t;
+
+/** MPF message definition */
+struct mpf_message_t {
+       /** Message type (request/response/event) */
+       mpf_message_type_e message_type;
+       /** Command identifier (add, modify, subtract, ...) */
+       mpf_command_type_e command_id;
+       /** Status code used in responses */
+       mpf_status_code_e  status_code;
+
+       /** Context */
+       mpf_context_t     *context;
+       /** Termination */
+       mpf_termination_t *termination;
+       /** Termination type dependent descriptor */
+       void              *descriptor;
+};
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_MESSAGE_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_object.h b/libs/unimrcp/libs/mpf/include/mpf_object.h
new file mode 100644 (file)
index 0000000..f4136b0
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_OBJECT_H__
+#define __MPF_OBJECT_H__
+
+/**
+ * @file mpf_object.h
+ * @brief Media Processing Object Base (bridge, multiplexor, mixer, ...)
+ */ 
+
+#include "mpf_types.h"
+#include "mpf_frame.h"
+
+APT_BEGIN_EXTERN_C
+
+/** MPF object declaration */
+typedef struct mpf_object_t mpf_object_t;
+
+/** Base for media processing objects */
+struct mpf_object_t {
+       /** Audio stream source */
+       mpf_audio_stream_t *source;
+       /** Audio stream sink */
+       mpf_audio_stream_t *sink;
+
+       /** Media frame used to read data from source and write it to sink */
+       mpf_frame_t         frame;
+
+       /** Virtual process */
+       apt_bool_t (*process)(mpf_object_t *object);
+       /** Virtual destroy */
+       apt_bool_t (*destroy)(mpf_object_t *object);
+};
+
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_OBJECT_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_rtp_attribs.h b/libs/unimrcp/libs/mpf/include/mpf_rtp_attribs.h
new file mode 100644 (file)
index 0000000..5fe3d96
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_RTP_ATTRIBS_H__
+#define __MPF_RTP_ATTRIBS_H__
+
+/**
+ * @file mpf_rtp_attribs.h
+ * @brief RTP Attributes (SDP)
+ */ 
+
+#include "mpf_media_descriptor.h"
+#include "mpf_stream_mode.h"
+
+APT_BEGIN_EXTERN_C
+
+/** RTP attributes */
+typedef enum {
+       RTP_ATTRIB_RTPMAP,
+       RTP_ATTRIB_SENDONLY,
+       RTP_ATTRIB_RECVONLY,
+       RTP_ATTRIB_SENDRECV,
+       RTP_ATTRIB_MID,
+       RTP_ATTRIB_PTIME,
+
+       RTP_ATTRIB_COUNT,
+       RTP_ATTRIB_UNKNOWN = RTP_ATTRIB_COUNT
+} mpf_rtp_attrib_e;
+
+
+/** Get audio media attribute name by attribute identifier */
+MPF_DECLARE(const apt_str_t*) mpf_rtp_attrib_str_get(mpf_rtp_attrib_e attrib_id);
+
+/** Find audio media attribute identifier by attribute name */
+MPF_DECLARE(mpf_rtp_attrib_e) mpf_rtp_attrib_id_find(const apt_str_t *attrib);
+
+/** Get string by stream mode (send/receive) */
+MPF_DECLARE(const apt_str_t*) mpf_stream_mode_str_get(mpf_stream_mode_e direction);
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_RTP_ATTRIBS_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_rtp_defs.h b/libs/unimrcp/libs/mpf/include/mpf_rtp_defs.h
new file mode 100644 (file)
index 0000000..9fc7925
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_RTP_DEFS_H__
+#define __MPF_RTP_DEFS_H__
+
+/**
+ * @file mpf_rtp_defs.h
+ * @brief Internal RTP Definitions
+ */ 
+
+#include "mpf_rtp_stat.h"
+#include "mpf_jitter_buffer.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Used to calculate actual number of received packets (32bit) in
+ * case seq number (16bit) wrapped around */
+#define RTP_SEQ_MOD (1 << 16)
+/** Number of max dropout packets (seq numbers) is used to trigger drift 
+ * in seq number or misorder packets */
+#define MAX_DROPOUT 3000
+/** Number of max misorder packets (seq numbers) to differentiate 
+ * seq drift from misorder packets */
+#define MAX_MISORDER 100
+/** Restart receiver if threshold is fired */
+#define DISCARDED_TO_RECEIVED_RATIO_THRESHOLD 30 /* 30% */
+/** Deviation threshold is used to trigger drift in timestamps */
+#define DEVIATION_THRESHOLD 4000
+
+/** RTP receive history declaration */
+typedef struct rtp_rx_history_t rtp_rx_history_t;
+/** RTP receive periodic history declaration */
+typedef struct rtp_rx_periodic_history_t rtp_rx_periodic_history_t;
+/** RTP receiver declaration */
+typedef struct rtp_receiver_t rtp_receiver_t;
+/** RTP transmitter declaration */
+typedef struct rtp_transmitter_t rtp_transmitter_t;
+
+/** History of RTP receive */
+struct rtp_rx_history_t {
+       /** Updated on every seq num wrap around*/
+       apr_uint32_t           seq_cycles;
+
+       /** First seq num received */
+       apr_uint16_t           seq_num_base;
+       /** Max seq num received */
+       apr_uint16_t           seq_num_max;
+
+       /** Last timestamp received */
+       apr_uint32_t           ts_last;
+       /** Local time measured on last packet received */
+       apr_time_t             time_last;
+
+       /** New ssrc, which is in probation */
+       apr_uint32_t           ssrc_new;
+       /** Period of ssrc probation */
+       apr_byte_t             ssrc_probation;
+};
+
+/** Periodic history of RTP receive (initialized after every N packets) */
+struct rtp_rx_periodic_history_t {
+       /** Number of packets received */
+       apr_uint32_t           received_prior;
+       /** Number of packets discarded */
+       apr_uint32_t           discarded_prior;
+
+       /** Min jitter */
+       apr_uint32_t           jitter_min;
+       /** Max jitter */
+       apr_uint32_t           jitter_max;
+};
+
+/** Reset RTP receive history */
+static APR_INLINE void mpf_rtp_rx_history_reset(rtp_rx_history_t *rx_history)
+{
+       memset(rx_history,0,sizeof(rtp_rx_history_t));
+}
+
+/** Reset RTP receive periodic history */
+static APR_INLINE void mpf_rtp_rx_periodic_history_reset(rtp_rx_periodic_history_t *rx_periodic_history)
+{
+       memset(rx_periodic_history,0,sizeof(rtp_rx_periodic_history_t));
+}
+
+/** RTP receiver */
+struct rtp_receiver_t {
+       /** Payload type of named-event packets (RFC2833) */
+       apr_byte_t                event_pt;
+
+       /** Jitter buffer */
+       mpf_jitter_buffer_t      *jb;
+
+       /** RTP receive statistics to report */
+       rtp_rx_stat_t             stat;
+       /** RTP history */
+       rtp_rx_history_t          history;
+       /** RTP periodic history */
+       rtp_rx_periodic_history_t periodic_history;
+};
+
+
+/** RTP transmitter */
+struct rtp_transmitter_t {
+       /** RTP stream ssrc */
+       apr_uint32_t    ssrc;
+       /** Payload type of named-event packets (RFC2833) */
+       apr_byte_t      event_pt;
+       /** Packetization time in msec */
+       apr_uint16_t    ptime;
+
+       /** Number of frames in a packet */
+       apr_uint16_t    packet_frames;
+       /** Current number of frames */
+       apr_uint16_t    current_frames;
+       /** Samples in frames in timestamp units */
+       apr_uint32_t    samples_per_frame;
+
+       /** Indicate silence period among the talkspurts */
+       apr_byte_t      inactivity;
+       /** Last seq number sent */
+       apr_uint16_t    last_seq_num;
+       /** Current timestamp (samples processed) */
+       apr_uint32_t    timestamp;
+
+       /** RTP packet payload */
+       char           *packet_data;
+       /** RTP packet payload size */
+       apr_size_t      packet_size;
+
+       /** RTP transmit statistics to report */
+       rtp_tx_stat_t   stat;
+};
+
+
+/** Initialize RTP receiver */
+static APR_INLINE void rtp_receiver_init(rtp_receiver_t *receiver)
+{
+       receiver->event_pt = 0;
+
+       receiver->jb = NULL;
+
+       mpf_rtp_rx_stat_reset(&receiver->stat);
+       mpf_rtp_rx_history_reset(&receiver->history);
+       mpf_rtp_rx_periodic_history_reset(&receiver->periodic_history);
+}
+
+/** Initialize RTP transmitter */
+static APR_INLINE void rtp_transmitter_init(rtp_transmitter_t *transmitter)
+{
+       transmitter->ssrc = 0;
+       transmitter->event_pt = 0;
+       transmitter->ptime = 0;
+
+       transmitter->packet_frames = 0;
+       transmitter->current_frames = 0;
+       transmitter->samples_per_frame = 0;
+
+       transmitter->inactivity = 0;
+       transmitter->last_seq_num = 0;
+       transmitter->timestamp = 0;
+
+       transmitter->packet_data = NULL;
+       transmitter->packet_size = 0;
+
+       mpf_rtp_tx_stat_reset(&transmitter->stat);
+}
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_RTP_DEFS_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_rtp_descriptor.h b/libs/unimrcp/libs/mpf/include/mpf_rtp_descriptor.h
new file mode 100644 (file)
index 0000000..46655e4
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_RTP_DESCRIPTOR_H__
+#define __MPF_RTP_DESCRIPTOR_H__
+
+/**
+ * @file mpf_rtp_descriptor.h
+ * @brief MPF RTP Stream Descriptor
+ */ 
+
+#include "mpf_stream_mode.h"
+#include "mpf_media_descriptor.h"
+#include "mpf_codec_descriptor.h"
+
+APT_BEGIN_EXTERN_C
+
+/** RTP media descriptor declaration */
+typedef struct mpf_rtp_media_descriptor_t mpf_rtp_media_descriptor_t;
+/** RTP stream descriptor declaration */
+typedef struct mpf_rtp_stream_descriptor_t mpf_rtp_stream_descriptor_t;
+/** RTP termination descriptor declaration */
+typedef struct mpf_rtp_termination_descriptor_t mpf_rtp_termination_descriptor_t;
+/** RTP configuration declaration */
+typedef struct mpf_rtp_config_t mpf_rtp_config_t;
+/** Jitter buffer configuration declaration */
+typedef struct mpf_jb_config_t mpf_jb_config_t;
+
+
+/** RTP media (local/remote) descriptor */
+struct mpf_rtp_media_descriptor_t {
+       /** Media descriptor base */
+       mpf_media_descriptor_t base;
+       /** Stream mode (send/receive) */
+       mpf_stream_mode_e      mode;
+       /** Packetization time */
+       apr_uint16_t           ptime;
+       /** Codec list */
+       mpf_codec_list_t       codec_list;
+       /** Media identifier */
+       apr_size_t             mid;
+};
+
+/** RTP stream descriptor */
+struct mpf_rtp_stream_descriptor_t {
+       /** Local media descriptor */
+       mpf_rtp_media_descriptor_t *local;
+       /** Remote media descriptor */
+       mpf_rtp_media_descriptor_t *remote;
+};
+
+/** RTP termination descriptor */
+struct mpf_rtp_termination_descriptor_t {
+       /** Audio stream descriptor */
+       mpf_rtp_stream_descriptor_t audio;
+       /** Video stream descriptor */
+       mpf_rtp_stream_descriptor_t video;
+};
+
+/** Jitter buffer configuration */
+struct mpf_jb_config_t {
+       /** Min playout delay in msec (used in case of adaptive jitter buffer) */
+       apr_size_t min_playout_delay;
+       /** Initial playout delay in msec */
+       apr_size_t initial_playout_delay;
+       /** Max playout delay in msec (used in case of adaptive jitter buffer) */
+       apr_size_t max_playout_delay;
+       /** Static - 0, adaptive - 1 jitter buffer */
+       apr_byte_t adaptive;
+};
+
+/** RTP config */
+struct mpf_rtp_config_t {
+       /** Local IP address to bind to */
+       apt_str_t ip;
+       /** External (NAT) IP address */
+       apt_str_t ext_ip;
+       /** Min RTP port */
+       apr_port_t rtp_port_min;
+       /** Max RTP port */
+       apr_port_t rtp_port_max;
+       /** Current RTP port */
+       apr_port_t rtp_port_cur;
+       /** Packetization time */
+       apr_uint16_t ptime;
+       /** Codec list */
+       mpf_codec_list_t codec_list;
+       /** Preference in offer/anser: 1 - own(local) preference, 0 - remote preference */
+       apt_bool_t own_preferrence;
+       /** Jitter buffer config */
+       mpf_jb_config_t jb_config;
+};
+
+/** Initialize media descriptor */
+static APR_INLINE void mpf_rtp_media_descriptor_init(mpf_rtp_media_descriptor_t *media)
+{
+       mpf_media_descriptor_init(&media->base);
+       media->mode = STREAM_MODE_NONE;
+       media->ptime = 0;
+       mpf_codec_list_reset(&media->codec_list);
+       media->mid = 0;
+}
+
+/** Initialize stream descriptor */
+static APR_INLINE void mpf_rtp_stream_descriptor_init(mpf_rtp_stream_descriptor_t *stream)
+{
+       stream->local = NULL;
+       stream->remote = NULL;
+}
+
+/** Initialize RTP termination descriptor */
+static APR_INLINE void mpf_rtp_termination_descriptor_init(mpf_rtp_termination_descriptor_t *rtp_descriptor)
+{
+       mpf_rtp_stream_descriptor_init(&rtp_descriptor->audio);
+       mpf_rtp_stream_descriptor_init(&rtp_descriptor->video);
+}
+
+/** Initialize JB config */
+static APR_INLINE void mpf_jb_config_init(mpf_jb_config_t *jb_config)
+{
+       jb_config->adaptive = 0;
+       jb_config->initial_playout_delay = 0;
+       jb_config->min_playout_delay = 0;
+       jb_config->max_playout_delay = 0;
+}
+
+/** Create/allocate RTP config */
+static APR_INLINE mpf_rtp_config_t* mpf_rtp_config_create(apr_pool_t *pool)
+{
+       mpf_rtp_config_t *rtp_config = (mpf_rtp_config_t*)apr_palloc(pool,sizeof(mpf_rtp_config_t));
+       apt_string_reset(&rtp_config->ip);
+       apt_string_reset(&rtp_config->ext_ip);
+       rtp_config->rtp_port_cur = 0;
+       rtp_config->rtp_port_min = 0;
+       rtp_config->rtp_port_max = 0;
+       rtp_config->ptime = 0;
+       mpf_codec_list_init(&rtp_config->codec_list,0,pool);
+       rtp_config->own_preferrence = FALSE;
+       mpf_jb_config_init(&rtp_config->jb_config);
+       return rtp_config;
+}
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_RTP_DESCRIPTOR_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_rtp_header.h b/libs/unimrcp/libs/mpf/include/mpf_rtp_header.h
new file mode 100644 (file)
index 0000000..070bf8c
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_RTP_HEADER_H__
+#define __MPF_RTP_HEADER_H__
+
+/**
+ * @file mpf_rtp_header.h
+ * @brief RTP Header Definition
+ */ 
+
+#include "mpf.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Protocol version. */
+#define RTP_VERSION 2
+
+/** RTP header declaration */
+typedef struct rtp_header_t rtp_header_t;
+/** RTP extension header declaration */
+typedef struct rtp_extension_header_t rtp_extension_header_t;
+
+
+/** RTP header */
+struct rtp_header_t {
+#if (APR_IS_BIGENDIAN == 1)
+       /** protocol version */
+       apr_uint32_t version:   2;
+       /** padding flag */
+       apr_uint32_t padding:   1;
+       /** header extension flag */
+       apr_uint32_t extension: 1;
+       /** CSRC count */
+       apr_uint32_t count:     4;
+       /** marker bit */
+       apr_uint32_t marker:    1;
+       /** payload type */
+       apr_uint32_t type:      7;
+#else
+       /** CSRC count */
+       apr_uint32_t count:     4;
+       /** header extension flag */
+       apr_uint32_t extension: 1;
+       /** padding flag */
+       apr_uint32_t padding:   1;
+       /** protocol version */
+       apr_uint32_t version:   2;
+       /** payload type */
+       apr_uint32_t type:      7;
+       /** marker bit */
+       apr_uint32_t marker:    1;
+#endif 
+       
+       /** sequence number */
+       apr_uint32_t sequence:  16;
+       /** timestamp */
+       apr_uint32_t timestamp;
+       /** synchronization source */
+       apr_uint32_t ssrc;
+};
+
+/** RTP extension header */
+struct rtp_extension_header_t
+{
+       /** profile */
+       apr_uint16_t profile;
+       /** length */
+       apr_uint16_t length;
+};
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_RTP_HEADER_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_rtp_stat.h b/libs/unimrcp/libs/mpf/include/mpf_rtp_stat.h
new file mode 100644 (file)
index 0000000..248a4b5
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_RTP_STAT_H__
+#define __MPF_RTP_STAT_H__
+
+/**
+ * @file mpf_rtp_stat.h
+ * @brief RTP Statistics
+ */ 
+
+#include "mpf.h"
+
+APT_BEGIN_EXTERN_C
+
+/** RTP transmit statistics declaration */
+typedef struct rtp_tx_stat_t rtp_tx_stat_t;
+/** RTP receive statistics declaration */
+typedef struct rtp_rx_stat_t rtp_rx_stat_t;
+
+
+/** RTP transmit statistics */
+struct rtp_tx_stat_t {
+       /** number of RTP packets received */
+       apr_uint32_t    sent_packets;
+
+       /* more to come */
+};
+
+/** RTP receive statistics */
+struct rtp_rx_stat_t {
+       /** number of valid RTP packets received */
+       apr_uint32_t           received_packets;
+       /** number of invalid RTP packets received */
+       apr_uint32_t           invalid_packets;
+
+       /** number of discarded in jitter buffer packets */
+       apr_uint32_t           discarded_packets;
+       /** number of ignored packets */
+       apr_uint32_t           ignored_packets;
+
+       /** number of lost in network packets */
+       apr_uint32_t           lost_packets;
+
+       /** number of restarts */
+       apr_byte_t             restarts;
+
+       /** network jitter (rfc3550) */
+       apr_uint32_t           jitter;
+
+       /** source id of received RTP stream */
+       apr_uint32_t           ssrc;
+};
+
+
+/** Reset RTP transmit statistics */
+static APR_INLINE void mpf_rtp_tx_stat_reset(rtp_tx_stat_t *tx_stat)
+{
+       memset(tx_stat,0,sizeof(rtp_tx_stat_t));
+}
+
+/** Reset RTP receive statistics */
+static APR_INLINE void mpf_rtp_rx_stat_reset(rtp_rx_stat_t *rx_stat)
+{
+       memset(rx_stat,0,sizeof(rtp_rx_stat_t));
+}
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_RTP_STAT_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_rtp_stream.h b/libs/unimrcp/libs/mpf/include/mpf_rtp_stream.h
new file mode 100644 (file)
index 0000000..848cb54
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_RTP_STREAM_H__
+#define __MPF_RTP_STREAM_H__
+
+/**
+ * @file mpf_rtp_stream.h
+ * @brief MPF RTP Stream
+ */ 
+
+#include "mpf_stream.h"
+#include "mpf_rtp_descriptor.h"
+
+APT_BEGIN_EXTERN_C
+
+/**
+ * Create RTP stream.
+ * @param termination the back pointer to hold
+ * @param config the configuration to use
+ * @param pool the pool to allocate memory from
+ */
+MPF_DECLARE(mpf_audio_stream_t*) mpf_rtp_stream_create(mpf_termination_t *termination, mpf_rtp_config_t *config, apr_pool_t *pool);
+
+/**
+ * Modify RTP stream.
+ * @param stream RTP stream to modify
+ * @param descriptor the descriptor to modify stream according
+ */
+MPF_DECLARE(apt_bool_t) mpf_rtp_stream_modify(mpf_audio_stream_t *stream, mpf_rtp_stream_descriptor_t *descriptor);
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_RTP_STREAM_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_rtp_termination_factory.h b/libs/unimrcp/libs/mpf/include/mpf_rtp_termination_factory.h
new file mode 100644 (file)
index 0000000..2f9f171
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_RTP_TERMINATION_FACTORY_H__
+#define __MPF_RTP_TERMINATION_FACTORY_H__
+
+/**
+ * @file mpf_rtp_termination_factory.h
+ * @brief MPF RTP Termination Factory
+ */ 
+
+#include <apr_network_io.h>
+#include "mpf_types.h"
+#include "mpf_rtp_descriptor.h"
+
+APT_BEGIN_EXTERN_C
+
+/**
+ * Create RTP termination factory.
+ */
+MPF_DECLARE(mpf_termination_factory_t*) mpf_rtp_termination_factory_create(
+                                                                               mpf_rtp_config_t *rtp_config,
+                                                                               apr_pool_t *pool);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_RTP_TERMINATION_FACTORY_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_stream.h b/libs/unimrcp/libs/mpf/include/mpf_stream.h
new file mode 100644 (file)
index 0000000..9df864e
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_STREAM_H__
+#define __MPF_STREAM_H__
+
+/**
+ * @file mpf_stream.h
+ * @brief MPF Bidirectional Stream
+ */ 
+
+#include "mpf_types.h"
+#include "mpf_stream_mode.h"
+#include "mpf_frame.h"
+#include "mpf_codec.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque audio stream virtual table declaration */
+typedef struct mpf_audio_stream_vtable_t mpf_audio_stream_vtable_t;
+
+/** Audio stream */
+struct mpf_audio_stream_t {
+       /** External object */
+       void                            *obj;
+       /** Table of virtual methods */
+       const mpf_audio_stream_vtable_t *vtable;
+       /** Back pointer */
+       mpf_termination_t               *termination;
+       /** Stream mode (send/receive) */
+       mpf_stream_mode_e                mode;
+       /** Receive codec */
+       mpf_codec_t                     *rx_codec;
+       /** Transmit codec */
+       mpf_codec_t                     *tx_codec;
+};
+
+/** Video stream */
+struct mpf_video_stream_t {
+       /** Back pointer */
+       mpf_termination_t               *termination;
+       /** Stream mode (send/receive) */
+       mpf_stream_mode_e                mode;
+};
+
+/** Table of audio stream virtual methods */
+struct mpf_audio_stream_vtable_t {
+       /** Virtual destroy method */
+       apt_bool_t (*destroy)(mpf_audio_stream_t *stream);
+
+       /** Virtual open receiver method */
+       apt_bool_t (*open_rx)(mpf_audio_stream_t *stream);
+       /** Virtual close receiver method */
+       apt_bool_t (*close_rx)(mpf_audio_stream_t *stream);
+       /** Virtual read frame method */
+       apt_bool_t (*read_frame)(mpf_audio_stream_t *stream, mpf_frame_t *frame);
+
+       /** Virtual open transmitter method */
+       apt_bool_t (*open_tx)(mpf_audio_stream_t *stream);
+       /** Virtual close transmitter method */
+       apt_bool_t (*close_tx)(mpf_audio_stream_t *stream);
+       /** Virtual write frame method */
+       apt_bool_t (*write_frame)(mpf_audio_stream_t *stream, const mpf_frame_t *frame);
+};
+
+
+/** Create audio stream */
+static APR_INLINE mpf_audio_stream_t* mpf_audio_stream_create(void *obj, const mpf_audio_stream_vtable_t *vtable, mpf_stream_mode_e mode, apr_pool_t *pool)
+{
+       mpf_audio_stream_t *stream = (mpf_audio_stream_t*)apr_palloc(pool,sizeof(mpf_audio_stream_t));
+       stream->obj = obj;
+       stream->vtable = vtable;
+       stream->termination = NULL;
+       stream->mode = mode;
+       stream->rx_codec = NULL;
+       stream->tx_codec = NULL;
+       return stream;
+}
+
+/** Destroy audio stream */
+static APR_INLINE apt_bool_t mpf_audio_stream_destroy(mpf_audio_stream_t *stream)
+{
+       if(stream->vtable->destroy)
+               return stream->vtable->destroy(stream);
+       return TRUE;
+}
+
+/** Open audio stream receive */
+static APR_INLINE apt_bool_t mpf_audio_stream_rx_open(mpf_audio_stream_t *stream)
+{
+       if(stream->vtable->open_rx)
+               return stream->vtable->open_rx(stream);
+       return TRUE;
+}
+
+/** Close audio stream receive */
+static APR_INLINE apt_bool_t mpf_audio_stream_rx_close(mpf_audio_stream_t *stream)
+{
+       if(stream->vtable->close_rx)
+               return stream->vtable->close_rx(stream);
+       return TRUE;
+}
+
+/** Read frame */
+static APR_INLINE apt_bool_t mpf_audio_stream_frame_read(mpf_audio_stream_t *stream, mpf_frame_t *frame)
+{
+       if(stream->vtable->read_frame)
+               return stream->vtable->read_frame(stream,frame);
+       return TRUE;
+}
+
+/** Open audio stream transmit */
+static APR_INLINE apt_bool_t mpf_audio_stream_tx_open(mpf_audio_stream_t *stream)
+{
+       if(stream->vtable->open_tx)
+               return stream->vtable->open_tx(stream);
+       return TRUE;
+}
+
+/** Close audio stream transmit */
+static APR_INLINE apt_bool_t mpf_audio_stream_tx_close(mpf_audio_stream_t *stream)
+{
+       if(stream->vtable->close_tx)
+               return stream->vtable->close_tx(stream);
+       return TRUE;
+}
+
+/** Write frame */
+static APR_INLINE apt_bool_t mpf_audio_stream_frame_write(mpf_audio_stream_t *stream, const mpf_frame_t *frame)
+{
+       if(stream->vtable->write_frame)
+               return stream->vtable->write_frame(stream,frame);
+       return TRUE;
+}
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_STREAM_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_stream_mode.h b/libs/unimrcp/libs/mpf/include/mpf_stream_mode.h
new file mode 100644 (file)
index 0000000..9b7cf0d
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_STREAM_MODE_H__
+#define __MPF_STREAM_MODE_H__
+
+/**
+ * @file mpf_stream_mode.h
+ * @brief MPF Stream Mode (Send/Receive)
+ */ 
+
+#include "mpf.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Enumeration of stream modes */
+typedef enum {
+       STREAM_MODE_NONE    = 0x0, /**< none */
+       STREAM_MODE_SEND    = 0x1, /**< send */
+       STREAM_MODE_RECEIVE = 0x2, /**< receive */
+
+       STREAM_MODE_SEND_RECEIVE = STREAM_MODE_SEND | STREAM_MODE_RECEIVE /**< send and receive */
+} mpf_stream_mode_e; 
+
+static APR_INLINE mpf_stream_mode_e mpf_stream_mode_negotiate(mpf_stream_mode_e remote_mode)
+{
+       mpf_stream_mode_e local_mode = remote_mode;
+       if(local_mode == STREAM_MODE_SEND) {
+               local_mode = STREAM_MODE_RECEIVE;
+       }
+       else if(local_mode == STREAM_MODE_RECEIVE) {
+               local_mode = STREAM_MODE_SEND;
+       }
+       return local_mode;
+}
+
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_STREAM_MODE_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_termination.h b/libs/unimrcp/libs/mpf/include/mpf_termination.h
new file mode 100644 (file)
index 0000000..df51fbb
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_TERMINATION_H__
+#define __MPF_TERMINATION_H__
+
+/**
+ * @file mpf_termination.h
+ * @brief MPF Termination
+ */ 
+
+#include "mpf_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Prototype of termination event handler */
+typedef apt_bool_t (*mpf_termination_event_handler_f)(mpf_termination_t *termination, int event_id, void *descriptor);
+
+/** MPF Termination */
+struct mpf_termination_t {
+       /** Pool to allocate memory from */
+       apr_pool_t                     *pool;
+       /** External object */
+       void                           *obj;
+       /** Object to send events to */
+       void                           *event_handler_obj;
+       /** Event handler */
+       mpf_termination_event_handler_f event_handler;
+       /** Codec manager */
+       const mpf_codec_manager_t      *codec_manager;
+       /** Termination factory entire termination created by */
+       mpf_termination_factory_t      *termination_factory;
+       /** Table of virtual methods */
+       const mpf_termination_vtable_t *vtable;
+       /** Slot in context */
+       apr_size_t                      slot;
+
+       /** Audio stream */
+       mpf_audio_stream_t             *audio_stream;
+       /** Video stream */
+       mpf_video_stream_t             *video_stream;
+};
+
+/** MPF termination factory */
+struct mpf_termination_factory_t {
+       /** Virtual create */
+       mpf_termination_t* (*create_termination)(mpf_termination_factory_t *factory, void *obj, apr_pool_t *pool);
+
+       /* more to add */
+};
+
+
+/**
+ * Create MPF termination base.
+ * @param termination_factory the termination factory
+ * @param obj the external object associated with termination
+ * @param vtable the table of virtual functions of termination
+ * @param audio_stream the audio stream
+ * @param video_stream the video stream
+ * @param pool the pool to allocate memory from
+ */
+MPF_DECLARE(mpf_termination_t*) mpf_termination_base_create(
+                                                                               mpf_termination_factory_t *termination_factory,
+                                                                               void *obj,
+                                                                               const mpf_termination_vtable_t *vtable,
+                                                                               mpf_audio_stream_t *audio_stream, 
+                                                                               mpf_video_stream_t *video_stream, 
+                                                                               apr_pool_t *pool);
+
+/**
+ * Modify MPF termination.
+ * @param termination the termination to modify
+ * @param descriptor the termination specific descriptor
+ */
+MPF_DECLARE(apt_bool_t) mpf_termination_modify(mpf_termination_t *termination, void *descriptor);
+
+/**
+ * Validate MPF termination.
+ * @param termination the termination to validate
+ */
+MPF_DECLARE(apt_bool_t) mpf_termination_validate(mpf_termination_t *termination);
+
+/**
+ * Destroy MPF termination.
+ * @param termination the termination to destroy
+ */
+MPF_DECLARE(apt_bool_t) mpf_termination_destroy(mpf_termination_t *termination);
+
+/**
+ * Get associated object.
+ * @param termination the termination to get object from
+ */
+MPF_DECLARE(void*) mpf_termination_object_get(mpf_termination_t *termination);
+
+
+/**
+ * Create MPF termination by termination factory.
+ * @param termination_factory the termination factory to create termination from
+ * @param obj the external object associated with termination
+ * @param pool the pool to allocate memory from
+ */
+MPF_DECLARE(mpf_termination_t*) mpf_termination_create(
+                                                                               mpf_termination_factory_t *termination_factory,
+                                                                               void *obj,
+                                                                               apr_pool_t *pool);
+
+/**
+ * Create raw MPF termination.
+ * @param obj the external object associated with termination
+ * @param audio_stream the audio stream of the termination
+ * @param video_stream the video stream of the termination
+ * @param pool the pool to allocate memory from
+ */
+MPF_DECLARE(mpf_termination_t*) mpf_raw_termination_create(
+                                                                               void *obj,
+                                                                               mpf_audio_stream_t *audio_stream, 
+                                                                               mpf_video_stream_t *video_stream, 
+                                                                               apr_pool_t *pool);
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_TERMINATION_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_timer.h b/libs/unimrcp/libs/mpf/include/mpf_timer.h
new file mode 100644 (file)
index 0000000..a58af07
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_TIMER_H__
+#define __MPF_TIMER_H__
+
+/**
+ * @file mpf_timer.h
+ * @brief MPF High Resolution Timer
+ */ 
+
+#include "mpf.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque MPF timer declaration */
+typedef struct mpf_timer_t mpf_timer_t;
+
+/** Prototype of timer callback */
+typedef void (*mpf_timer_proc_f)(mpf_timer_t *timer, void *obj);
+
+/** Start periodic timer */
+MPF_DECLARE(mpf_timer_t*) mpf_timer_start(unsigned long timeout, mpf_timer_proc_f timer_proc, void *obj, apr_pool_t *pool);
+
+/** Stop timer */
+MPF_DECLARE(void) mpf_timer_stop(mpf_timer_t *timer);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_TIMER_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_types.h b/libs/unimrcp/libs/mpf/include/mpf_types.h
new file mode 100644 (file)
index 0000000..721fa61
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_TYPES_H__
+#define __MPF_TYPES_H__
+
+/**
+ * @file mpf_types.h
+ * @brief MPF Types Declarations
+ */ 
+
+#include "mpf.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque MPF engine declaration */
+typedef struct mpf_engine_t mpf_engine_t;
+
+/** Opaque codec manager declaration */
+typedef struct mpf_codec_manager_t mpf_codec_manager_t;
+
+/** Opaque MPF context declaration */
+typedef struct mpf_context_t mpf_context_t;
+
+/** Opaque MPF termination declaration */
+typedef struct mpf_termination_t mpf_termination_t;
+
+/** Opaque MPF termination factory declaration */
+typedef struct mpf_termination_factory_t mpf_termination_factory_t;
+
+/** Opaque MPF audio stream declaration */
+typedef struct mpf_audio_stream_t mpf_audio_stream_t;
+
+/** Opaque MPF video stream declaration */
+typedef struct mpf_video_stream_t mpf_video_stream_t;
+
+/** Termination vtable declaration */
+typedef struct mpf_termination_vtable_t mpf_termination_vtable_t;
+
+/** Table of termination virtual methods */
+struct mpf_termination_vtable_t {
+       /** Virtual termination destroy method */
+       apt_bool_t (*destroy)(mpf_termination_t *termination);
+       /** Virtual termination modify method */
+       apt_bool_t (*modify)(mpf_termination_t *termination, void *descriptor);
+};
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_TYPES_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_user.h b/libs/unimrcp/libs/mpf/include/mpf_user.h
new file mode 100644 (file)
index 0000000..0d6ab83
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPF_USER_H__
+#define __MPF_USER_H__
+
+/**
+ * @file mpf_user.h
+ * @brief MPF User Interface
+ */ 
+
+#include "mpf_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/**
+ * Create MPF context.
+ * @param obj the external object associated with context
+ * @param max_termination_count the max number of terminations in context
+ * @param pool the pool to allocate memory from
+ */
+MPF_DECLARE(mpf_context_t*) mpf_context_create(void *obj, apr_size_t max_termination_count, apr_pool_t *pool);
+
+/**
+ * Destroy MPF context.
+ * @param context the context to destroy
+ */
+MPF_DECLARE(apt_bool_t) mpf_context_destroy(mpf_context_t *context);
+
+/**
+ * Get external object associated with MPF context.
+ * @param context the context to get object from
+ */
+MPF_DECLARE(void*) mpf_context_object_get(mpf_context_t *context);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_USER_H__*/
diff --git a/libs/unimrcp/libs/mpf/mpf.vcproj b/libs/unimrcp/libs/mpf/mpf.vcproj
new file mode 100644 (file)
index 0000000..4dd2794
--- /dev/null
@@ -0,0 +1,363 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="mpf"\r
+       ProjectGUID="{B5A00BFA-6083-4FAE-A097-71642D6473B5}"\r
+       RootNamespace="mpf"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       ConfigurationType="4"\r
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\mpf.vsprops"\r
+                       CharacterSet="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="codecs"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLibrarianTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       ConfigurationType="4"\r
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\mpf.vsprops"\r
+                       CharacterSet="1"\r
+                       WholeProgramOptimization="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="codecs"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLibrarianTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="codecs"\r
+                       >\r
+                       <Filter\r
+                               Name="g711"\r
+                               >\r
+                               <File\r
+                                       RelativePath=".\codecs\g711\g711.c"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath=".\codecs\g711\g711.h"\r
+                                       >\r
+                               </File>\r
+                       </Filter>\r
+               </Filter>\r
+               <Filter\r
+                       Name="include"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\include\mpf.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_activity_detector.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_audio_file_descriptor.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_audio_file_stream.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_bridge.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_buffer.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_codec.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_codec_descriptor.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_codec_manager.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_context.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_decoder.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_encoder.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_engine.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_file_termination_factory.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_frame.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_jitter_buffer.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_media_descriptor.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_message.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_object.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_rtp_attribs.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_rtp_defs.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_rtp_descriptor.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_rtp_header.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_rtp_stat.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_rtp_stream.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_rtp_termination_factory.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_stream.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_stream_mode.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_termination.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_timer.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_types.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_user.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="src"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\src\mpf_activity_detector.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_audio_file_stream.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_bridge.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_buffer.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_codec_descriptor.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_codec_g711.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_codec_linear.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_codec_manager.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_context.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_decoder.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_encoder.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_engine.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_file_termination_factory.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_jitter_buffer.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_rtp_attribs.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_rtp_stream.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_rtp_termination_factory.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_termination.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_timer.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/libs/unimrcp/libs/mpf/src/mpf_activity_detector.c b/libs/unimrcp/libs/mpf/src/mpf_activity_detector.c
new file mode 100644 (file)
index 0000000..1b40c84
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mpf_activity_detector.h"
+#include "apt_log.h"
+
+/** Detector states */
+typedef enum {
+       DETECTOR_STATE_INACTIVITY,           /**< inactivity detected */
+       DETECTOR_STATE_ACTIVITY_TRANSITION,  /**< activity detection is in-progress */
+       DETECTOR_STATE_ACTIVITY,             /**< activity detected */
+       DETECTOR_STATE_INACTIVITY_TRANSITION /**< inactivity detection is in-progress */
+} mpf_detector_state_e;
+
+/** Activity detector */
+struct mpf_activity_detector_t {
+       /* voice activity (silence) level threshold */
+       apr_size_t level_threshold;
+
+       /* period of activity/inactivity required to complete/raise an event */
+       apr_size_t complete_timeout;
+       /* noinput timeout */
+       apr_size_t noinput_timeout;
+
+       /* current state */
+       apt_bool_t state;
+       /* duration spent in current state  */
+       apr_size_t duration;
+};
+
+/** Create activity detector */
+MPF_DECLARE(mpf_activity_detector_t*) mpf_activity_detector_create(apr_pool_t *pool)
+{
+       mpf_activity_detector_t *detector = apr_palloc(pool,sizeof(mpf_activity_detector_t));
+       detector->level_threshold = 2; /* 0 .. 255 */
+       detector->complete_timeout = 300; /* 0.3 s */
+       detector->noinput_timeout = 5000; /* 5 s */
+       detector->duration = 0;
+       detector->state = DETECTOR_STATE_INACTIVITY;
+       return detector;
+}
+
+/** Set threshold of voice activity (silence) level */
+MPF_DECLARE(void) mpf_activity_detector_level_set(mpf_activity_detector_t *detector, apr_size_t level_threshold)
+{
+       detector->level_threshold = level_threshold;
+}
+
+/** Set noinput timeout */
+MPF_DECLARE(void) mpf_activity_detector_noinput_timeout_set(mpf_activity_detector_t *detector, apr_size_t noinput_timeout)
+{
+       detector->noinput_timeout = noinput_timeout;
+}
+
+/** Set transition complete timeout */
+MPF_DECLARE(void) mpf_activity_detector_complete_timeout_set(mpf_activity_detector_t *detector, apr_size_t complete_timeout)
+{
+       detector->complete_timeout = complete_timeout;
+}
+
+
+static APR_INLINE void mpf_activity_detector_state_change(mpf_activity_detector_t *detector, mpf_detector_state_e state)
+{
+       detector->duration = 0;
+       detector->state = state;
+}
+
+static apr_size_t mpf_activity_detector_level_calculate(const mpf_frame_t *frame)
+{
+       apr_size_t sum = 0;
+       apr_size_t count = frame->codec_frame.size/2;
+       const apr_int16_t *cur = frame->codec_frame.buffer;
+       const apr_int16_t *end = cur + count;
+
+       for(; cur < end; cur++) {
+               if(*cur < 0) {
+                       sum -= *cur;
+               }
+               else {
+                       sum += *cur;
+               }
+       }
+
+       return sum / count;
+}
+
+/** Process current frame */
+MPF_DECLARE(mpf_detector_event_e) mpf_activity_detector_process(mpf_activity_detector_t *detector, const mpf_frame_t *frame)
+{
+       mpf_detector_event_e det_event = MPF_DETECTOR_EVENT_NONE;
+       apr_size_t level = 0;
+       if((frame->type & MEDIA_FRAME_TYPE_AUDIO) == MEDIA_FRAME_TYPE_AUDIO) {
+               /* first, calculate current activity level of processed frame */
+               level = mpf_activity_detector_level_calculate(frame);
+#if 0
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Activity Detector [%d]",level);
+#endif
+       }
+
+       if(detector->state == DETECTOR_STATE_INACTIVITY) {
+               if(level >= detector->level_threshold) {
+                       /* start to detect activity */
+                       mpf_activity_detector_state_change(detector,DETECTOR_STATE_ACTIVITY_TRANSITION);
+               }
+               else {
+                       detector->duration += CODEC_FRAME_TIME_BASE;
+                       if(detector->duration >= detector->noinput_timeout) {
+                               /* detected noinput */
+                               det_event = MPF_DETECTOR_EVENT_NOINPUT;
+                       }
+               }
+       }
+       else if(detector->state == DETECTOR_STATE_ACTIVITY_TRANSITION) {
+               if(level >= detector->level_threshold) {
+                       detector->duration += CODEC_FRAME_TIME_BASE;
+                       if(detector->duration >= detector->complete_timeout) {
+                               /* finally detected activity */
+                               det_event = MPF_DETECTOR_EVENT_ACTIVITY;
+                               mpf_activity_detector_state_change(detector,DETECTOR_STATE_ACTIVITY);
+                       }
+               }
+               else {
+                       /* fallback to inactivity */
+                       mpf_activity_detector_state_change(detector,DETECTOR_STATE_INACTIVITY);
+               }
+       }
+       else if(detector->state == DETECTOR_STATE_ACTIVITY) {
+               if(level >= detector->level_threshold) {
+                       detector->duration += CODEC_FRAME_TIME_BASE;
+               }
+               else {
+                       /* start to detect inactivity */
+                       mpf_activity_detector_state_change(detector,DETECTOR_STATE_INACTIVITY_TRANSITION);
+               }
+       }
+       else if(detector->state == DETECTOR_STATE_INACTIVITY_TRANSITION) {
+               if(level >= detector->level_threshold) {
+                       /* fallback to activity */
+                       mpf_activity_detector_state_change(detector,DETECTOR_STATE_ACTIVITY);
+               }
+               else {
+                       detector->duration += CODEC_FRAME_TIME_BASE;
+                       if(detector->duration >= detector->complete_timeout) {
+                               /* detected inactivity */
+                               det_event = MPF_DETECTOR_EVENT_INACTIVITY;
+                               mpf_activity_detector_state_change(detector,DETECTOR_STATE_INACTIVITY);
+                       }
+               }
+       }
+
+       return det_event;
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_audio_file_stream.c b/libs/unimrcp/libs/mpf/src/mpf_audio_file_stream.c
new file mode 100644 (file)
index 0000000..e52d156
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mpf_audio_file_stream.h"
+#include "mpf_termination.h"
+#include "mpf_frame.h"
+#include "mpf_codec_manager.h"
+#include "apt_log.h"
+
+/** Audio file stream */
+typedef struct mpf_audio_file_stream_t mpf_audio_file_stream_t;
+struct mpf_audio_file_stream_t {
+       mpf_audio_stream_t *audio_stream;
+
+       FILE               *read_handle;
+       FILE               *write_handle;
+
+       apt_bool_t          eof;
+       apr_size_t          max_write_size;
+       apr_size_t          cur_write_size;
+};
+
+static APR_INLINE void mpf_audio_file_event_raise(mpf_audio_stream_t *stream, int event_id, void *descriptor);
+
+
+static apt_bool_t mpf_audio_file_destroy(mpf_audio_stream_t *stream)
+{
+       mpf_audio_file_stream_t *file_stream = stream->obj;
+       if(file_stream->read_handle) {
+               fclose(file_stream->read_handle);
+               file_stream->read_handle = NULL;
+       }
+       if(file_stream->write_handle) {
+               fclose(file_stream->write_handle);
+               file_stream->write_handle = NULL;
+       }
+       return TRUE;
+}
+
+static apt_bool_t mpf_audio_file_reader_open(mpf_audio_stream_t *stream)
+{
+       return TRUE;
+}
+
+static apt_bool_t mpf_audio_file_reader_close(mpf_audio_stream_t *stream)
+{
+       return TRUE;
+}
+
+static apt_bool_t mpf_audio_file_frame_read(mpf_audio_stream_t *stream, mpf_frame_t *frame)
+{
+       mpf_audio_file_stream_t *file_stream = stream->obj;
+       if(file_stream->read_handle && file_stream->eof == FALSE) {
+               if(fread(frame->codec_frame.buffer,1,frame->codec_frame.size,file_stream->read_handle) == frame->codec_frame.size) {
+                       frame->type = MEDIA_FRAME_TYPE_AUDIO;
+               }
+               else {
+                       file_stream->eof = TRUE;
+                       mpf_audio_file_event_raise(stream,0,NULL);
+               }
+       }
+       return TRUE;
+}
+
+
+static apt_bool_t mpf_audio_file_writer_open(mpf_audio_stream_t *stream)
+{
+       return TRUE;
+}
+
+static apt_bool_t mpf_audio_file_writer_close(mpf_audio_stream_t *stream)
+{
+       return TRUE;
+}
+
+static apt_bool_t mpf_audio_file_frame_write(mpf_audio_stream_t *stream, const mpf_frame_t *frame)
+{
+       mpf_audio_file_stream_t *file_stream = stream->obj;
+       if(file_stream->write_handle && 
+               (!file_stream->max_write_size || file_stream->cur_write_size < file_stream->max_write_size)) {
+               file_stream->cur_write_size += fwrite(
+                                                                               frame->codec_frame.buffer,
+                                                                               1,
+                                                                               frame->codec_frame.size,
+                                                                               file_stream->write_handle);
+               if(file_stream->cur_write_size >= file_stream->max_write_size) {
+                       mpf_audio_file_event_raise(stream,0,NULL);
+               }
+       }
+       return TRUE;
+}
+
+static const mpf_audio_stream_vtable_t vtable = {
+       mpf_audio_file_destroy,
+       mpf_audio_file_reader_open,
+       mpf_audio_file_reader_close,
+       mpf_audio_file_frame_read,
+       mpf_audio_file_writer_open,
+       mpf_audio_file_writer_close,
+       mpf_audio_file_frame_write
+};
+
+MPF_DECLARE(mpf_audio_stream_t*) mpf_file_stream_create(mpf_termination_t *termination, apr_pool_t *pool)
+{
+       mpf_audio_file_stream_t *file_stream = apr_palloc(pool,sizeof(mpf_audio_file_stream_t));
+       file_stream->audio_stream = mpf_audio_stream_create(file_stream,&vtable,STREAM_MODE_NONE,pool);
+       file_stream->audio_stream->termination = termination;
+
+       file_stream->write_handle = NULL;
+       file_stream->read_handle = NULL;
+       file_stream->eof = FALSE;
+       file_stream->max_write_size = 0;
+       file_stream->cur_write_size = 0;
+       return file_stream->audio_stream;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_file_stream_modify(mpf_audio_stream_t *stream, mpf_audio_file_descriptor_t *descriptor)
+{
+       mpf_audio_file_stream_t *file_stream = stream->obj;
+       if(descriptor->mask & FILE_READER) {
+               if(file_stream->read_handle) {
+                       fclose(file_stream->read_handle);
+               }
+               file_stream->read_handle = descriptor->read_handle;
+               file_stream->eof = FALSE;
+               stream->mode |= FILE_READER;
+
+               stream->rx_codec = mpf_codec_manager_codec_get(
+                                                               stream->termination->codec_manager,
+                                                               &descriptor->codec_descriptor,
+                                                               stream->termination->pool);
+       }
+       if(descriptor->mask & FILE_WRITER) {
+               if(file_stream->write_handle) {
+                       fclose(file_stream->write_handle);
+               }
+               file_stream->write_handle = descriptor->write_handle;
+               file_stream->max_write_size = descriptor->max_write_size;
+               file_stream->cur_write_size = 0;
+               stream->mode |= FILE_WRITER;
+
+               stream->tx_codec = mpf_codec_manager_codec_get(
+                                                               stream->termination->codec_manager,
+                                                               &descriptor->codec_descriptor,
+                                                               stream->termination->pool);
+       }
+       return TRUE;
+}
+
+static APR_INLINE void mpf_audio_file_event_raise(mpf_audio_stream_t *stream, int event_id, void *descriptor)
+{
+       if(stream->termination->event_handler) {
+               stream->termination->event_handler(stream->termination,event_id,descriptor);
+       }
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_bridge.c b/libs/unimrcp/libs/mpf/src/mpf_bridge.c
new file mode 100644 (file)
index 0000000..45aa1c7
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mpf_bridge.h"
+#include "mpf_stream.h"
+#include "apt_log.h"
+
+static apt_bool_t mpf_bridge_process(mpf_object_t *object)
+{
+       object->frame.type = MEDIA_FRAME_TYPE_NONE;
+       object->source->vtable->read_frame(object->source,&object->frame);
+       
+       if((object->frame.type & MEDIA_FRAME_TYPE_AUDIO) == 0) {
+               memset( object->frame.codec_frame.buffer,
+                               0,
+                               object->frame.codec_frame.size);
+       }
+
+       object->sink->vtable->write_frame(object->sink,&object->frame);
+       return TRUE;
+}
+
+static apt_bool_t mpf_null_bridge_process(mpf_object_t *object)
+{
+       object->frame.type = MEDIA_FRAME_TYPE_NONE;
+       object->source->vtable->read_frame(object->source,&object->frame);
+       object->sink->vtable->write_frame(object->sink,&object->frame);
+       return TRUE;
+}
+
+
+static apt_bool_t mpf_bridge_destroy(mpf_object_t *object)
+{
+       mpf_object_t *bridge = object;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Destroy Audio Bridge");
+       mpf_audio_stream_rx_close(bridge->source);
+       mpf_audio_stream_tx_close(bridge->sink);
+       return TRUE;
+}
+
+static mpf_object_t* mpf_bridge_base_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, apr_pool_t *pool)
+{
+       mpf_object_t *bridge;
+       if(!source || !sink) {
+               return NULL;
+       }
+
+       bridge = apr_palloc(pool,sizeof(mpf_object_t));
+       bridge->source = source;
+       bridge->sink = sink;
+       bridge->process = mpf_bridge_process;
+       bridge->destroy = mpf_bridge_destroy;
+
+       if(mpf_audio_stream_rx_open(source) == FALSE) {
+               return NULL;
+       }
+       if(mpf_audio_stream_tx_open(sink) == FALSE) {
+               mpf_audio_stream_rx_close(source);
+               return NULL;
+       }
+       return bridge;
+}
+
+MPF_DECLARE(mpf_object_t*) mpf_bridge_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, apr_pool_t *pool)
+{
+       mpf_codec_descriptor_t *descriptor;
+       apr_size_t frame_size;
+       mpf_object_t *bridge;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Create Audio Bridge");
+       bridge = mpf_bridge_base_create(source,sink,pool);
+       if(!bridge) {
+               return NULL;
+       }
+
+       descriptor = source->rx_codec->descriptor;
+       frame_size = mpf_codec_linear_frame_size_calculate(descriptor->sampling_rate,descriptor->channel_count);
+       bridge->frame.codec_frame.size = frame_size;
+       bridge->frame.codec_frame.buffer = apr_palloc(pool,frame_size);
+       return bridge;
+}
+
+MPF_DECLARE(mpf_object_t*) mpf_null_bridge_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, apr_pool_t *pool)
+{
+       mpf_codec_t *codec;
+       apr_size_t frame_size;
+       mpf_object_t *bridge;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Create Audio Null Bridge");
+       bridge = mpf_bridge_base_create(source,sink,pool);
+       if(!bridge) {
+               return NULL;
+       }
+       bridge->process = mpf_null_bridge_process;
+
+       codec = source->rx_codec;
+       frame_size = mpf_codec_frame_size_calculate(codec->descriptor,codec->attribs);
+       bridge->frame.codec_frame.size = frame_size;
+       bridge->frame.codec_frame.buffer = apr_palloc(pool,frame_size);
+       return bridge;
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_buffer.c b/libs/unimrcp/libs/mpf/src/mpf_buffer.c
new file mode 100644 (file)
index 0000000..f128760
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef WIN32
+#pragma warning(disable: 4127)
+#endif
+#include <apr_ring.h>
+#include "mpf_buffer.h"
+
+typedef struct mpf_chunk_t mpf_chunk_t;
+
+struct mpf_chunk_t {
+       APR_RING_ENTRY(mpf_chunk_t) link;
+       mpf_frame_t                 frame;
+};
+
+struct mpf_buffer_t {
+       APR_RING_HEAD(mpf_chunk_head_t, mpf_chunk_t) head;
+       mpf_chunk_t                                 *cur_chunk;
+       apr_size_t                                   remaining_chunk_size;
+       apr_thread_mutex_t                          *guard;
+       apr_pool_t                                  *pool;
+       apr_size_t                                   size; /* total size */
+};
+
+mpf_buffer_t* mpf_buffer_create(apr_pool_t *pool)
+{
+       mpf_buffer_t *buffer = apr_palloc(pool,sizeof(mpf_buffer_t));
+       buffer->pool = pool;
+       buffer->cur_chunk = NULL;
+       buffer->remaining_chunk_size = 0;
+       buffer->size = 0;
+       APR_RING_INIT(&buffer->head, mpf_chunk_t, link);
+       apr_thread_mutex_create(&buffer->guard,APR_THREAD_MUTEX_UNNESTED,pool);
+       return buffer;
+}
+
+void mpf_buffer_destroy(mpf_buffer_t *buffer)
+{
+       if(buffer->guard) {
+               apr_thread_mutex_destroy(buffer->guard);
+               buffer->guard = NULL;
+       }
+}
+
+apt_bool_t mpf_buffer_restart(mpf_buffer_t *buffer)
+{
+       apr_thread_mutex_lock(buffer->guard);
+       APR_RING_INIT(&buffer->head, mpf_chunk_t, link);
+       apr_thread_mutex_unlock(buffer->guard);
+       return TRUE;
+}
+
+static APR_INLINE apt_bool_t mpf_buffer_chunk_write(mpf_buffer_t *buffer, mpf_chunk_t *chunk)
+{
+       APR_RING_INSERT_TAIL(&buffer->head,chunk,mpf_chunk_t,link);
+       return TRUE;
+}
+
+static APR_INLINE mpf_chunk_t* mpf_buffer_chunk_read(mpf_buffer_t *buffer)
+{
+       mpf_chunk_t *chunk = NULL;
+       if(!APR_RING_EMPTY(&buffer->head,mpf_chunk_t,link)) {
+               chunk = APR_RING_FIRST(&buffer->head);
+               APR_RING_REMOVE(chunk,link);
+       }
+       return chunk;
+}
+
+apt_bool_t mpf_buffer_audio_write(mpf_buffer_t *buffer, void *data, apr_size_t size)
+{
+       mpf_chunk_t *chunk;
+       apt_bool_t status = TRUE;
+       apr_thread_mutex_lock(buffer->guard);
+
+       chunk = apr_palloc(buffer->pool,sizeof(mpf_chunk_t));
+       chunk->frame.codec_frame.buffer = apr_palloc(buffer->pool,size);
+       memcpy(chunk->frame.codec_frame.buffer,data,size);
+       chunk->frame.codec_frame.size = size;
+       chunk->frame.type = MEDIA_FRAME_TYPE_AUDIO;
+       status = mpf_buffer_chunk_write(buffer,chunk);
+       
+       buffer->size += size;
+       apr_thread_mutex_unlock(buffer->guard);
+       return status;
+}
+
+apt_bool_t mpf_buffer_event_write(mpf_buffer_t *buffer, mpf_frame_type_e event_type)
+{
+       mpf_chunk_t *chunk;
+       apt_bool_t status = TRUE;
+       apr_thread_mutex_lock(buffer->guard);
+
+       chunk = apr_palloc(buffer->pool,sizeof(mpf_chunk_t));
+       chunk->frame.codec_frame.buffer = NULL;
+       chunk->frame.codec_frame.size = 0;
+       chunk->frame.type = event_type;
+       status = mpf_buffer_chunk_write(buffer,chunk);
+       
+       apr_thread_mutex_unlock(buffer->guard);
+       return status;
+}
+
+apt_bool_t mpf_buffer_frame_read(mpf_buffer_t *buffer, mpf_frame_t *media_frame)
+{
+       mpf_codec_frame_t *dest;
+       mpf_codec_frame_t *src;
+       apr_size_t remaining_frame_size = media_frame->codec_frame.size;
+       apr_thread_mutex_lock(buffer->guard);
+       do {
+               if(!buffer->cur_chunk) {
+                       buffer->cur_chunk = mpf_buffer_chunk_read(buffer);
+                       if(!buffer->cur_chunk) {
+                               /* buffer is empty */
+                               break;
+                       }
+                       buffer->remaining_chunk_size = buffer->cur_chunk->frame.codec_frame.size;
+               }
+
+               dest = &media_frame->codec_frame;
+               src = &buffer->cur_chunk->frame.codec_frame;
+               media_frame->type |= buffer->cur_chunk->frame.type;
+               if(remaining_frame_size < buffer->remaining_chunk_size) {
+                       /* copy remaining_frame_size */
+                       memcpy(
+                               (char*)dest->buffer + dest->size - remaining_frame_size,
+                               (char*)src->buffer + src->size - buffer->remaining_chunk_size,
+                               remaining_frame_size);
+                       buffer->remaining_chunk_size -= remaining_frame_size;
+                       buffer->size -= remaining_frame_size;
+                       remaining_frame_size = 0;
+               }
+               else {
+                       /* copy remaining_chunk_size and proceed to the next chunk */
+                       memcpy(
+                               (char*)dest->buffer + dest->size - remaining_frame_size,
+                               (char*)src->buffer + src->size - buffer->remaining_chunk_size,
+                               buffer->remaining_chunk_size);
+                       remaining_frame_size -= buffer->remaining_chunk_size;
+                       buffer->size -= buffer->remaining_chunk_size;
+                       buffer->remaining_chunk_size = 0;
+                       buffer->cur_chunk = NULL;
+               }
+       }
+       while(remaining_frame_size);
+
+       if(remaining_frame_size) {
+               apr_size_t offset = media_frame->codec_frame.size - remaining_frame_size;
+               memset((char*)media_frame->codec_frame.buffer + offset, 0, remaining_frame_size);
+       }
+       apr_thread_mutex_unlock(buffer->guard);
+       return TRUE;
+}
+
+apr_size_t mpf_buffer_get_size(mpf_buffer_t *buffer)
+{
+       return buffer->size;
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_codec_descriptor.c b/libs/unimrcp/libs/mpf/src/mpf_codec_descriptor.c
new file mode 100644 (file)
index 0000000..0a811ac
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mpf_codec_descriptor.h"
+
+/** Match two codec descriptors */
+MPF_DECLARE(apt_bool_t) mpf_codec_descriptor_match(const mpf_codec_descriptor_t *descriptor1, const mpf_codec_descriptor_t *descriptor2)
+{
+       apt_bool_t match = FALSE;
+       if(descriptor1->payload_type < 96 && descriptor2->payload_type < 96) {
+               if(descriptor1->payload_type == descriptor2->payload_type) {
+                       match = TRUE;
+               }
+       }
+       else {
+               if(apt_string_compare(&descriptor1->name,&descriptor2->name) == TRUE) {
+                       if(descriptor1->sampling_rate == descriptor2->sampling_rate && 
+                               descriptor1->channel_count == descriptor2->channel_count) {
+                               match = TRUE;
+                       }
+               }
+       }
+       return match;
+}
+
+/** Intersect two codec lists */
+MPF_DECLARE(apt_bool_t) mpf_codec_list_intersect(mpf_codec_list_t *codec_list1, mpf_codec_list_t *codec_list2)
+{
+       int i;
+       int j;
+       mpf_codec_descriptor_t *descriptor1;
+       mpf_codec_descriptor_t *descriptor2;
+       codec_list1->preffered = NULL;
+       codec_list2->preffered = NULL;
+       /* find only one match, set the matched codec as preffered, disable the others */
+       for(i=0; i<codec_list1->descriptor_arr->nelts; i++) {
+               descriptor1 = (mpf_codec_descriptor_t*)codec_list1->descriptor_arr->elts + i;
+               if(codec_list1->preffered) {
+                       descriptor1->enabled = FALSE;
+                       continue;
+               }
+
+               for(j=0; j<codec_list2->descriptor_arr->nelts; j++) {
+                       descriptor2 = (mpf_codec_descriptor_t*)codec_list2->descriptor_arr->elts + j;
+
+                       descriptor1->enabled = mpf_codec_descriptor_match(descriptor1,descriptor2);
+                       if(descriptor1->enabled == TRUE) {
+                               codec_list1->preffered = descriptor1;
+                               codec_list2->preffered = descriptor2;
+                               break;
+                       }
+               }
+       }
+       for(j=0; j<codec_list2->descriptor_arr->nelts; j++) {
+               descriptor2 = (mpf_codec_descriptor_t*)codec_list2->descriptor_arr->elts + j;
+               descriptor2->enabled = (codec_list2->preffered == descriptor2) ? TRUE : FALSE;
+       }
+
+       return TRUE;
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_codec_g711.c b/libs/unimrcp/libs/mpf/src/mpf_codec_g711.c
new file mode 100644 (file)
index 0000000..c2feefa
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mpf_codec.h"
+#include "g711/g711.h"
+
+#define G711u_CODEC_NAME        "PCMU"
+#define G711u_CODEC_NAME_LENGTH (sizeof(G711u_CODEC_NAME)-1)
+
+#define G711a_CODEC_NAME        "PCMA"
+#define G711a_CODEC_NAME_LENGTH (sizeof(G711a_CODEC_NAME)-1)
+
+static apt_bool_t g711_open(mpf_codec_t *codec)
+{
+       return TRUE;
+}
+
+static apt_bool_t g711_close(mpf_codec_t *codec)
+{
+       return TRUE;
+}
+
+static apt_bool_t g711u_encode(mpf_codec_t *codec, const mpf_codec_frame_t *frame_in, mpf_codec_frame_t *frame_out)
+{
+       const short *decode_buf;
+       unsigned char *encode_buf;
+       apr_uint32_t i;
+
+       decode_buf = frame_in->buffer;
+       encode_buf = frame_out->buffer;
+
+       frame_out->size = frame_in->size / sizeof(short);
+
+       for(i=0; i<frame_out->size; i++) {
+               encode_buf[i] = linear_to_ulaw(decode_buf[i]);
+       }
+
+       return TRUE;
+}
+
+static apt_bool_t g711u_decode(mpf_codec_t *codec, const mpf_codec_frame_t *frame_in, mpf_codec_frame_t *frame_out)
+{
+       short *decode_buf;
+       const unsigned char *encode_buf;
+       apr_uint32_t i;
+
+       decode_buf = frame_out->buffer;
+       encode_buf = frame_in->buffer;
+
+       frame_out->size = frame_in->size * sizeof(short);
+
+       for(i=0; i<frame_in->size; i++) {
+               decode_buf[i] = ulaw_to_linear(encode_buf[i]);
+       }
+
+       return TRUE;
+}
+
+static apt_bool_t g711a_encode(mpf_codec_t *codec, const mpf_codec_frame_t *frame_in, mpf_codec_frame_t *frame_out)
+{
+       const short *decode_buf;
+       unsigned char *encode_buf;
+       apr_uint32_t i;
+
+       decode_buf = frame_in->buffer;
+       encode_buf = frame_out->buffer;
+
+       frame_out->size = frame_in->size / sizeof(short);
+
+       for(i=0; i<frame_out->size; i++) {
+               encode_buf[i] = linear_to_alaw(decode_buf[i]);
+       }
+
+       return TRUE;
+}
+
+static apt_bool_t g711a_decode(mpf_codec_t *codec, const mpf_codec_frame_t *frame_in, mpf_codec_frame_t *frame_out)
+{
+       short *decode_buf;
+       const unsigned char *encode_buf;
+       apr_uint32_t i;
+
+       decode_buf = frame_out->buffer;
+       encode_buf = frame_in->buffer;
+
+       frame_out->size = frame_in->size * sizeof(short);
+
+       for(i=0; i<frame_in->size; i++) {
+               decode_buf[i] = alaw_to_linear(encode_buf[i]);
+       }
+
+       return TRUE;
+}
+
+static const mpf_codec_vtable_t g711u_vtable = {
+       g711_open,
+       g711_close,
+       g711u_encode,
+       g711u_decode,
+       NULL
+};
+
+static const mpf_codec_vtable_t g711a_vtable = {
+       g711_open,
+       g711_close,
+       g711a_encode,
+       g711a_decode,
+       NULL
+};
+
+static const mpf_codec_descriptor_t g711u_descriptor = {
+       0,
+       {G711u_CODEC_NAME, G711u_CODEC_NAME_LENGTH},
+       8000,
+       1,
+       NULL,
+       TRUE
+};
+
+static const mpf_codec_descriptor_t g711a_descriptor = {
+       8,
+       {G711a_CODEC_NAME, G711a_CODEC_NAME_LENGTH},
+       8000,
+       1,
+       NULL,
+       TRUE
+};
+
+static const mpf_codec_attribs_t g711u_attribs = {
+       {G711u_CODEC_NAME, G711u_CODEC_NAME_LENGTH}, /* codec name */
+       8,                                           /* bits per sample */
+       MPF_SAMPLE_RATE_8000 | MPF_SAMPLE_RATE_16000 /* sampling rates */
+};
+
+static const mpf_codec_attribs_t g711a_attribs = {
+       {G711a_CODEC_NAME, G711a_CODEC_NAME_LENGTH}, /* codec name */
+       8,                                           /* bits per sample */
+       MPF_SAMPLE_RATE_8000 | MPF_SAMPLE_RATE_16000 /* sampling rates */
+};
+
+mpf_codec_t* mpf_codec_g711u_create(apr_pool_t *pool)
+{
+       return mpf_codec_create(&g711u_vtable,&g711u_attribs,&g711u_descriptor,pool);
+}
+
+mpf_codec_t* mpf_codec_g711a_create(apr_pool_t *pool)
+{
+       return mpf_codec_create(&g711a_vtable,&g711a_attribs,&g711a_descriptor,pool);
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_codec_linear.c b/libs/unimrcp/libs/mpf/src/mpf_codec_linear.c
new file mode 100644 (file)
index 0000000..f2aa0a7
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mpf_codec.h"
+
+#define L16_CODEC_NAME        "L16"
+#define L16_CODEC_NAME_LENGTH (sizeof(L16_CODEC_NAME)-1)
+
+static const mpf_codec_vtable_t l16_vtable = {
+       NULL
+};
+
+static const mpf_codec_descriptor_t l16_descriptor = {
+       96, /* not specified */
+       {L16_CODEC_NAME, L16_CODEC_NAME_LENGTH},
+       8000,
+       1,
+       NULL,
+       TRUE
+};
+
+static const mpf_codec_attribs_t l16_attribs = {
+       {L16_CODEC_NAME, L16_CODEC_NAME_LENGTH},     /* codec name */
+       16,                                          /* bits per sample */
+       MPF_SAMPLE_RATE_8000 | MPF_SAMPLE_RATE_16000 /* sampling rates */
+};
+
+mpf_codec_t* mpf_codec_l16_create(apr_pool_t *pool)
+{
+       return mpf_codec_create(&l16_vtable,&l16_attribs,NULL,pool);
+}
+
+const mpf_codec_descriptor_t* l16_descriptor_get()
+{
+       return &l16_descriptor;
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_codec_manager.c b/libs/unimrcp/libs/mpf/src/mpf_codec_manager.c
new file mode 100644 (file)
index 0000000..3492cb2
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include "mpf_codec_manager.h"
+#include "apt_log.h"
+
+
+struct mpf_codec_manager_t {
+       /** Memory pool */
+       apr_pool_t   *pool;
+
+       /** Dynamic array of codecs (mpf_codec_t*) */
+       apr_array_header_t *codec_arr;
+};
+
+
+MPF_DECLARE(mpf_codec_manager_t*) mpf_codec_manager_create(apr_size_t codec_count, apr_pool_t *pool)
+{
+       mpf_codec_manager_t *codec_manager = apr_palloc(pool,sizeof(mpf_codec_manager_t));
+       codec_manager->pool = pool;
+       codec_manager->codec_arr = apr_array_make(pool,(int)codec_count,sizeof(mpf_codec_t*));
+       return codec_manager;
+}
+
+MPF_DECLARE(void) mpf_codec_manager_destroy(mpf_codec_manager_t *codec_manager)
+{
+       /* nothing to do */
+}
+
+MPF_DECLARE(apt_bool_t) mpf_codec_manager_codec_register(mpf_codec_manager_t *codec_manager, mpf_codec_t *codec)
+{
+       mpf_codec_t **slot;
+       if(!codec || !codec->attribs || !codec->attribs->name.buf) {
+               return FALSE;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Codec [%s]",codec->attribs->name.buf);
+
+       slot = apr_array_push(codec_manager->codec_arr);
+       *slot = codec;
+       return TRUE;
+}
+
+MPF_DECLARE(mpf_codec_t*) mpf_codec_manager_codec_get(const mpf_codec_manager_t *codec_manager, mpf_codec_descriptor_t *descriptor, apr_pool_t *pool)
+{
+       int i;
+       mpf_codec_t *codec = NULL;
+       mpf_codec_t *ret_codec = NULL;
+       if(!descriptor) {
+               return NULL;
+       }
+
+       for(i=0; i<codec_manager->codec_arr->nelts; i++) {
+               codec = ((mpf_codec_t**)codec_manager->codec_arr->elts)[i];
+               if(descriptor->payload_type < 96) {
+                       if(codec->static_descriptor && codec->static_descriptor->payload_type == descriptor->payload_type) {
+                               descriptor->name = codec->static_descriptor->name;
+                               descriptor->sampling_rate = codec->static_descriptor->sampling_rate;
+                               descriptor->channel_count = codec->static_descriptor->channel_count;
+                               break;
+                       }
+               }
+               else {
+                       if(apt_string_compare(&codec->attribs->name,&descriptor->name) == TRUE) {
+                               /* sampling rate must be checked as well */
+                               break;
+                       }
+               }
+       }
+
+       if(i == codec_manager->codec_arr->nelts) {
+               /* no match found */
+               return NULL;
+       }
+       if(codec) {
+               ret_codec = mpf_codec_clone(codec,pool);
+               ret_codec->descriptor = descriptor;
+       }
+       return ret_codec;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_codec_manager_codec_list_get(const mpf_codec_manager_t *codec_manager, mpf_codec_list_t *codec_list, apr_pool_t *pool)
+{
+       const mpf_codec_descriptor_t *static_descriptor;
+       mpf_codec_descriptor_t *descriptor;
+       int i;
+       mpf_codec_t *codec;
+
+       mpf_codec_list_init(codec_list,codec_manager->codec_arr->nelts,pool);
+       for(i=0; i<codec_manager->codec_arr->nelts; i++) {
+               codec = ((mpf_codec_t**)codec_manager->codec_arr->elts)[i];
+               static_descriptor = codec->static_descriptor;
+               if(static_descriptor) {
+                       descriptor = mpf_codec_list_add(codec_list);
+                       if(descriptor) {
+                               *descriptor = *static_descriptor;
+                       }
+               }
+       }
+       return TRUE;
+}
+
+static apt_bool_t mpf_codec_manager_codec_parse(const mpf_codec_manager_t *codec_manager, mpf_codec_list_t *codec_list, char *codec_desc_str, apr_pool_t *pool)
+{
+       const mpf_codec_t *codec;
+       mpf_codec_descriptor_t *descriptor;
+       const char *separator = "/";
+       char *state;
+       /* parse codec name */
+       char *str = apr_strtok(codec_desc_str, separator, &state);
+       codec_desc_str = NULL; /* make sure we pass NULL on subsequent calls of apr_strtok() */
+       if(str) {
+               apt_str_t name;
+               apt_string_assign(&name,str,pool);
+               /* find codec by name */
+               codec = mpf_codec_manager_codec_find(codec_manager,&name);
+               if(!codec) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Such Codec [%s]",str);
+                       return FALSE;
+               }
+
+               descriptor = mpf_codec_list_add(codec_list);
+               descriptor->name = name;
+
+               /* set defualt attributes */
+               if(codec->static_descriptor) {
+                       descriptor->payload_type = codec->static_descriptor->payload_type;
+                       descriptor->sampling_rate = codec->static_descriptor->sampling_rate;
+                       descriptor->channel_count = codec->static_descriptor->channel_count;
+               }
+               else {
+                       descriptor->payload_type = 96;
+                       descriptor->sampling_rate = 8000;
+                       descriptor->channel_count = 1;
+               }
+
+               /* parse optional payload type */
+               str = apr_strtok(codec_desc_str, separator, &state);
+               if(str) {
+                       descriptor->payload_type = (apr_byte_t)atol(str);
+
+                       /* parse optional sampling rate */
+                       str = apr_strtok(codec_desc_str, separator, &state);
+                       if(str) {
+                               descriptor->sampling_rate = (apr_uint16_t)atol(str);
+
+                               /* parse optional channel count */
+                               str = apr_strtok(codec_desc_str, separator, &state);
+                               if(str) {
+                                       descriptor->channel_count = (apr_byte_t)atol(str);
+                               }
+                       }
+               }
+       }
+       return TRUE;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_codec_manager_codec_list_load(const mpf_codec_manager_t *codec_manager, mpf_codec_list_t *codec_list, const char *str, apr_pool_t *pool)
+{
+       char *codec_desc_str;
+       char *state;
+       char *codec_list_str = apr_pstrdup(pool,str);
+       do {
+               codec_desc_str = apr_strtok(codec_list_str, " ", &state);
+               if(codec_desc_str) {
+                       mpf_codec_manager_codec_parse(codec_manager,codec_list,codec_desc_str,pool);
+               }
+               codec_list_str = NULL; /* make sure we pass NULL on subsequent calls of apr_strtok() */
+       } 
+       while(codec_desc_str);
+       return TRUE;
+}
+
+MPF_DECLARE(const mpf_codec_t*) mpf_codec_manager_codec_find(const mpf_codec_manager_t *codec_manager, const apt_str_t *codec_name)
+{
+       int i;
+       mpf_codec_t *codec;
+       for(i=0; i<codec_manager->codec_arr->nelts; i++) {
+               codec = ((mpf_codec_t**)codec_manager->codec_arr->elts)[i];
+               if(apt_string_compare(&codec->attribs->name,codec_name) == TRUE) {
+                       return codec;
+               }
+       }
+       return NULL;
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_context.c b/libs/unimrcp/libs/mpf/src/mpf_context.c
new file mode 100644 (file)
index 0000000..2f26148
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mpf_context.h"
+#include "mpf_termination.h"
+#include "mpf_stream.h"
+#include "mpf_encoder.h"
+#include "mpf_decoder.h"
+#include "mpf_bridge.h"
+#include "apt_log.h"
+
+static mpf_object_t* mpf_context_connection_create(mpf_context_t *context, mpf_termination_t *src_termination, mpf_termination_t *sink_termination);
+
+MPF_DECLARE(mpf_context_t*) mpf_context_create(void *obj, apr_size_t max_termination_count, apr_pool_t *pool)
+{
+       apr_size_t i,j;
+       mpf_context_t *context = apr_palloc(pool,sizeof(mpf_context_t));
+       context->obj = obj;
+       context->pool = pool;
+       context->elem = NULL;
+       context->max_termination_count = max_termination_count;
+       context->termination_count = 0;
+       context->table = apr_palloc(pool,sizeof(table_item_t)*max_termination_count);
+       for(i=0; i<max_termination_count; i++) {
+               context->table[i] = apr_palloc(pool,sizeof(table_item_t)*max_termination_count);
+               for(j=0; j<max_termination_count; j++) {
+                       context->table[i][j] = NULL;
+               }
+       }
+
+       return context;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_context_destroy(mpf_context_t *context)
+{
+       apr_size_t i;
+       apr_size_t count = context->max_termination_count;
+       mpf_termination_t *termination;
+       for(i=0; i<count; i++){
+               termination = context->table[i][i];
+               if(termination) {
+                       mpf_context_termination_subtract(context,termination);
+                       if(termination->audio_stream) {
+                               mpf_audio_stream_destroy(termination->audio_stream);
+                       }
+               }
+       }
+       return TRUE;
+}
+
+MPF_DECLARE(void*) mpf_context_object_get(mpf_context_t *context)
+{
+       return context->obj;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_context_termination_add(mpf_context_t *context, mpf_termination_t *termination)
+{
+       apr_size_t i;
+       apr_size_t count = context->max_termination_count;
+       for(i=0; i<count; i++) {
+               if(!context->table[i][i]) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add Termination");
+                       context->table[i][i] = termination;
+                       termination->slot = i;
+                       context->termination_count++;
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_context_termination_subtract(mpf_context_t *context, mpf_termination_t *termination)
+{
+       apr_size_t i = termination->slot;
+       if(i >= context->max_termination_count) {
+               return FALSE;
+       }
+       if(context->table[i][i] != termination) {
+               return FALSE;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Subtract Termination");
+       context->table[i][i] = NULL;
+       termination->slot = (apr_size_t)-1;
+       context->termination_count--;
+       return TRUE;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_context_process(mpf_context_t *context)
+{
+       mpf_object_t *object;
+       apr_size_t i,j;
+       for(i=0; i<context->max_termination_count; i++) {
+               for(j=0; j<context->max_termination_count; j++) {
+                       if(i==j) continue;
+
+                       object = context->table[i][j];
+                       if(object && object->process) {
+                               object->process(object);
+                       }
+               }
+       }
+       return TRUE;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_context_topology_apply(mpf_context_t *context, mpf_termination_t *termination)
+{
+       apr_size_t i,j;
+       mpf_object_t *object;
+       mpf_termination_t *sink_termination;
+       mpf_termination_t *source_termination;
+       if(context->termination_count <= 1) {
+               /* at least 2 terminations are required to apply topology on them */
+               return TRUE;
+       }
+
+       i = termination->slot;
+       for(j=0; j<context->max_termination_count; j++) {
+               if(i == j) continue;
+
+               sink_termination = context->table[j][j];
+               object = mpf_context_connection_create(context,termination,sink_termination);
+               if(object) {
+                       context->table[i][j] = object;
+               }
+       }
+
+       j = termination->slot;
+       for(i=0; i<context->max_termination_count; i++) {
+               if(i == j) continue;
+
+               source_termination = context->table[i][i];
+               object = mpf_context_connection_create(context,source_termination,termination);
+               if(object) {
+                       context->table[i][j] = object;
+               }
+       }
+
+       return TRUE;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_context_topology_destroy(mpf_context_t *context, mpf_termination_t *termination)
+{
+       apr_size_t i,j;
+       mpf_object_t *object;
+       if(context->termination_count <= 1) {
+               /* at least 2 terminations are required to destroy topology */
+               return TRUE;
+       }
+
+       i = termination->slot;
+       for(j=0; j<context->max_termination_count; j++) {
+               if(i == j) continue;
+
+               object = context->table[i][j];
+               if(object) {
+                       if(object->destroy) {
+                               object->destroy(object);
+                       }
+                       context->table[i][j] = NULL;
+               }
+       }
+
+       j = termination->slot;
+       for(i=0; i<context->max_termination_count; i++) {
+               if(i == j) continue;
+
+               object = context->table[i][j];
+               if(object) {
+                       if(object->destroy) {
+                               object->destroy(object);
+                       }
+                       context->table[i][j] = NULL;
+               }
+       }
+       return TRUE;
+}
+
+static mpf_object_t* mpf_context_connection_create(mpf_context_t *context, mpf_termination_t *src_termination, mpf_termination_t *sink_termination)
+{
+       mpf_object_t *object = NULL;
+       mpf_audio_stream_t *source;
+       mpf_audio_stream_t *sink;
+       if(!src_termination || !sink_termination) {
+               return NULL;
+       }
+       source = src_termination->audio_stream;
+       sink = sink_termination->audio_stream;
+       if(source && (source->mode & STREAM_MODE_RECEIVE) == STREAM_MODE_RECEIVE &&
+               sink && (sink->mode & STREAM_MODE_SEND) == STREAM_MODE_SEND) {
+               mpf_codec_t *rx_codec = source->rx_codec;
+               mpf_codec_t *tx_codec = sink->tx_codec;
+               if(rx_codec && tx_codec) {
+                       if(mpf_codec_descriptor_match(rx_codec->descriptor,tx_codec->descriptor) == TRUE) {
+                               object = mpf_null_bridge_create(source,sink,context->pool);
+                       }
+                       else {
+                               if(rx_codec->attribs->bits_per_samples != BITS_PER_SAMPLE) {
+                                       /* set decoder before bridge */
+                                       mpf_audio_stream_t *decoder = mpf_decoder_create(source,context->pool);
+                                       source = decoder;
+                               }
+                               if(tx_codec->attribs->bits_per_samples != BITS_PER_SAMPLE) {
+                                       /* set encoder after bridge */
+                                       mpf_audio_stream_t *encoder = mpf_encoder_create(sink,context->pool);
+                                       sink = encoder;
+                               }
+                               object = mpf_bridge_create(source,sink,context->pool);
+                       }
+               }
+       }
+       return object;
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_decoder.c b/libs/unimrcp/libs/mpf/src/mpf_decoder.c
new file mode 100644 (file)
index 0000000..2add5e4
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mpf_decoder.h"
+#include "apt_log.h"
+
+typedef struct mpf_decoder_t mpf_decoder_t;
+
+struct mpf_decoder_t {
+       mpf_audio_stream_t *base;
+       mpf_audio_stream_t *source;
+       mpf_frame_t         frame_in;
+};
+
+
+static apt_bool_t mpf_decoder_destroy(mpf_audio_stream_t *stream)
+{
+       mpf_decoder_t *decoder = stream->obj;
+       return mpf_audio_stream_destroy(decoder->source);
+}
+
+static apt_bool_t mpf_decoder_open(mpf_audio_stream_t *stream)
+{
+       mpf_decoder_t *decoder = stream->obj;
+       return mpf_audio_stream_rx_open(decoder->source);
+}
+
+static apt_bool_t mpf_decoder_close(mpf_audio_stream_t *stream)
+{
+       mpf_decoder_t *decoder = stream->obj;
+       return mpf_audio_stream_rx_close(decoder->source);
+}
+
+static apt_bool_t mpf_decoder_process(mpf_audio_stream_t *stream, mpf_frame_t *frame)
+{
+       mpf_decoder_t *decoder = stream->obj;
+       if(mpf_audio_stream_frame_read(decoder->source,&decoder->frame_in) != TRUE) {
+               return FALSE;
+       }
+
+       frame->type = decoder->frame_in.type;
+       if((frame->type & MEDIA_FRAME_TYPE_EVENT) == MEDIA_FRAME_TYPE_EVENT) {
+               frame->event_frame = decoder->frame_in.event_frame;
+       }
+       if((frame->type & MEDIA_FRAME_TYPE_AUDIO) == MEDIA_FRAME_TYPE_AUDIO) {
+               mpf_codec_decode(decoder->source->rx_codec,&decoder->frame_in.codec_frame,&frame->codec_frame);
+       }
+       return TRUE;
+}
+
+
+static const mpf_audio_stream_vtable_t vtable = {
+       mpf_decoder_destroy,
+       mpf_decoder_open,
+       mpf_decoder_close,
+       mpf_decoder_process,
+       NULL,
+       NULL,
+       NULL
+};
+
+MPF_DECLARE(mpf_audio_stream_t*) mpf_decoder_create(mpf_audio_stream_t *source, apr_pool_t *pool)
+{
+       apr_size_t frame_size;
+       mpf_codec_t *codec;
+       mpf_decoder_t *decoder;
+       if(!source || !source->rx_codec) {
+               return NULL;
+       }
+       decoder = apr_palloc(pool,sizeof(mpf_decoder_t));
+       decoder->base = mpf_audio_stream_create(decoder,&vtable,STREAM_MODE_RECEIVE,pool);
+       decoder->source = source;
+
+       codec = source->rx_codec;
+       frame_size = mpf_codec_frame_size_calculate(codec->descriptor,codec->attribs);
+       decoder->base->rx_codec = codec;
+       decoder->frame_in.codec_frame.size = frame_size;
+       decoder->frame_in.codec_frame.buffer = apr_palloc(pool,frame_size);
+       return decoder->base;
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_encoder.c b/libs/unimrcp/libs/mpf/src/mpf_encoder.c
new file mode 100644 (file)
index 0000000..0c85ac9
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mpf_encoder.h"
+#include "apt_log.h"
+
+typedef struct mpf_encoder_t mpf_encoder_t;
+
+struct mpf_encoder_t {
+       mpf_audio_stream_t *base;
+       mpf_audio_stream_t *sink;
+       mpf_frame_t         frame_out;
+};
+
+
+static apt_bool_t mpf_encoder_destroy(mpf_audio_stream_t *stream)
+{
+       mpf_encoder_t *encoder = stream->obj;
+       return mpf_audio_stream_destroy(encoder->sink);
+}
+
+static apt_bool_t mpf_encoder_open(mpf_audio_stream_t *stream)
+{
+       mpf_encoder_t *encoder = stream->obj;
+       return mpf_audio_stream_tx_open(encoder->sink);
+}
+
+static apt_bool_t mpf_encoder_close(mpf_audio_stream_t *stream)
+{
+       mpf_encoder_t *encoder = stream->obj;
+       return mpf_audio_stream_tx_close(encoder->sink);
+}
+
+static apt_bool_t mpf_encoder_process(mpf_audio_stream_t *stream, const mpf_frame_t *frame)
+{
+       mpf_encoder_t *encoder = stream->obj;
+
+       encoder->frame_out.type = frame->type;
+       if((frame->type & MEDIA_FRAME_TYPE_EVENT) == MEDIA_FRAME_TYPE_EVENT) {
+               encoder->frame_out.event_frame = frame->event_frame;
+       }
+       if((frame->type & MEDIA_FRAME_TYPE_AUDIO) == MEDIA_FRAME_TYPE_AUDIO) {
+               mpf_codec_encode(encoder->sink->tx_codec,&frame->codec_frame,&encoder->frame_out.codec_frame);
+       }
+       return mpf_audio_stream_frame_write(encoder->sink,&encoder->frame_out);
+}
+
+
+static const mpf_audio_stream_vtable_t vtable = {
+       mpf_encoder_destroy,
+       NULL,
+       NULL,
+       NULL,
+       mpf_encoder_open,
+       mpf_encoder_close,
+       mpf_encoder_process
+};
+
+MPF_DECLARE(mpf_audio_stream_t*) mpf_encoder_create(mpf_audio_stream_t *sink, apr_pool_t *pool)
+{
+       apr_size_t frame_size;
+       mpf_codec_t *codec;
+       mpf_encoder_t *encoder;
+       if(!sink || !sink->tx_codec) {
+               return NULL;
+       }
+       encoder = apr_palloc(pool,sizeof(mpf_encoder_t));
+       encoder->base = mpf_audio_stream_create(encoder,&vtable,STREAM_MODE_SEND,pool);
+       encoder->sink = sink;
+
+       codec = sink->tx_codec;
+       frame_size = mpf_codec_frame_size_calculate(codec->descriptor,codec->attribs);
+       encoder->base->tx_codec = codec;
+       encoder->frame_out.codec_frame.size = frame_size;
+       encoder->frame_out.codec_frame.buffer = apr_palloc(pool,frame_size);
+       return encoder->base;
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_engine.c b/libs/unimrcp/libs/mpf/src/mpf_engine.c
new file mode 100644 (file)
index 0000000..2c6dca9
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mpf_engine.h"
+#include "mpf_user.h"
+#include "mpf_context.h"
+#include "mpf_termination.h"
+#include "mpf_stream.h"
+#include "mpf_timer.h"
+#include "mpf_codec_descriptor.h"
+#include "mpf_codec_manager.h"
+#include "apt_obj_list.h"
+#include "apt_cyclic_queue.h"
+#include "apt_log.h"
+
+#define MPF_TASK_NAME "Media Processing Engine"
+
+struct mpf_engine_t {
+       apr_pool_t                *pool;
+       apt_task_t                *task;
+       apt_task_msg_type_e        task_msg_type;
+       apr_thread_mutex_t        *request_queue_guard;
+       apt_cyclic_queue_t        *request_queue;
+       apt_obj_list_t            *contexts;
+       mpf_timer_t               *timer;
+       const mpf_codec_manager_t *codec_manager;
+};
+
+static void mpf_engine_main(mpf_timer_t *timer, void *data);
+static apt_bool_t mpf_engine_destroy(apt_task_t *task);
+static apt_bool_t mpf_engine_start(apt_task_t *task);
+static apt_bool_t mpf_engine_terminate(apt_task_t *task);
+static apt_bool_t mpf_engine_msg_signal(apt_task_t *task, apt_task_msg_t *msg);
+static apt_bool_t mpf_engine_msg_process(apt_task_t *task, apt_task_msg_t *msg);
+
+static apt_bool_t mpf_engine_contexts_destroy(mpf_engine_t *engine);
+
+mpf_codec_t* mpf_codec_l16_create(apr_pool_t *pool);
+mpf_codec_t* mpf_codec_g711u_create(apr_pool_t *pool);
+mpf_codec_t* mpf_codec_g711a_create(apr_pool_t *pool);
+
+MPF_DECLARE(mpf_engine_t*) mpf_engine_create(apr_pool_t *pool)
+{
+       apt_task_vtable_t *vtable;
+       apt_task_msg_pool_t *msg_pool;
+       mpf_engine_t *engine = apr_palloc(pool,sizeof(mpf_engine_t));
+       engine->pool = pool;
+       engine->request_queue = NULL;
+       engine->contexts = NULL;
+       engine->codec_manager = NULL;
+
+       msg_pool = apt_task_msg_pool_create_dynamic(sizeof(mpf_message_t),pool);
+
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create "MPF_TASK_NAME);
+       engine->task = apt_task_create(engine,msg_pool,pool);
+       if(!engine->task) {
+               return NULL;
+       }
+
+       apt_task_name_set(engine->task,MPF_TASK_NAME);
+
+       vtable = apt_task_vtable_get(engine->task);
+       if(vtable) {
+               vtable->destroy = mpf_engine_destroy;
+               vtable->start = mpf_engine_start;
+               vtable->terminate = mpf_engine_terminate;
+               vtable->signal_msg = mpf_engine_msg_signal;
+               vtable->process_msg = mpf_engine_msg_process;
+       }
+
+       engine->task_msg_type = TASK_MSG_USER;
+
+       engine->request_queue = apt_cyclic_queue_create(CYCLIC_QUEUE_DEFAULT_SIZE);
+       apr_thread_mutex_create(&engine->request_queue_guard,APR_THREAD_MUTEX_UNNESTED,engine->pool);
+
+       engine->contexts = apt_list_create(engine->pool);
+
+       return engine;
+}
+
+MPF_DECLARE(apt_task_t*) mpf_task_get(mpf_engine_t *engine)
+{
+       return engine->task;
+}
+
+MPF_DECLARE(void) mpf_engine_task_msg_type_set(mpf_engine_t *engine, apt_task_msg_type_e type)
+{
+       engine->task_msg_type = type;
+}
+
+static apt_bool_t mpf_engine_destroy(apt_task_t *task)
+{
+       mpf_engine_t *engine = apt_task_object_get(task);
+
+       apt_list_destroy(engine->contexts);
+
+       apt_cyclic_queue_destroy(engine->request_queue);
+       apr_thread_mutex_destroy(engine->request_queue_guard);
+       return TRUE;
+}
+
+static apt_bool_t mpf_engine_start(apt_task_t *task)
+{
+       mpf_engine_t *engine = apt_task_object_get(task);
+
+       engine->timer = mpf_timer_start(CODEC_FRAME_TIME_BASE,mpf_engine_main,engine,engine->pool);
+       apt_task_child_start(task);
+       return TRUE;
+}
+
+static apt_bool_t mpf_engine_terminate(apt_task_t *task)
+{
+       mpf_engine_t *engine = apt_task_object_get(task);
+
+       mpf_timer_stop(engine->timer);
+       mpf_engine_contexts_destroy(engine);
+       return TRUE;
+}
+
+static apt_bool_t mpf_engine_contexts_destroy(mpf_engine_t *engine)
+{
+       mpf_context_t *context;
+       context = apt_list_pop_front(engine->contexts);
+       while(context) {
+               mpf_context_destroy(context);
+               
+               context = apt_list_pop_front(engine->contexts);
+       }
+       return TRUE;
+}
+
+static apt_bool_t mpf_engine_event_raise(mpf_termination_t *termination, int event_id, void *descriptor)
+{
+       apt_task_msg_t *task_msg;
+       mpf_message_t *event_msg;
+       mpf_engine_t *engine;
+       engine = termination->event_handler_obj;
+       if(!engine) {
+               return FALSE;
+       }
+
+       task_msg = apt_task_msg_get(engine->task);
+       task_msg->type = engine->task_msg_type;
+       event_msg = (mpf_message_t*) task_msg->data;
+       event_msg->command_id = event_id;
+       event_msg->message_type = MPF_MESSAGE_TYPE_EVENT;
+       event_msg->status_code = MPF_STATUS_CODE_SUCCESS;
+       event_msg->context = NULL;
+       event_msg->termination = termination;
+       event_msg->descriptor = descriptor;
+       
+       return apt_task_msg_parent_signal(engine->task,task_msg);
+}
+
+static apt_bool_t mpf_engine_msg_signal(apt_task_t *task, apt_task_msg_t *msg)
+{
+       mpf_engine_t *engine = apt_task_object_get(task);
+       
+       apr_thread_mutex_lock(engine->request_queue_guard);
+       if(apt_cyclic_queue_push(engine->request_queue,msg) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_ERROR,"MPF Request Queue is Full");
+       }
+       apr_thread_mutex_unlock(engine->request_queue_guard);
+       return TRUE;
+}
+
+static apt_bool_t mpf_engine_msg_process(apt_task_t *task, apt_task_msg_t *msg)
+{
+       mpf_engine_t *engine = apt_task_object_get(task);
+       apt_task_msg_t *response_msg;
+       mpf_message_t *response;
+       mpf_context_t *context;
+       mpf_termination_t *termination;
+       const mpf_message_t *request = (const mpf_message_t*) msg->data;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process MPF Message");
+       if(request->message_type != MPF_MESSAGE_TYPE_REQUEST) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Invalid MPF Message Type [%d]",request->message_type);
+               return FALSE;
+       }
+
+       response_msg = apt_task_msg_get(engine->task);
+       response_msg->type = engine->task_msg_type;
+       response = (mpf_message_t*) response_msg->data;
+       *response = *request;
+       response->message_type = MPF_MESSAGE_TYPE_RESPONSE;
+       response->status_code = MPF_STATUS_CODE_SUCCESS;
+       context = request->context;
+       termination = request->termination;
+       switch(request->command_id) {
+               case MPF_COMMAND_ADD:
+               {
+                       termination->event_handler_obj = engine;
+                       termination->event_handler = mpf_engine_event_raise;
+                       termination->codec_manager = engine->codec_manager;
+                       if(request->descriptor) {
+                               mpf_termination_modify(termination,request->descriptor);
+                       }
+                       mpf_termination_validate(termination);
+                       if(mpf_context_termination_add(context,termination) == FALSE) {
+                               response->status_code = MPF_STATUS_CODE_FAILURE;
+                               break;
+                       }
+                       mpf_context_topology_apply(context,termination);
+                       if(context->termination_count == 1) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add Context");
+                               context->elem = apt_list_push_back(engine->contexts,context,context->pool);
+                       }
+                       break;
+               }
+               case MPF_COMMAND_SUBTRACT:
+               {
+                       mpf_context_topology_destroy(context,termination);
+                       if(mpf_context_termination_subtract(context,termination) == FALSE) {
+                               response->status_code = MPF_STATUS_CODE_FAILURE;
+                               break;
+                       }
+                       if(context->termination_count == 0) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Remove Context");
+                               apt_list_elem_remove(engine->contexts,context->elem);
+                               context->elem = NULL;
+                       }
+                       break;
+               }
+               case MPF_COMMAND_MODIFY:
+               {
+                       if(request->descriptor) {
+                               mpf_context_topology_destroy(context,termination);
+                               mpf_termination_modify(termination,request->descriptor);
+                               mpf_termination_validate(termination);
+                               mpf_context_topology_apply(context,termination);
+                       }
+                       break;
+               }
+               default:
+               {
+                       response->status_code = MPF_STATUS_CODE_FAILURE;
+               }
+       }
+
+       return apt_task_msg_parent_signal(engine->task,response_msg);
+}
+
+static void mpf_engine_main(mpf_timer_t *timer, void *data)
+{
+       mpf_engine_t *engine = data;
+       apt_task_msg_t *msg;
+       apt_list_elem_t *elem;
+       mpf_context_t *context;
+
+       /* process request queue */
+       apr_thread_mutex_lock(engine->request_queue_guard);
+       msg = apt_cyclic_queue_pop(engine->request_queue);
+       while(msg) {
+               apr_thread_mutex_unlock(engine->request_queue_guard);
+               apt_task_msg_process(engine->task,msg);
+               apr_thread_mutex_lock(engine->request_queue_guard);
+               msg = apt_cyclic_queue_pop(engine->request_queue);
+       }
+       apr_thread_mutex_unlock(engine->request_queue_guard);
+
+       /* process contexts */
+       elem = apt_list_first_elem_get(engine->contexts);
+       while(elem) {
+               context = apt_list_elem_object_get(elem);
+               if(context) {
+                       mpf_context_process(context);
+               }
+               elem = apt_list_next_elem_get(engine->contexts,elem);
+       }
+}
+
+MPF_DECLARE(mpf_codec_manager_t*) mpf_engine_codec_manager_create(apr_pool_t *pool)
+{
+       mpf_codec_manager_t *codec_manager = mpf_codec_manager_create(3,pool);
+       if(codec_manager) {
+               mpf_codec_t *codec;
+               codec = mpf_codec_g711u_create(pool);
+               mpf_codec_manager_codec_register(codec_manager,codec);
+
+               codec = mpf_codec_g711a_create(pool);
+               mpf_codec_manager_codec_register(codec_manager,codec);
+
+               codec = mpf_codec_l16_create(pool);
+               mpf_codec_manager_codec_register(codec_manager,codec);
+       }
+       return codec_manager;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_engine_codec_manager_register(mpf_engine_t *engine, const mpf_codec_manager_t *codec_manager)
+{
+       engine->codec_manager = codec_manager;
+       return TRUE;
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_file_termination_factory.c b/libs/unimrcp/libs/mpf/src/mpf_file_termination_factory.c
new file mode 100644 (file)
index 0000000..4bab083
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mpf_termination.h"
+#include "mpf_file_termination_factory.h"
+#include "mpf_audio_file_stream.h"
+
+static apt_bool_t mpf_file_termination_destroy(mpf_termination_t *termination)
+{
+       return TRUE;
+}
+
+static apt_bool_t mpf_file_termination_modify(mpf_termination_t *termination, void *descriptor)
+{
+       mpf_audio_stream_t *audio_stream = termination->audio_stream;
+       if(!audio_stream) {
+               audio_stream = mpf_file_stream_create(termination,termination->pool);
+               if(!audio_stream) {
+                       return FALSE;
+               }
+               termination->audio_stream = audio_stream;
+       }
+
+       return mpf_file_stream_modify(audio_stream,descriptor);
+}
+
+static const mpf_termination_vtable_t file_vtable = {
+       mpf_file_termination_destroy,
+       mpf_file_termination_modify,
+};
+
+static mpf_termination_t* mpf_file_termination_create(
+                                                                       mpf_termination_factory_t *termination_factory,
+                                                                       void *obj, 
+                                                                       apr_pool_t *pool)
+{
+       return mpf_termination_base_create(termination_factory,obj,&file_vtable,NULL,NULL,pool);
+}
+
+MPF_DECLARE(mpf_termination_factory_t*) mpf_file_termination_factory_create(apr_pool_t *pool)
+{
+       mpf_termination_factory_t *file_termination_factory = apr_palloc(pool,sizeof(mpf_termination_factory_t));
+       file_termination_factory->create_termination = mpf_file_termination_create;
+       return file_termination_factory;
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_jitter_buffer.c b/libs/unimrcp/libs/mpf/src/mpf_jitter_buffer.c
new file mode 100644 (file)
index 0000000..55a90bf
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mpf_jitter_buffer.h"
+
+struct mpf_jitter_buffer_t {
+       mpf_jb_config_t *config;
+
+       apr_byte_t      *raw_data;
+       mpf_frame_t     *frames;
+       apr_size_t       frame_count;
+       apr_size_t       frame_ts;
+       apr_size_t       frame_size;
+
+       apr_size_t       playout_delay_ts;
+
+       apr_byte_t       write_sync;
+       int              write_ts_offset;
+       
+       apr_size_t       write_ts;
+       apr_size_t       read_ts;
+
+       apr_pool_t      *pool;
+};
+
+
+mpf_jitter_buffer_t* mpf_jitter_buffer_create(mpf_jb_config_t *jb_config, mpf_codec_t *codec, apr_pool_t *pool)
+{
+       size_t i;
+       mpf_jitter_buffer_t *jb = apr_palloc(pool,sizeof(mpf_jitter_buffer_t));
+       if(!jb_config) {
+               /* create default jb config */
+               jb_config = apr_palloc(pool,sizeof(mpf_jb_config_t));
+               mpf_jb_config_init(jb_config);
+       }
+       /* validate jb config */
+       if(jb_config->initial_playout_delay == 0) {
+               /* default configuration */
+               jb_config->min_playout_delay = 10; /* ms */
+               jb_config->initial_playout_delay = 50; /* ms */
+               jb_config->max_playout_delay = 200; /* ms */
+       }
+       else {
+               if(jb_config->min_playout_delay > jb_config->initial_playout_delay) {
+                       jb_config->min_playout_delay = jb_config->initial_playout_delay;
+               }
+               if(jb_config->max_playout_delay < jb_config->initial_playout_delay) {
+                       jb_config->max_playout_delay = 2 * jb_config->initial_playout_delay;
+               }
+       }
+       jb->config = jb_config;
+
+       jb->frame_ts = mpf_codec_frame_samples_calculate(codec->descriptor);
+       jb->frame_size = mpf_codec_frame_size_calculate(codec->descriptor,codec->attribs);
+       jb->frame_count = jb->config->max_playout_delay / CODEC_FRAME_TIME_BASE;
+       jb->raw_data = apr_palloc(pool,jb->frame_size*jb->frame_count);
+       jb->frames = apr_palloc(pool,sizeof(mpf_frame_t)*jb->frame_count);
+       for(i=0; i<jb->frame_count; i++) {
+               jb->frames[i].type = MEDIA_FRAME_TYPE_NONE;
+               jb->frames[i].codec_frame.buffer = jb->raw_data + i*jb->frame_size;
+       }
+
+       jb->playout_delay_ts = jb->config->initial_playout_delay *
+               codec->descriptor->channel_count * codec->descriptor->sampling_rate / 1000;
+
+       jb->write_sync = 1;
+       jb->write_ts_offset = 0;
+       jb->write_ts = jb->read_ts = 0;
+
+       return jb;
+}
+
+void mpf_jitter_buffer_destroy(mpf_jitter_buffer_t *jb)
+{
+}
+
+apt_bool_t mpf_jitter_buffer_restart(mpf_jitter_buffer_t *jb)
+{
+       jb->write_sync = 1;
+       jb->write_ts_offset = 0;
+       jb->write_ts = jb->read_ts;
+       return TRUE;
+}
+
+static APR_INLINE mpf_frame_t* mpf_jitter_buffer_frame_get(mpf_jitter_buffer_t *jb, apr_size_t ts)
+{
+       apr_size_t index = (ts / jb->frame_ts) % jb->frame_count;
+       return &jb->frames[index];
+}
+
+static APR_INLINE jb_result_t mpf_jitter_buffer_write_prepare(mpf_jitter_buffer_t *jb, apr_uint32_t ts, 
+                                                                                               apr_size_t *write_ts, apr_size_t *available_frame_count)
+{
+       jb_result_t result = JB_OK;
+       if(jb->write_sync) {
+               jb->write_ts_offset = ts - jb->write_ts;
+               jb->write_sync = 0;
+       }
+
+       *write_ts = ts - jb->write_ts_offset + jb->playout_delay_ts;
+       if(*write_ts % jb->frame_ts != 0) {
+               /* not frame alligned */
+               return JB_DISCARD_NOT_ALLIGNED;
+       }
+
+       if(*write_ts >= jb->write_ts) {
+               if(*write_ts - jb->write_ts > jb->frame_ts) {
+                       /* gap */
+               }
+               /* normal write */
+       }
+       else {
+               if(*write_ts >= jb->read_ts) {
+                       /* backward write */
+               }
+               else {
+                       /* too late */
+                       result = JB_DISCARD_TOO_LATE;
+               }
+       }
+       *available_frame_count = jb->frame_count - (*write_ts - jb->read_ts)/jb->frame_ts;
+       return result;
+}
+
+jb_result_t mpf_jitter_buffer_write(mpf_jitter_buffer_t *jb, mpf_codec_t *codec, void *buffer, apr_size_t size, apr_uint32_t ts)
+{
+       mpf_frame_t *media_frame;
+       apr_size_t write_ts;
+       apr_size_t available_frame_count = 0;
+       jb_result_t result = mpf_jitter_buffer_write_prepare(jb,ts,&write_ts,&available_frame_count);
+       if(result != JB_OK) {
+               return result;
+       }
+
+       while(available_frame_count && size) {
+               media_frame = mpf_jitter_buffer_frame_get(jb,write_ts);
+               media_frame->codec_frame.size = jb->frame_size;
+               if(mpf_codec_dissect(codec,&buffer,&size,&media_frame->codec_frame) == FALSE) {
+                       break;
+               }
+
+               media_frame->type |= MEDIA_FRAME_TYPE_AUDIO;
+               write_ts += jb->frame_ts;
+               available_frame_count--;
+       }
+
+       if(size) {
+               /* no frame available to write, but some data remains in buffer (partialy too early) */
+       }
+
+       if(write_ts > jb->write_ts) {
+               jb->write_ts = write_ts;
+       }
+       return result;
+}
+
+jb_result_t mpf_jitter_buffer_write_named_event(mpf_jitter_buffer_t *jb, mpf_named_event_frame_t *named_event, apr_uint32_t ts)
+{
+       return JB_OK;
+}
+
+apt_bool_t mpf_jitter_buffer_read(mpf_jitter_buffer_t *jb, mpf_frame_t *media_frame)
+{
+       mpf_frame_t *src_media_frame = mpf_jitter_buffer_frame_get(jb,jb->read_ts);
+       if(jb->write_ts > jb->read_ts) {
+               /* normal read */
+               media_frame->type = src_media_frame->type;
+               if(media_frame->type & MEDIA_FRAME_TYPE_AUDIO) {
+                       media_frame->codec_frame.size = src_media_frame->codec_frame.size;
+                       memcpy(media_frame->codec_frame.buffer,src_media_frame->codec_frame.buffer,media_frame->codec_frame.size);
+               }
+               if(media_frame->type & MEDIA_FRAME_TYPE_EVENT) {
+                       media_frame->event_frame = src_media_frame->event_frame;
+               }
+       }
+       else {
+               /* underflow */
+               media_frame->type = MEDIA_FRAME_TYPE_NONE;
+               jb->write_ts += jb->frame_ts;
+       }
+       src_media_frame->type = MEDIA_FRAME_TYPE_NONE;
+       jb->read_ts += jb->frame_ts;
+       return TRUE;
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_rtp_attribs.c b/libs/unimrcp/libs/mpf/src/mpf_rtp_attribs.c
new file mode 100644 (file)
index 0000000..5b59315
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apt_string_table.h"
+#include "mpf_rtp_attribs.h"
+
+/** String table of RTP attributes (mpf_rtp_attrib_e) */
+static const apt_str_table_item_t mpf_rtp_attrib_table[] = {
+       {{"rtpmap",   6},1},
+       {{"sendonly", 8},8},
+       {{"recvonly", 8},2},
+       {{"sendrecv", 8},4},
+       {{"mid",      3},0},
+       {{"ptime",    5},0}
+};
+
+
+MPF_DECLARE(const apt_str_t*) mpf_rtp_attrib_str_get(mpf_rtp_attrib_e attrib_id)
+{
+       return apt_string_table_str_get(mpf_rtp_attrib_table,RTP_ATTRIB_COUNT,attrib_id);
+}
+
+MPF_DECLARE(mpf_rtp_attrib_e) mpf_rtp_attrib_id_find(const apt_str_t *attrib)
+{
+       return apt_string_table_id_find(mpf_rtp_attrib_table,RTP_ATTRIB_COUNT,attrib);
+}
+
+MPF_DECLARE(const apt_str_t*) mpf_stream_mode_str_get(mpf_stream_mode_e direction)
+{
+       mpf_rtp_attrib_e attrib_id = RTP_ATTRIB_UNKNOWN;
+       switch(direction) {
+               case STREAM_MODE_SEND:
+                       attrib_id = RTP_ATTRIB_SENDONLY;
+                       break;
+               case STREAM_MODE_RECEIVE:
+                       attrib_id = RTP_ATTRIB_RECVONLY;
+                       break;
+               case STREAM_MODE_SEND_RECEIVE:
+                       attrib_id = RTP_ATTRIB_SENDRECV;
+                       break;
+               default:
+                       break;
+       }
+       return apt_string_table_str_get(mpf_rtp_attrib_table,RTP_ATTRIB_COUNT,attrib_id);
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_rtp_stream.c b/libs/unimrcp/libs/mpf/src/mpf_rtp_stream.c
new file mode 100644 (file)
index 0000000..3956d1e
--- /dev/null
@@ -0,0 +1,764 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_network_io.h>
+#include "mpf_rtp_stream.h"
+#include "mpf_termination.h"
+#include "mpf_codec_manager.h"
+#include "mpf_rtp_header.h"
+#include "mpf_rtp_defs.h"
+#include "apt_log.h"
+
+
+/** RTP stream */
+typedef struct mpf_rtp_stream_t mpf_rtp_stream_t;
+struct mpf_rtp_stream_t {
+       mpf_audio_stream_t         *base;
+
+       mpf_rtp_media_descriptor_t *local_media;
+       mpf_rtp_media_descriptor_t *remote_media;
+
+       rtp_transmitter_t           transmitter;
+       rtp_receiver_t              receiver;
+
+       mpf_rtp_config_t           *config;
+
+       apr_socket_t               *socket;
+       apr_sockaddr_t             *local_sockaddr;
+       apr_sockaddr_t             *remote_sockaddr;
+       
+       apr_pool_t                 *pool;
+};
+
+static apt_bool_t mpf_rtp_stream_destroy(mpf_audio_stream_t *stream);
+static apt_bool_t mpf_rtp_rx_stream_open(mpf_audio_stream_t *stream);
+static apt_bool_t mpf_rtp_rx_stream_close(mpf_audio_stream_t *stream);
+static apt_bool_t mpf_rtp_stream_receive(mpf_audio_stream_t *stream, mpf_frame_t *frame);
+static apt_bool_t mpf_rtp_tx_stream_open(mpf_audio_stream_t *stream);
+static apt_bool_t mpf_rtp_tx_stream_close(mpf_audio_stream_t *stream);
+static apt_bool_t mpf_rtp_stream_transmit(mpf_audio_stream_t *stream, const mpf_frame_t *frame);
+
+static const mpf_audio_stream_vtable_t vtable = {
+       mpf_rtp_stream_destroy,
+       mpf_rtp_rx_stream_open,
+       mpf_rtp_rx_stream_close,
+       mpf_rtp_stream_receive,
+       mpf_rtp_tx_stream_open,
+       mpf_rtp_tx_stream_close,
+       mpf_rtp_stream_transmit
+};
+
+static apt_bool_t mpf_rtp_socket_create(mpf_rtp_stream_t *stream, mpf_rtp_media_descriptor_t *local_media);
+
+
+MPF_DECLARE(mpf_audio_stream_t*) mpf_rtp_stream_create(mpf_termination_t *termination, mpf_rtp_config_t *config, apr_pool_t *pool)
+{
+       mpf_rtp_stream_t *rtp_stream = apr_palloc(pool,sizeof(mpf_rtp_stream_t));
+       rtp_stream->pool = pool;
+       rtp_stream->config = config;
+       rtp_stream->local_media = NULL;
+       rtp_stream->remote_media = NULL;
+       rtp_stream->socket = NULL;
+       rtp_stream->local_sockaddr = NULL;
+       rtp_stream->remote_sockaddr = NULL;
+       rtp_stream->base = mpf_audio_stream_create(rtp_stream,&vtable,STREAM_MODE_NONE,pool);
+       rtp_stream->base->termination = termination;
+       rtp_receiver_init(&rtp_stream->receiver);
+       rtp_transmitter_init(&rtp_stream->transmitter);
+       rtp_stream->transmitter.ssrc = (apr_uint32_t)apr_time_now();
+
+       return rtp_stream->base;
+}
+
+static void mpf_rtp_stream_ip_port_set(mpf_rtp_media_descriptor_t *media, mpf_rtp_config_t *config)
+{
+       if(media->base.ip.length == 0) {
+               media->base.ip = config->ip;
+               media->base.ext_ip = config->ext_ip;
+       }
+       if(media->base.port == 0) {
+               media->base.port = config->rtp_port_cur;
+               config->rtp_port_cur += 2;
+               if(config->rtp_port_cur == config->rtp_port_max) {
+                       config->rtp_port_cur = config->rtp_port_min;
+               }
+       }
+}
+
+static apt_bool_t mpf_rtp_stream_local_media_create(mpf_rtp_stream_t *rtp_stream, mpf_rtp_media_descriptor_t *local_media, mpf_rtp_media_descriptor_t *remote_media)
+{
+       apt_bool_t status = TRUE;
+       if(!local_media) {
+               /* local media is not specified, create the default one */
+               local_media = apr_palloc(rtp_stream->pool,sizeof(mpf_rtp_media_descriptor_t));
+               mpf_rtp_media_descriptor_init(local_media);
+               local_media->base.state = MPF_MEDIA_ENABLED;
+               local_media->mode = STREAM_MODE_SEND_RECEIVE;
+       }
+       if(remote_media) {
+               local_media->base.id = remote_media->base.id;
+       }
+
+       mpf_rtp_stream_ip_port_set(local_media,rtp_stream->config);
+       if(mpf_rtp_socket_create(rtp_stream,local_media) == FALSE) {
+               local_media->base.state = MPF_MEDIA_DISABLED;
+               status = FALSE;
+       }
+
+       if(rtp_stream->config->ptime) {
+               local_media->ptime = rtp_stream->config->ptime;
+       }
+
+       if(mpf_codec_list_is_empty(&local_media->codec_list) == TRUE) {
+               if(mpf_codec_list_is_empty(&rtp_stream->config->codec_list) == TRUE) {
+                       mpf_codec_manager_codec_list_get(
+                                                               rtp_stream->base->termination->codec_manager,
+                                                               &local_media->codec_list,
+                                                               rtp_stream->pool);
+               }
+               else {
+                       mpf_codec_list_copy(&local_media->codec_list,
+                                                               &rtp_stream->config->codec_list,
+                                                               rtp_stream->pool);
+               }
+       }
+
+       rtp_stream->local_media = local_media;
+       return status;
+}
+
+static apt_bool_t mpf_rtp_stream_local_media_update(mpf_rtp_stream_t *rtp_stream, mpf_rtp_media_descriptor_t *media)
+{
+       apt_bool_t status = TRUE;
+       if(apt_string_compare(&rtp_stream->local_media->base.ip,&media->base.ip) == FALSE ||
+               rtp_stream->local_media->base.port != media->base.port) {
+
+               if(mpf_rtp_socket_create(rtp_stream,media) == FALSE) {
+                       media->base.state = MPF_MEDIA_DISABLED;
+                       status = FALSE;
+               }
+       }
+       if(mpf_codec_list_is_empty(&media->codec_list) == TRUE) {
+               mpf_codec_manager_codec_list_get(
+                                                       rtp_stream->base->termination->codec_manager,
+                                                       &media->codec_list,
+                                                       rtp_stream->pool);
+       }
+
+       rtp_stream->local_media = media;
+       return status;
+}
+
+static apt_bool_t mpf_rtp_stream_remote_media_update(mpf_rtp_stream_t *rtp_stream, mpf_rtp_media_descriptor_t *media)
+{
+       apt_bool_t status = TRUE;
+       if(!rtp_stream->remote_media || 
+               apt_string_compare(&rtp_stream->remote_media->base.ip,&media->base.ip) == FALSE ||
+               rtp_stream->remote_media->base.port != media->base.port) {
+
+               rtp_stream->remote_sockaddr = NULL;
+               apr_sockaddr_info_get(
+                       &rtp_stream->remote_sockaddr,
+                       media->base.ip.buf,
+                       APR_INET,
+                       media->base.port,
+                       0,
+                       rtp_stream->pool);
+               if(!rtp_stream->remote_sockaddr) {
+                       status = FALSE;
+               }
+       }
+
+       rtp_stream->remote_media = media;
+       return status;
+}
+
+static apt_bool_t mpf_rtp_stream_media_negotiate(mpf_rtp_stream_t *rtp_stream)
+{
+       if(!rtp_stream->local_media || !rtp_stream->remote_media) {
+               return FALSE;
+       }
+
+       rtp_stream->local_media->base.id = rtp_stream->remote_media->base.id;
+       rtp_stream->local_media->base.state = rtp_stream->remote_media->base.state;
+
+       rtp_stream->local_media->mid = rtp_stream->remote_media->mid;
+       rtp_stream->local_media->ptime = rtp_stream->remote_media->ptime;
+       rtp_stream->local_media->mode = mpf_stream_mode_negotiate(rtp_stream->remote_media->mode);
+
+       if(mpf_codec_list_is_empty(&rtp_stream->remote_media->codec_list) == TRUE) {
+               /* no remote codecs available, initialize them according to the local codecs  */
+               mpf_codec_list_copy(&rtp_stream->remote_media->codec_list,
+                                                       &rtp_stream->local_media->codec_list,
+                                                       rtp_stream->pool);
+       }
+
+       /* intersect local and remote codecs */
+       if(rtp_stream->config->own_preferrence == TRUE) {
+               mpf_codec_list_intersect(&rtp_stream->local_media->codec_list,&rtp_stream->remote_media->codec_list);
+       }
+       else {
+               mpf_codec_list_intersect(&rtp_stream->remote_media->codec_list,&rtp_stream->local_media->codec_list);
+       }
+
+       rtp_stream->base->mode = rtp_stream->local_media->mode;
+       return TRUE;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_rtp_stream_modify(mpf_audio_stream_t *stream, mpf_rtp_stream_descriptor_t *descriptor)
+{
+       apt_bool_t status = TRUE;
+       mpf_rtp_stream_t *rtp_stream = stream->obj;
+       if(!rtp_stream) {
+               return FALSE;
+       }
+
+       if(!rtp_stream->local_media) {
+               /* create local media */
+               status = mpf_rtp_stream_local_media_create(rtp_stream,descriptor->local,descriptor->remote);
+       }
+       else if(descriptor->local) {
+               /* update local media */
+               status = mpf_rtp_stream_local_media_update(rtp_stream,descriptor->local);
+       }
+       
+       if(descriptor->remote && status == TRUE) {
+               /* update remote media */
+               mpf_rtp_stream_remote_media_update(rtp_stream,descriptor->remote);
+
+               /* negotiate local and remote media */
+               mpf_rtp_stream_media_negotiate(rtp_stream);
+       }
+
+       if((rtp_stream->base->mode & STREAM_MODE_SEND) == STREAM_MODE_SEND) {
+               rtp_stream->base->tx_codec = mpf_codec_manager_codec_get(
+                                                               rtp_stream->base->termination->codec_manager,
+                                                               rtp_stream->remote_media->codec_list.preffered,
+                                                               rtp_stream->pool);
+               if(rtp_stream->base->tx_codec) {
+                       rtp_stream->transmitter.samples_per_frame = 
+                               (apr_uint32_t)mpf_codec_frame_samples_calculate(rtp_stream->base->tx_codec->descriptor);
+               }
+       }
+       if((rtp_stream->base->mode & STREAM_MODE_RECEIVE) == STREAM_MODE_RECEIVE) {
+               rtp_stream->base->rx_codec = mpf_codec_manager_codec_get(
+                                                               rtp_stream->base->termination->codec_manager,
+                                                               rtp_stream->local_media->codec_list.preffered,
+                                                               rtp_stream->pool);
+       }
+
+       if(!descriptor->local) {
+               descriptor->local = rtp_stream->local_media;
+       }
+       return status;
+}
+
+static apt_bool_t mpf_rtp_stream_destroy(mpf_audio_stream_t *stream)
+{
+       mpf_rtp_stream_t *rtp_stream = stream->obj;
+       if(rtp_stream->socket) {
+               apr_socket_close(rtp_stream->socket);
+               rtp_stream->socket = NULL;
+       }
+       
+       return TRUE;
+}
+
+static apt_bool_t mpf_rtp_rx_stream_open(mpf_audio_stream_t *stream)
+{
+       mpf_rtp_stream_t *rtp_stream = stream->obj;
+       rtp_receiver_t *receiver = &rtp_stream->receiver;
+       if(!rtp_stream->socket || !rtp_stream->local_media) {
+               return FALSE;
+       }
+
+       receiver->jb = mpf_jitter_buffer_create(
+                                               &rtp_stream->config->jb_config,
+                                               stream->rx_codec,
+                                               rtp_stream->pool);
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open RTP Receive %s:%hu <- %s:%hu playout [%d ms]",
+                       rtp_stream->local_media->base.ip.buf,
+                       rtp_stream->local_media->base.port,
+                       rtp_stream->remote_media->base.ip.buf,
+                       rtp_stream->remote_media->base.port,
+                       rtp_stream->config->jb_config.initial_playout_delay);
+       return TRUE;
+}
+
+static apt_bool_t mpf_rtp_rx_stream_close(mpf_audio_stream_t *stream)
+{
+       mpf_rtp_stream_t *rtp_stream = stream->obj;
+       rtp_receiver_t *receiver = &rtp_stream->receiver;
+       receiver->stat.lost_packets = 0;
+       if(receiver->stat.received_packets) {
+               apr_uint32_t expected_packets = receiver->history.seq_cycles + 
+                       receiver->history.seq_num_max - receiver->history.seq_num_base + 1;
+               if(expected_packets > receiver->stat.received_packets) {
+                       receiver->stat.lost_packets = expected_packets - receiver->stat.received_packets;
+               }
+       }
+
+       mpf_jitter_buffer_destroy(receiver->jb);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close RTP Receive %s:%hu <- %s:%hu [r:%lu l:%lu j:%lu]",
+                       rtp_stream->local_media->base.ip.buf,
+                       rtp_stream->local_media->base.port,
+                       rtp_stream->remote_media->base.ip.buf,
+                       rtp_stream->remote_media->base.port,
+                       receiver->stat.received_packets,
+                       receiver->stat.lost_packets,
+                       receiver->stat.jitter);
+       return TRUE;
+}
+
+
+static APR_INLINE void rtp_rx_overall_stat_reset(rtp_receiver_t *receiver)
+{
+       memset(&receiver->stat,0,sizeof(receiver->stat));
+       memset(&receiver->history,0,sizeof(receiver->history));
+       memset(&receiver->periodic_history,0,sizeof(receiver->periodic_history));
+}
+
+static APR_INLINE void rtp_rx_stat_init(rtp_receiver_t *receiver, rtp_header_t *header, apr_time_t *time)
+{
+       receiver->stat.ssrc = header->ssrc;
+       receiver->history.seq_num_base = receiver->history.seq_num_max = (apr_uint16_t)header->sequence;
+       receiver->history.ts_last = header->timestamp;
+       receiver->history.time_last = *time;
+}
+
+static APR_INLINE void rtp_rx_restart(rtp_receiver_t *receiver)
+{
+       apr_byte_t restarts = ++receiver->stat.restarts;
+       rtp_rx_overall_stat_reset(receiver);
+       mpf_jitter_buffer_restart(receiver->jb);
+       receiver->stat.restarts = restarts;
+}
+
+static rtp_header_t* rtp_rx_header_skip(void **buffer, apr_size_t *size)
+{
+       apr_size_t offset = 0;
+       rtp_header_t *header = (rtp_header_t*)*buffer;
+
+    /* RTP header validity check */
+       if(header->version != RTP_VERSION) {
+               return NULL;
+       }
+
+    /* calculate payload offset */
+       offset = sizeof(rtp_header_t) + (header->count * sizeof(apr_uint32_t));
+
+       /* additional offset in case of RTP extension */
+       if(header->extension) {
+               rtp_extension_header_t *ext_header = (rtp_extension_header_t*)(((apr_byte_t*)*buffer)+offset);
+               offset += (ntohs(ext_header->length) * sizeof(apr_uint32_t));
+       }
+
+       if (offset >= *size) {
+               return NULL;
+       }
+
+       /* skip to payload */
+       *buffer = (apr_byte_t*)*buffer + offset;
+       *size = *size - offset;
+
+       return header;
+}
+
+typedef enum {
+       RTP_SSRC_UPDATE,
+       RTP_SSRC_PROBATION,
+       RTP_SSRC_RESTART
+} rtp_ssrc_result_e;
+
+static APR_INLINE rtp_ssrc_result_e rtp_rx_ssrc_update(rtp_receiver_t *receiver, apr_uint32_t ssrc)
+{
+       if(receiver->stat.ssrc == ssrc) {
+               /* known ssrc */
+               if(receiver->history.ssrc_probation) {
+                       /* reset the probation for new ssrc */
+                       receiver->history.ssrc_probation = 0;
+                       receiver->history.ssrc_new = 0;
+               }
+       }
+       else {
+               if(receiver->history.ssrc_new == ssrc) {
+                       if(--receiver->history.ssrc_probation == 0) {
+                               /* restart with new ssrc */
+                               receiver->stat.ssrc = ssrc;
+                               return RTP_SSRC_RESTART;
+                       }
+                       else {
+                               return RTP_SSRC_PROBATION;
+                       }
+               }
+               else {
+                       /* start probation for new ssrc */
+                       receiver->history.ssrc_new = ssrc;
+                       receiver->history.ssrc_probation = 5;
+                       return RTP_SSRC_PROBATION;
+               }
+       }
+       return RTP_SSRC_UPDATE;
+}
+
+typedef enum {
+       RTP_SEQ_UPDATE,
+       RTP_SEQ_MISORDER,
+       RTP_SEQ_DRIFT
+} rtp_seq_result_e;
+
+static APR_INLINE rtp_seq_result_e rtp_rx_seq_update(rtp_receiver_t *receiver, apr_uint16_t seq_num)
+{
+       rtp_seq_result_e result = RTP_SEQ_UPDATE;
+       apr_uint16_t seq_delta = seq_num - receiver->history.seq_num_max;
+       if(seq_delta < MAX_DROPOUT) {
+               if(seq_num < receiver->history.seq_num_max) {
+                       /* sequence number wrapped */
+                       receiver->history.seq_cycles += RTP_SEQ_MOD;
+               }
+               receiver->history.seq_num_max = seq_num;
+       }
+       else if(seq_delta <= RTP_SEQ_MOD - MAX_MISORDER) {
+               /* sequence number made a very large jump */
+               result = RTP_SEQ_DRIFT;
+       }
+       else {
+               /* duplicate or misordered packet */
+               result = RTP_SEQ_MISORDER;
+       }
+       receiver->stat.received_packets++;
+
+       if(receiver->stat.received_packets - receiver->periodic_history.received_prior >= 50) {
+               receiver->periodic_history.received_prior = receiver->stat.received_packets;
+               receiver->periodic_history.discarded_prior = receiver->stat.discarded_packets;
+               receiver->periodic_history.jitter_min = receiver->stat.jitter;
+               receiver->periodic_history.jitter_max = receiver->stat.jitter;
+       }
+       return result;
+}
+
+typedef enum {
+       RTP_TS_UPDATE,
+       RTP_TS_DRIFT
+} rtp_ts_result_e;
+
+static APR_INLINE rtp_ts_result_e rtp_rx_ts_update(rtp_receiver_t *receiver, mpf_codec_descriptor_t *descriptor, apr_time_t *time, apr_uint32_t ts)
+{
+       apr_int32_t deviation;
+
+       /* arrival time diff in samples */
+       deviation = (apr_int32_t)apr_time_as_msec(*time - receiver->history.time_last) * 
+               descriptor->channel_count * descriptor->sampling_rate / 1000;
+       /* arrival timestamp diff */
+       deviation -= ts - receiver->history.ts_last;
+
+       if(deviation < 0) {
+               deviation = -deviation;
+       }
+
+       if(deviation > DEVIATION_THRESHOLD) {
+               return RTP_TS_DRIFT;
+       }
+
+       receiver->stat.jitter += deviation - ((receiver->stat.jitter + 8) >> 4);
+#if PRINT_RTP_PACKET_STAT
+       printf("jitter=%d deviation=%d\n",receiver->stat.jitter,deviation);
+#endif
+       receiver->history.time_last = *time;
+       receiver->history.ts_last = ts;
+
+       if(receiver->stat.jitter < receiver->periodic_history.jitter_min) {
+               receiver->periodic_history.jitter_min = receiver->stat.jitter;
+       }
+       if(receiver->stat.jitter > receiver->periodic_history.jitter_max) {
+               receiver->periodic_history.jitter_max = receiver->stat.jitter;
+       }
+       return RTP_TS_UPDATE;
+}
+
+static APR_INLINE void rtp_rx_failure_threshold_check(rtp_receiver_t *receiver)
+{
+       apr_uint32_t received;
+       apr_uint32_t discarded;
+       received = receiver->stat.received_packets - receiver->periodic_history.received_prior;
+       discarded = receiver->stat.discarded_packets - receiver->periodic_history.discarded_prior;
+
+       if(discarded * 100 > received * DISCARDED_TO_RECEIVED_RATIO_THRESHOLD) {
+               /* failure threshold hired, restart */
+               rtp_rx_restart(receiver);
+       }
+}
+
+static apt_bool_t rtp_rx_packet_receive(rtp_receiver_t *receiver, mpf_codec_t *codec, void *buffer, apr_size_t size)
+{
+       apr_time_t time;
+       rtp_ssrc_result_e ssrc_result;
+       rtp_header_t *header = rtp_rx_header_skip(&buffer,&size);
+       if(!header) {
+               /* invalid RTP packet */
+               receiver->stat.invalid_packets++;
+               return FALSE;
+       }
+
+       header->sequence = ntohs((apr_uint16_t)header->sequence);
+       header->timestamp = ntohl(header->timestamp);
+       header->ssrc = ntohl(header->ssrc);
+
+       time = apr_time_now();
+
+#if PRINT_RTP_PACKET_STAT
+       printf("RTP time=%6lu ssrc=%8lx pt=%3u %cts=%9lu seq=%5u size=%lu\n",
+                                       (apr_uint32_t)apr_time_usec(time),
+                                       header->ssrc, header->type, header->marker ? '*' : ' ',
+                                       header->timestamp, header->sequence, size);
+#endif
+       if(!receiver->stat.received_packets) {
+               /* initialization */
+               rtp_rx_stat_init(receiver,header,&time);
+       }
+
+       ssrc_result = rtp_rx_ssrc_update(receiver,header->ssrc);
+       if(ssrc_result == RTP_SSRC_PROBATION) {
+               receiver->stat.invalid_packets++;
+               return FALSE;
+       }
+       else if(ssrc_result == RTP_SSRC_RESTART) {
+               rtp_rx_restart(receiver);
+               rtp_rx_stat_init(receiver,header,&time);
+       }
+
+       rtp_rx_seq_update(receiver,(apr_uint16_t)header->sequence);
+       
+       if(rtp_rx_ts_update(receiver,codec->descriptor,&time,header->timestamp) == RTP_TS_DRIFT) {
+               rtp_rx_restart(receiver);
+               return FALSE;
+       }
+       
+       if(header->type == codec->descriptor->payload_type) {
+               /* codec */
+               if(mpf_jitter_buffer_write(receiver->jb,codec,buffer,size,header->timestamp) != JB_OK) {
+                       receiver->stat.discarded_packets++;
+                       rtp_rx_failure_threshold_check(receiver);
+               }
+       }
+       else if(header->type == receiver->event_pt && receiver->event_pt != 0) {
+               /* named event */
+               mpf_named_event_frame_t *named_event = (mpf_named_event_frame_t *)buffer;
+               if(mpf_jitter_buffer_write_named_event(receiver->jb,named_event,header->timestamp) != JB_OK) {
+                       receiver->stat.discarded_packets++;
+                       rtp_rx_failure_threshold_check(receiver);
+               }
+       }
+       else if(header->type == 13 || header->type == 19) {
+               /* CN packet*/
+               receiver->stat.ignored_packets++;
+       }
+       else {
+               /* invalid payload type */
+               receiver->stat.ignored_packets++;
+       }
+       
+       return TRUE;
+}
+
+static apt_bool_t rtp_rx_process(mpf_rtp_stream_t *rtp_stream)
+{
+       char buffer[1500];
+       apr_size_t size = sizeof(buffer);
+       apr_size_t max_count = 5;
+       while(max_count && apr_socket_recvfrom(rtp_stream->remote_sockaddr,rtp_stream->socket,0,buffer,&size) == APR_SUCCESS) {
+               rtp_rx_packet_receive(&rtp_stream->receiver,rtp_stream->base->rx_codec,buffer,size);
+
+               size = sizeof(buffer);
+               max_count--;
+       }
+       return TRUE;
+}
+
+static apt_bool_t mpf_rtp_stream_receive(mpf_audio_stream_t *stream, mpf_frame_t *frame)
+{
+       mpf_rtp_stream_t *rtp_stream = stream->obj;
+       rtp_rx_process(rtp_stream);
+
+       return mpf_jitter_buffer_read(rtp_stream->receiver.jb,frame);
+}
+
+
+
+
+
+static apt_bool_t mpf_rtp_tx_stream_open(mpf_audio_stream_t *stream)
+{
+       apr_size_t frame_size;
+       mpf_rtp_stream_t *rtp_stream = stream->obj;
+       rtp_transmitter_t *transmitter = &rtp_stream->transmitter;
+       if(!rtp_stream->socket || !rtp_stream->remote_media) {
+               return FALSE;
+       }
+
+       if(!transmitter->ptime) {
+               if(rtp_stream->config && rtp_stream->config->ptime) {
+                       transmitter->ptime = rtp_stream->config->ptime;
+               }
+               else {
+                       transmitter->ptime = 20;
+               }
+       }
+       transmitter->packet_frames = transmitter->ptime / CODEC_FRAME_TIME_BASE;
+       transmitter->current_frames = 0;
+
+       frame_size = mpf_codec_frame_size_calculate(
+                                                       stream->tx_codec->descriptor,
+                                                       stream->tx_codec->attribs);
+       transmitter->packet_data = apr_palloc(
+                                                       rtp_stream->pool,
+                                                       sizeof(rtp_header_t) + transmitter->packet_frames * frame_size);
+       
+       transmitter->inactivity = 1;
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open RTP Transmit %s:%hu -> %s:%hu",
+                       rtp_stream->local_media->base.ip.buf,
+                       rtp_stream->local_media->base.port,
+                       rtp_stream->remote_media->base.ip.buf,
+                       rtp_stream->remote_media->base.port);
+       return TRUE;
+}
+
+static apt_bool_t mpf_rtp_tx_stream_close(mpf_audio_stream_t *stream)
+{
+       mpf_rtp_stream_t *rtp_stream = stream->obj;
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close RTP Transmit %s:%hu -> %s:%hu [s:%lu]",
+                       rtp_stream->local_media->base.ip.buf,
+                       rtp_stream->local_media->base.port,
+                       rtp_stream->remote_media->base.ip.buf,
+                       rtp_stream->remote_media->base.port,
+                       rtp_stream->transmitter.stat.sent_packets);
+       return TRUE;
+}
+
+
+static APR_INLINE void rtp_header_prepare(rtp_transmitter_t *transmitter, apr_byte_t payload_type)
+{
+       rtp_header_t *header = (rtp_header_t*)transmitter->packet_data;
+
+#if PRINT_RTP_PACKET_STAT
+       printf("> RTP time=%6lu ssrc=%8lx pt=%3u %cts=%9lu seq=%5u\n",
+               (apr_uint32_t)apr_time_usec(apr_time_now()),
+               transmitter->ssrc, payload_type, transmitter->inactivity ? '*' : ' ',
+               transmitter->timestamp, transmitter->last_seq_num);
+#endif 
+       header->version = RTP_VERSION;
+       header->padding = 0;
+       header->extension = 0;
+       header->count = 0;
+       header->marker = transmitter->inactivity;
+       header->type = payload_type;
+       header->sequence = htons(++transmitter->last_seq_num);
+       header->timestamp = htonl(transmitter->timestamp);
+       header->ssrc = htonl(transmitter->ssrc);
+
+       if(transmitter->inactivity) {
+               transmitter->inactivity = 0;
+       }
+
+       transmitter->packet_size = sizeof(rtp_header_t);
+}
+
+static apt_bool_t mpf_rtp_stream_transmit(mpf_audio_stream_t *stream, const mpf_frame_t *frame)
+{
+       apt_bool_t status = TRUE;
+       mpf_rtp_stream_t *rtp_stream = stream->obj;
+       rtp_transmitter_t *transmitter = &rtp_stream->transmitter;
+
+       transmitter->timestamp += transmitter->samples_per_frame;
+
+       if(transmitter->current_frames == 0) {
+               if(frame->type == MEDIA_FRAME_TYPE_NONE) {
+                       transmitter->inactivity = 1;
+               }
+               else {
+                       rtp_header_prepare(transmitter,stream->tx_codec->descriptor->payload_type);
+               }
+       }
+       
+       if(!transmitter->inactivity) {
+               memcpy(
+                       transmitter->packet_data + transmitter->packet_size,
+                       frame->codec_frame.buffer,
+                       frame->codec_frame.size);
+               transmitter->packet_size += frame->codec_frame.size;
+
+               if(++transmitter->current_frames == transmitter->packet_frames) {
+                       if(apr_socket_sendto(
+                                                               rtp_stream->socket,
+                                                               rtp_stream->remote_sockaddr,
+                                                               0,
+                                                               transmitter->packet_data,
+                                                               &transmitter->packet_size) == APR_SUCCESS) {
+                               transmitter->stat.sent_packets++;
+                       }
+                       else {
+                               status = FALSE;
+                       }
+                       transmitter->current_frames = 0;
+               }
+       }
+
+       return status;
+}
+
+static apt_bool_t mpf_rtp_socket_create(mpf_rtp_stream_t *stream, mpf_rtp_media_descriptor_t *local_media)
+{
+       if(stream->socket) {
+               apr_socket_close(stream->socket);
+               stream->socket = NULL;
+       }
+       
+       stream->local_sockaddr = NULL;
+       apr_sockaddr_info_get(
+               &stream->local_sockaddr,
+               local_media->base.ip.buf,
+               APR_INET,
+               local_media->base.port,
+               0,
+               stream->pool);
+       if(!stream->local_sockaddr) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Failed to Get Sockaddr %s:%hu",
+                               local_media->base.ip.buf,
+                               local_media->base.port);
+               return FALSE;
+       }
+       if(apr_socket_create(&stream->socket,stream->local_sockaddr->family,SOCK_DGRAM,0,stream->pool) != APR_SUCCESS) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Failed to Create Socket %s:%hu",
+                               local_media->base.ip.buf,
+                               local_media->base.port);
+               return FALSE;
+       }
+       
+       apr_socket_opt_set(stream->socket,APR_SO_NONBLOCK,1);
+       apr_socket_timeout_set(stream->socket,0);
+       apr_socket_opt_set(stream->socket,APR_SO_REUSEADDR,1);
+
+       if(apr_socket_bind(stream->socket,stream->local_sockaddr) != APR_SUCCESS) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Failed to Bind Socket to %s:%hu",
+                               local_media->base.ip.buf,
+                               local_media->base.port);
+               apr_socket_close(stream->socket);
+               stream->socket = NULL;
+               return FALSE;
+       }
+       return TRUE;
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_rtp_termination_factory.c b/libs/unimrcp/libs/mpf/src/mpf_rtp_termination_factory.c
new file mode 100644 (file)
index 0000000..5f5e058
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mpf_termination.h"
+#include "mpf_rtp_termination_factory.h"
+#include "mpf_rtp_stream.h"
+#include "apt_log.h"
+
+typedef struct rtp_termination_factory_t rtp_termination_factory_t;
+struct rtp_termination_factory_t {
+       mpf_termination_factory_t base;
+       mpf_rtp_config_t         *config;
+};
+
+static apt_bool_t mpf_rtp_termination_destroy(mpf_termination_t *termination)
+{
+       return TRUE;
+}
+
+static apt_bool_t mpf_rtp_termination_modify(mpf_termination_t *termination, void *descriptor)
+{
+       mpf_rtp_termination_descriptor_t *rtp_descriptor = descriptor;
+       mpf_audio_stream_t *audio_stream = termination->audio_stream;
+       if(!audio_stream) {
+               rtp_termination_factory_t *termination_factory = (rtp_termination_factory_t*)termination->termination_factory;
+               audio_stream = mpf_rtp_stream_create(termination,termination_factory->config,termination->pool);
+               if(!audio_stream) {
+                       return FALSE;
+               }
+               termination->audio_stream = audio_stream;
+       }
+
+       return mpf_rtp_stream_modify(audio_stream,&rtp_descriptor->audio);
+}
+
+static const mpf_termination_vtable_t rtp_vtable = {
+       mpf_rtp_termination_destroy,
+       mpf_rtp_termination_modify,
+};
+
+static mpf_termination_t* mpf_rtp_termination_create(mpf_termination_factory_t *termination_factory, void *obj, apr_pool_t *pool)
+{
+       return mpf_termination_base_create(termination_factory,obj,&rtp_vtable,NULL,NULL,pool);
+}
+
+MPF_DECLARE(mpf_termination_factory_t*) mpf_rtp_termination_factory_create(
+                                                                                       mpf_rtp_config_t *rtp_config,
+                                                                                       apr_pool_t *pool)
+{
+       rtp_termination_factory_t *rtp_termination_factory;
+       if(!rtp_config) {
+               return NULL;
+       }
+       rtp_config->rtp_port_cur = rtp_config->rtp_port_min;
+       rtp_termination_factory = apr_palloc(pool,sizeof(rtp_termination_factory_t));
+       rtp_termination_factory->base.create_termination = mpf_rtp_termination_create;
+       rtp_termination_factory->config = rtp_config;
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create RTP Termination Factory %s:[%hu,%hu]",
+                                                                       rtp_config->ip.buf,
+                                                                       rtp_config->rtp_port_min,
+                                                                       rtp_config->rtp_port_max);
+       return &rtp_termination_factory->base;
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_termination.c b/libs/unimrcp/libs/mpf/src/mpf_termination.c
new file mode 100644 (file)
index 0000000..2c97544
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mpf_termination.h"
+#include "mpf_stream.h"
+#include "mpf_codec_manager.h"
+
+const mpf_codec_descriptor_t* l16_descriptor_get();
+
+MPF_DECLARE(mpf_termination_t*) mpf_termination_base_create(
+                                                                               mpf_termination_factory_t *termination_factory,
+                                                                               void *obj,
+                                                                               const mpf_termination_vtable_t *vtable,
+                                                                               mpf_audio_stream_t *audio_stream,
+                                                                               mpf_video_stream_t *video_stream,
+                                                                               apr_pool_t *pool)
+{
+       mpf_termination_t *termination = apr_palloc(pool,sizeof(mpf_termination_t));
+       termination->pool = pool;
+       termination->obj = obj;
+       termination->event_handler_obj = NULL;
+       termination->event_handler = NULL;
+       termination->codec_manager = NULL;
+       termination->termination_factory = termination_factory;
+       termination->vtable = vtable;
+       termination->slot = 0;
+       if(audio_stream) {
+               audio_stream->termination = termination;
+       }
+       if(video_stream) {
+               video_stream->termination = termination;
+       }
+       termination->audio_stream = audio_stream;
+       termination->video_stream = video_stream;
+       return termination;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_termination_destroy(mpf_termination_t *termination)
+{
+       if(termination->vtable && termination->vtable->destroy) {
+               termination->vtable->destroy(termination);
+       }
+       return TRUE;
+}
+
+MPF_DECLARE(void*) mpf_termination_object_get(mpf_termination_t *termination)
+{
+       return termination->obj;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_termination_modify(mpf_termination_t *termination, void *descriptor)
+{
+       if(termination->vtable && termination->vtable->modify) {
+               termination->vtable->modify(termination,descriptor);
+       }
+       return TRUE;
+}
+
+static mpf_codec_t* mpf_termination_default_codec_create(mpf_termination_t *termination)
+{
+       mpf_codec_t *codec;
+       const mpf_codec_descriptor_t *default_descriptor = l16_descriptor_get();
+       mpf_codec_descriptor_t *descriptor = apr_palloc(termination->pool,sizeof(mpf_codec_descriptor_t));
+       mpf_codec_descriptor_init(descriptor);
+       *descriptor = *default_descriptor;
+       codec = mpf_codec_manager_codec_get(
+               termination->codec_manager,
+               descriptor,
+               termination->pool);
+       return codec;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_termination_validate(mpf_termination_t *termination)
+{
+       mpf_audio_stream_t *audio_stream;
+       if(!termination) {
+               return FALSE;
+       }
+       audio_stream = termination->audio_stream;
+       if(audio_stream) {
+               if(!audio_stream->vtable) {
+                       return FALSE;
+               }
+               if((audio_stream->mode & STREAM_MODE_RECEIVE) == STREAM_MODE_RECEIVE) {
+                       if(!audio_stream->rx_codec) {
+                               audio_stream->rx_codec = mpf_termination_default_codec_create(termination);
+                       }
+               }
+               if((audio_stream->mode & STREAM_MODE_SEND) == STREAM_MODE_SEND) {
+                       if(!audio_stream->tx_codec) {
+                               audio_stream->tx_codec = mpf_termination_default_codec_create(termination);
+                       }
+               }
+       }
+       return TRUE;
+}
+
+
+/** Create MPF termination by termination factory */
+MPF_DECLARE(mpf_termination_t*) mpf_termination_create(
+                                                                               mpf_termination_factory_t *termination_factory,
+                                                                               void *obj,
+                                                                               apr_pool_t *pool)
+{
+       if(termination_factory && termination_factory->create_termination) {
+               return termination_factory->create_termination(termination_factory,obj,pool);
+       }
+       return NULL;
+}
+
+/** Create raw MPF termination. */
+MPF_DECLARE(mpf_termination_t*) mpf_raw_termination_create(
+                                                                               void *obj,
+                                                                               mpf_audio_stream_t *audio_stream,
+                                                                               mpf_video_stream_t *video_stream,
+                                                                               apr_pool_t *pool)
+{
+       return mpf_termination_base_create(NULL,obj,NULL,audio_stream,video_stream,pool);
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_timer.c b/libs/unimrcp/libs/mpf/src/mpf_timer.c
new file mode 100644 (file)
index 0000000..aaca492
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mpf_timer.h"
+
+#ifdef WIN32
+#define ENABLE_MULTIMEDIA_TIMERS
+#endif
+
+#ifdef ENABLE_MULTIMEDIA_TIMERS
+
+#pragma warning(disable:4201)
+#include <mmsystem.h>
+#include <windows.h>
+
+#ifndef TIME_KILL_SYNCHRONOUS
+#define TIME_KILL_SYNCHRONOUS   0x0100
+#endif
+
+struct mpf_timer_t {
+       unsigned int     timer_id;
+       mpf_timer_proc_f timer_proc;
+       void            *obj;
+};
+
+#define MAX_MEDIA_TIMERS 10
+
+static mpf_timer_t media_timer_set[MAX_MEDIA_TIMERS];
+
+static void CALLBACK mm_timer_proc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2);
+
+MPF_DECLARE(mpf_timer_t*) mpf_timer_start(unsigned long timeout, mpf_timer_proc_f timer_proc, void *obj, apr_pool_t *pool)
+{
+       mpf_timer_t *timer = NULL;
+       size_t i;
+       for(i = 0; i<MAX_MEDIA_TIMERS; i++) {
+               if(!media_timer_set[i].timer_id) {
+                       timer = &media_timer_set[i];
+                       break;
+               }
+       }
+               
+       if(timer) {
+               timer->timer_proc = timer_proc;
+               timer->obj = obj;
+               timer->timer_id = timeSetEvent(timeout, 0, mm_timer_proc, i, 
+                       TIME_PERIODIC | TIME_CALLBACK_FUNCTION | TIME_KILL_SYNCHRONOUS);
+               if(!timer->timer_id) {
+                       timer = NULL;
+               }
+       }
+       return timer;
+}
+
+MPF_DECLARE(void) mpf_timer_stop(mpf_timer_t *timer)
+{
+       if(timer) {
+               timeKillEvent(timer->timer_id);
+               timer->timer_id = 0;
+               timer->timer_proc = NULL;
+               timer->obj = NULL;
+       }
+}
+
+static void CALLBACK mm_timer_proc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
+{
+       mpf_timer_t *timer;
+       if(dwUser >= MAX_MEDIA_TIMERS) {
+               return;
+       }
+       timer = &media_timer_set[dwUser];
+       timer->timer_proc(timer,timer->obj);
+}
+
+#else
+
+#include <apr_thread_proc.h>
+
+struct mpf_timer_t {
+       apr_thread_t    *thread;
+       apr_byte_t       running;
+
+       unsigned long    timeout;
+       mpf_timer_proc_f timer_proc;
+       void            *obj;
+};
+
+static void* APR_THREAD_FUNC timer_thread_proc(apr_thread_t *thread, void *data);
+
+MPF_DECLARE(mpf_timer_t*) mpf_timer_start(unsigned long timeout, mpf_timer_proc_f timer_proc, void *obj, apr_pool_t *pool)
+{
+       mpf_timer_t *timer = apr_palloc(pool,sizeof(mpf_timer_t));
+       timer->timeout = timeout;
+       timer->timer_proc = timer_proc;
+       timer->obj = obj;
+       timer->running = 1;
+       if(apr_thread_create(&timer->thread,NULL,timer_thread_proc,timer,pool) != APR_SUCCESS) {
+               return NULL;
+       }
+       return timer;
+}
+
+MPF_DECLARE(void) mpf_timer_stop(mpf_timer_t *timer)
+{
+       if(timer) {
+               timer->running = 0;
+               if(timer->thread) {
+                       apr_status_t s;
+                       apr_thread_join(&s,timer->thread);
+                       timer->thread = NULL;
+               }
+       }
+}
+
+static void* APR_THREAD_FUNC timer_thread_proc(apr_thread_t *thread, void *data)
+{
+       mpf_timer_t *timer = data;
+       apr_interval_time_t timeout = timer->timeout * 1000;
+       apr_interval_time_t time_drift = 0;
+       apr_time_t time_now, time_last;
+       
+       time_now = apr_time_now();
+       while(timer->running) {
+               time_last = time_now;
+               timer->timer_proc(timer,timer->obj);
+
+               if(timeout > time_drift) {
+                       apr_sleep(timeout - time_drift);
+               }
+
+               time_now = apr_time_now();
+               time_drift += time_now - time_last - timeout;
+#if 0
+               printf("time_drift=%d\n",time_drift);
+#endif
+       }
+       
+       return NULL;
+}
+
+#endif
diff --git a/libs/unimrcp/libs/mrcp-client/Makefile.am b/libs/unimrcp/libs/mrcp-client/Makefile.am
new file mode 100644 (file)
index 0000000..ec74936
--- /dev/null
@@ -0,0 +1,22 @@
+MAINTAINERCLEANFILES       = Makefile.in
+
+INCLUDES                    = -I$(top_srcdir)/libs/mrcp-client/include \
+                              -I$(top_srcdir)/libs/mrcp-signaling/include \
+                              -I$(top_srcdir)/libs/mrcpv2-transport/include \
+                              -I$(top_srcdir)/libs/mrcp/include \
+                              -I$(top_srcdir)/libs/mrcp/message/include \
+                              -I$(top_srcdir)/libs/mrcp/control/include \
+                              -I$(top_srcdir)/libs/mrcp/resources/include \
+                              -I$(top_srcdir)/libs/mpf/include \
+                              -I$(top_srcdir)/libs/apr-toolkit/include \
+                              $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+noinst_LTLIBRARIES          = libmrcpclient.la
+
+include_HEADERS             = include/mrcp_client_types.h \
+                              include/mrcp_client.h \
+                              include/mrcp_client_session.h \
+                              include/mrcp_application.h
+
+libmrcpclient_la_SOURCES    = src/mrcp_client.c \
+                              src/mrcp_client_session.c
diff --git a/libs/unimrcp/libs/mrcp-client/include/mrcp_application.h b/libs/unimrcp/libs/mrcp-client/include/mrcp_application.h
new file mode 100644 (file)
index 0000000..fbd4c42
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_APPLICATION_H__
+#define __MRCP_APPLICATION_H__
+
+/**
+ * @file mrcp_application.h
+ * @brief MRCP User Level Application Interface
+ */ 
+
+#include "mrcp_client_types.h"
+#include "mpf_rtp_descriptor.h"
+#include "mpf_stream.h"
+
+APT_BEGIN_EXTERN_C
+
+/** MRCP application message declaration */
+typedef struct mrcp_app_message_t mrcp_app_message_t;
+
+/** MRCP signaling message declaration */
+typedef struct mrcp_sig_message_t mrcp_sig_message_t;
+
+/** MRCP application message dispatcher declaration */
+typedef struct mrcp_app_message_dispatcher_t mrcp_app_message_dispatcher_t;
+
+/** MRCP application message handler */
+typedef apt_bool_t (*mrcp_app_message_handler_f)(const mrcp_app_message_t *app_message);
+
+/** Enumeration of MRCP signaling message types */
+typedef enum {
+       MRCP_SIG_MESSAGE_TYPE_REQUEST,  /**< request message */
+       MRCP_SIG_MESSAGE_TYPE_RESPONSE, /**< response message */
+       MRCP_SIG_MESSAGE_TYPE_EVENT     /**< event message */
+} mrcp_sig_message_type_e;
+
+/** Enumeration of MRCP signaling status codes */
+typedef enum {
+       MRCP_SIG_STATUS_CODE_SUCCESS,   /**< indicates success */
+       MRCP_SIG_STATUS_CODE_FAILURE,   /**< request failed */
+       MRCP_SIG_STATUS_CODE_TERMINATE, /**< request failed, session/channel/connection unexpectedly terminated */
+       MRCP_SIG_STATUS_CODE_CANCEL     /**< request cancelled */
+} mrcp_sig_status_code_e;
+
+
+/** Enumeration of MRCP signaling commands (requests/responses) */
+typedef enum {
+       MRCP_SIG_COMMAND_SESSION_UPDATE,
+       MRCP_SIG_COMMAND_SESSION_TERMINATE,
+       MRCP_SIG_COMMAND_CHANNEL_ADD,
+       MRCP_SIG_COMMAND_CHANNEL_REMOVE,
+       MRCP_SIG_COMMAND_RESOURCE_DISCOVER
+} mrcp_sig_command_e;
+
+/** Enumeration of MRCP signaling events */
+typedef enum {
+       MRCP_SIG_EVENT_READY,
+       MRCP_SIG_EVENT_TERMINATE
+} mrcp_sig_event_e;
+
+
+/** Enumeration of MRCP application message types */
+typedef enum {
+       MRCP_APP_MESSAGE_TYPE_SIGNALING, /**< signaling message type */
+       MRCP_APP_MESSAGE_TYPE_CONTROL    /**< control message type */
+} mrcp_app_message_type_e;
+
+/** MRCP signaling message definition */
+struct mrcp_sig_message_t {
+       /** Message type (request/response/event) */
+       mrcp_sig_message_type_e message_type;
+       /** Command (request/response) identifier */
+       mrcp_sig_command_e      command_id;
+       /** Event identifier */
+       mrcp_sig_event_e        event_id;
+       /** Status code used in response */
+       mrcp_sig_status_code_e  status;
+};
+
+
+/** MRCP application message definition */
+struct mrcp_app_message_t {
+       /** Message type (signaling/control) */
+       mrcp_app_message_type_e message_type;
+
+       /** Application */
+       mrcp_application_t        *application;
+       /** Session */
+       mrcp_session_t            *session;
+       /** Channel */
+       mrcp_channel_t            *channel;
+       /** Session/resource descriptor */
+       mrcp_session_descriptor_t *descriptor;
+
+       /** MRCP signaling message (used if message_type == MRCP_APP_MESSAGE_SIGNALING) */
+       mrcp_sig_message_t         sig_message;
+       /** MRCP control message (used if message_type == MRCP_APP_MESSAGE_CONTROL) */
+       mrcp_message_t            *control_message;
+};
+
+/** MRCP application message dispatcher interface */
+struct mrcp_app_message_dispatcher_t {
+       /** Response to mrcp_application_session_update()request */
+       apt_bool_t (*on_session_update)(mrcp_application_t *application, mrcp_session_t *session, mrcp_sig_status_code_e status);
+       /** Response to mrcp_application_session_terminate()request */
+       apt_bool_t (*on_session_terminate)(mrcp_application_t *application, mrcp_session_t *session, mrcp_sig_status_code_e status);
+       
+       /** Response to mrcp_application_channel_add() request */
+       apt_bool_t (*on_channel_add)(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_sig_status_code_e status);
+       /** Response to mrcp_application_channel_remove() request */
+       apt_bool_t (*on_channel_remove)(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_sig_status_code_e status);
+
+       /** Response (event) to mrcp_application_message_send() request */
+       apt_bool_t (*on_message_receive)(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_message_t *message);
+
+       /** Event indicating client stack is started and ready to process requests from the application */
+       apt_bool_t (*on_ready)(mrcp_application_t *application, mrcp_sig_status_code_e status);
+
+       /** Event indicating unexpected session/channel termination */
+       apt_bool_t (*on_terminate_event)(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel);
+
+       /** Response to mrcp_application_resource_discover() request */
+       apt_bool_t (*on_resource_discover)(mrcp_application_t *application, mrcp_session_t *session, mrcp_session_descriptor_t *descriptor, mrcp_sig_status_code_e status);
+};
+
+
+
+/**
+ * Create application instance.
+ * @param handler the event handler
+ * @param obj the external object
+ * @param pool the pool to allocate memory from
+ */
+MRCP_DECLARE(mrcp_application_t*) mrcp_application_create(const mrcp_app_message_handler_f handler, void *obj, apr_pool_t *pool);
+
+/**
+ * Destroy application instance.
+ * @param application the application to destroy
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_application_destroy(mrcp_application_t *application);
+
+/**
+ * Get external object associated with the application.
+ * @param application the application to get object from
+ */
+MRCP_DECLARE(void*) mrcp_application_object_get(mrcp_application_t *application);
+
+/**
+ * Get dir layout structure.
+ * @param application the application to get dir layout from
+ */
+MRCP_DECLARE(const apt_dir_layout_t*) mrcp_application_dir_layout_get(mrcp_application_t *application);
+
+/**
+ * Create session.
+ * @param application the entire application
+ * @param profile the name of the profile to use
+ * @param obj the external object
+ * @return the created session instance
+ */
+MRCP_DECLARE(mrcp_session_t*) mrcp_application_session_create(mrcp_application_t *application, const char *profile, void *obj);
+
+/**
+ * Get external object associated with the session.
+ * @param session the session to get object from
+ */
+MRCP_DECLARE(void*) mrcp_application_session_object_get(mrcp_session_t *session);
+
+/** 
+ * Send session update request.
+ * @param session the session to update
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_application_session_update(mrcp_session_t *session);
+
+/** 
+ * Send session termination request.
+ * @param session the session to terminate
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_application_session_terminate(mrcp_session_t *session);
+
+/** 
+ * Destroy client session (session must be terminated prior to destroy).
+ * @param session the session to destroy
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_application_session_destroy(mrcp_session_t *session);
+
+
+/** 
+ * Create control channel.
+ * @param session the session to create channel for
+ * @param resource_id the resource identifier of the channel
+ * @param termination the media termination
+ * @param rtp_descriptor the RTP termination descriptor (NULL by default)
+ * @param obj the external object
+ */
+MRCP_DECLARE(mrcp_channel_t*) mrcp_application_channel_create(
+                                                                       mrcp_session_t *session, 
+                                                                       mrcp_resource_id resource_id, 
+                                                                       mpf_termination_t *termination, 
+                                                                       mpf_rtp_termination_descriptor_t *rtp_descriptor, 
+                                                                       void *obj);
+
+/**
+ * Get external object associated with the channel.
+ * @param channel the channel to get object from
+ */
+MRCP_DECLARE(void*) mrcp_application_channel_object_get(mrcp_channel_t *channel);
+
+/**
+ * Get RTP termination descriptor.
+ * @param channel the channel to get descriptor from
+ */
+MRCP_DECLARE(mpf_rtp_termination_descriptor_t*) mrcp_application_rtp_descriptor_get(mrcp_channel_t *channel);
+
+/** 
+ * Send channel add request.
+ * @param session the session to create channel for
+ * @param channel the control channel
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_application_channel_add(mrcp_session_t *session, mrcp_channel_t *channel);
+
+/** 
+ * Create MRCP message.
+ * @param session the session
+ * @param channel the control channel
+ * @param method_id the method identifier of MRCP message
+ */
+MRCP_DECLARE(mrcp_message_t*) mrcp_application_message_create(mrcp_session_t *session, mrcp_channel_t *channel, mrcp_method_id method_id);
+
+/** 
+ * Send MRCP message.
+ * @param session the session
+ * @param channel the control channel
+ * @param message the MRCP message to send
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_application_message_send(mrcp_session_t *session, mrcp_channel_t *channel, mrcp_message_t *message);
+
+/** 
+ * Remove channel.
+ * @param session the session to remove channel from
+ * @param channel the control channel to remove
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_application_channel_remove(mrcp_session_t *session, mrcp_channel_t *channel);
+
+/** 
+ * Discover resources.
+ * @param session the session to use as communication object
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_application_resource_discover(mrcp_session_t *session);
+
+/**
+ * Dispatch application message.
+ * @param dispatcher the dispatcher inteface
+ * @param app_message the message to dispatch
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_application_message_dispatch(const mrcp_app_message_dispatcher_t *dispatcher, const mrcp_app_message_t *app_message);
+
+
+/** Create source media termination
+ * @param session the session to create channel for
+ * @param stream_vtable the virtual table of audio stream
+ * @param codec_descriptor the descriptor of audio stream (NULL by default)
+ * @param obj the external object
+ */
+MRCP_DECLARE(mpf_termination_t*) mrcp_application_source_termination_create(
+                                                                               mrcp_session_t *session,
+                                                                               const mpf_audio_stream_vtable_t *stream_vtable,
+                                                                               mpf_codec_descriptor_t *codec_descriptor,
+                                                                               void *obj);
+/** Create sink media termination
+ * @param session the session to create channel for
+ * @param stream_vtable the virtual table of audio stream
+ * @param codec_descriptor the descriptor of audio stream (NULL by default)
+ * @param obj the external object
+ */
+MRCP_DECLARE(mpf_termination_t*) mrcp_application_sink_termination_create(
+                                                                               mrcp_session_t *session,
+                                                                               const mpf_audio_stream_vtable_t *stream_vtable,
+                                                                               mpf_codec_descriptor_t *codec_descriptor,
+                                                                               void *obj);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_APPLICATION_H__*/
diff --git a/libs/unimrcp/libs/mrcp-client/include/mrcp_client.h b/libs/unimrcp/libs/mrcp-client/include/mrcp_client.h
new file mode 100644 (file)
index 0000000..e155b76
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_CLIENT_H__
+#define __MRCP_CLIENT_H__
+
+/**
+ * @file mrcp_client.h
+ * @brief MRCP Client
+ */ 
+
+#include "mrcp_client_types.h"
+#include "apt_task.h"
+
+APT_BEGIN_EXTERN_C
+
+/**
+ * Create MRCP client instance.
+ * @return the created client instance
+ */
+MRCP_DECLARE(mrcp_client_t*) mrcp_client_create(apt_dir_layout_t *dir_layout);
+
+/**
+ * Start message processing loop.
+ * @param client the MRCP client to start
+ * @return the created client instance
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_client_start(mrcp_client_t *client);
+
+/**
+ * Shutdown message processing loop.
+ * @param client the MRCP client to shutdown
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_client_shutdown(mrcp_client_t *client);
+
+/**
+ * Destroy MRCP client.
+ * @param client the MRCP client to destroy
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_client_destroy(mrcp_client_t *client);
+
+
+/**
+ * Register MRCP resource factory.
+ * @param client the MRCP client to set resource factory for
+ * @param resource_factory the resource factory to set
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_client_resource_factory_register(mrcp_client_t *client, mrcp_resource_factory_t *resource_factory);
+
+/**
+ * Register codec manager.
+ * @param client the MRCP client to set codec manager for
+ * @param codec_manager the codec manager to set
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_client_codec_manager_register(mrcp_client_t *client, mpf_codec_manager_t *codec_manager);
+
+/**
+ * Get registered codec manager.
+ * @param client the MRCP client to get codec manager from
+ */
+MRCP_DECLARE(const mpf_codec_manager_t*) mrcp_client_codec_manager_get(mrcp_client_t *client);
+
+/**
+ * Register media engine.
+ * @param client the MRCP client to set media engine for
+ * @param media_engine the media engine to set
+ * @param name the name of the media engine
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_client_media_engine_register(mrcp_client_t *client, mpf_engine_t *media_engine, const char *name);
+
+/**
+ * Register RTP termination factory.
+ * @param client the MRCP client to set termination factory for
+ * @param rtp_termination_factory the termination factory
+ * @param name the name of the factory
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_client_rtp_factory_register(mrcp_client_t *client, mpf_termination_factory_t *rtp_termination_factory, const char *name);
+
+/**
+ * Register MRCP signaling agent.
+ * @param client the MRCP client to set signaling agent for
+ * @param signaling_agent the signaling agent to set
+ * @param name the name of the agent
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_client_signaling_agent_register(mrcp_client_t *client, mrcp_sig_agent_t *signaling_agent, const char *name);
+
+/**
+ * Register MRCP connection agent (MRCPv2 only).
+ * @param client the MRCP client to set connection agent for
+ * @param connection_agent the connection agent to set
+ * @param name the name of the agent
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_client_connection_agent_register(mrcp_client_t *client, mrcp_connection_agent_t *connection_agent, const char *name);
+
+/** Create MRCP profile */
+MRCP_DECLARE(mrcp_profile_t*) mrcp_client_profile_create(
+                                                                       mrcp_resource_factory_t *resource_factory,
+                                                                       mrcp_sig_agent_t *signaling_agent,
+                                                                       mrcp_connection_agent_t *connection_agent,
+                                                                       mpf_engine_t *media_engine,
+                                                                       mpf_termination_factory_t *rtp_factory,
+                                                                       apr_pool_t *pool);
+
+/**
+ * Register MRCP profile.
+ * @param client the MRCP client to set profile for
+ * @param profile the profile to set
+ * @param name the name of the profile
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_client_profile_register(mrcp_client_t *client, mrcp_profile_t *profile, const char *name);
+
+/**
+ * Register MRCP application.
+ * @param client the MRCP client to set application for
+ * @param application the application to set
+ * @param name the name of the application
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_client_application_register(mrcp_client_t *client, mrcp_application_t *application, const char *name);
+
+/**
+ * Get memory pool.
+ * @param client the MRCP client to get memory pool from
+ */
+MRCP_DECLARE(apr_pool_t*) mrcp_client_memory_pool_get(mrcp_client_t *client);
+
+/**
+ * Get media engine by name.
+ * @param client the MRCP client to get media engine from
+ * @param name the name of the media engine to lookup
+ */
+MRCP_DECLARE(mpf_engine_t*) mrcp_client_media_engine_get(mrcp_client_t *client, const char *name);
+
+/**
+ * Get RTP termination factory by name.
+ * @param client the MRCP client to get from
+ * @param name the name to lookup
+ */
+MRCP_DECLARE(mpf_termination_factory_t*) mrcp_client_rtp_factory_get(mrcp_client_t *client, const char *name);
+
+/**
+ * Get signaling agent by name.
+ * @param client the MRCP client to get from
+ * @param name the name to lookup
+ */
+MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_client_signaling_agent_get(mrcp_client_t *client, const char *name);
+
+/**
+ * Get connection agent by name.
+ * @param client the MRCP client to get from
+ * @param name the name to lookup
+ */
+MRCP_DECLARE(mrcp_connection_agent_t*) mrcp_client_connection_agent_get(mrcp_client_t *client, const char *name);
+
+/**
+ * Get profile by name.
+ * @param client the MRCP client to get from
+ * @param name the name to lookup
+ */
+MRCP_DECLARE(mrcp_profile_t*) mrcp_client_profile_get(mrcp_client_t *client, const char *name);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_CLIENT_H__*/
diff --git a/libs/unimrcp/libs/mrcp-client/include/mrcp_client_session.h b/libs/unimrcp/libs/mrcp-client/include/mrcp_client_session.h
new file mode 100644 (file)
index 0000000..c128201
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_CLIENT_SESSION_H__
+#define __MRCP_CLIENT_SESSION_H__
+
+/**
+ * @file mrcp_client_session.h
+ * @brief MRCP Client Session
+ */ 
+
+#include "mrcp_client_types.h"
+#include "mrcp_application.h"
+#include "mrcp_session.h"
+#include "mpf_message.h"
+#include "apt_task_msg.h"
+#include "apt_obj_list.h"
+
+APT_BEGIN_EXTERN_C
+
+/** RTP termination slot declaration */
+typedef struct rtp_termination_slot_t rtp_termination_slot_t;
+
+/** MRCP client session declaration */
+typedef struct mrcp_client_session_t mrcp_client_session_t;
+
+/** MRCP client session */
+struct mrcp_client_session_t {
+       /** Session base */
+       mrcp_session_t             base;
+       /** Application session belongs to */
+       mrcp_application_t        *application;
+       /** External object associated with session */
+       void                      *app_obj;
+       /** Profile to use */
+       mrcp_profile_t            *profile;
+
+       /** Media context */
+       mpf_context_t             *context;
+       /** Codec manager */
+       const mpf_codec_manager_t *codec_manager;
+
+
+       /** RTP termination array (mrcp_termination_slot_t) */
+       apr_array_header_t        *terminations;
+       /** MRCP control channel array (mrcp_channel_t*) */
+       apr_array_header_t        *channels;
+
+       /** Indicates whether session is already added to session table */
+       apt_bool_t                 registered;
+
+       /** In-progress offer */
+       mrcp_session_descriptor_t *offer;
+       /** In-progress answer */
+       mrcp_session_descriptor_t *answer;
+
+       /** MRCP application active request */
+       const mrcp_app_message_t  *active_request;
+       /** MRCP application request queue */
+       apt_obj_list_t            *request_queue;
+
+       /** Number of in-progress offer requests (flags) */
+       apr_size_t                 offer_flag_count;
+       /** Number of in-progress answer requests (flags) */
+       apr_size_t                 answer_flag_count;
+       /** Number of in-progress terminate requests (flags) */
+       apr_size_t                 terminate_flag_count;
+};
+
+/** MRCP channel */
+struct mrcp_channel_t {
+       /** Memory pool */
+       apr_pool_t             *pool;
+       /** External object associated with channel */
+       void                   *obj;
+       /** MRCP resource identifier */
+       mrcp_resource_id        resource_id;
+       /** MRCP resource name */
+       const apt_str_t        *resource_name;
+       /** MRCP resource */
+       mrcp_resource_t        *resource;
+       /** MRCP session entire channel belongs to */
+       mrcp_session_t         *session;
+       /** MRCP control channel */
+       mrcp_control_channel_t *control_channel;
+       /** Media termination */
+       mpf_termination_t      *termination;
+       /** Associated RTP termination slot */
+       rtp_termination_slot_t *rtp_termination_slot;
+
+       /** waiting state of control channel */
+       apt_bool_t              waiting_for_channel;         
+       /** waiting state of media termination */
+       apt_bool_t              waiting_for_termination;
+};
+
+/** RTP termination slot */
+struct rtp_termination_slot_t {
+       /** waiting state */
+       apt_bool_t                        waiting;
+       /** RTP termination */
+       mpf_termination_t                *termination;
+       /** RTP termination descriptor */
+       mpf_rtp_termination_descriptor_t *descriptor;
+};
+
+
+/** MRCP profile */
+struct mrcp_profile_t {
+       /** MRCP resource factory */
+       mrcp_resource_factory_t   *resource_factory;
+       /** Media processing engine */
+       mpf_engine_t              *media_engine;
+       /** RTP termination factory */
+       mpf_termination_factory_t *rtp_termination_factory;
+       /** Signaling agent */
+       mrcp_sig_agent_t          *signaling_agent;
+       /** Connection agent */
+       mrcp_connection_agent_t   *connection_agent;
+};
+
+/** MRCP application */
+struct mrcp_application_t {
+       /** External object associated with the application */
+       void                      *obj;
+       /** Application message handler */
+       mrcp_app_message_handler_f handler;
+       /** MRCP client */
+       mrcp_client_t             *client;
+       /** Application task message pool */
+       apt_task_msg_pool_t       *msg_pool;
+};
+
+/** Create client session */
+mrcp_client_session_t* mrcp_client_session_create(mrcp_application_t *application, void *obj);
+/** Create channel */
+mrcp_channel_t* mrcp_client_channel_create(
+                                       mrcp_session_t *session, 
+                                       mrcp_resource_id resource_id, 
+                                       mpf_termination_t *termination, 
+                                       mpf_rtp_termination_descriptor_t *rtp_descriptor, 
+                                       void *obj);
+
+/** Create signaling app_message_t request */
+mrcp_app_message_t* mrcp_client_app_signaling_request_create(mrcp_sig_command_e command_id, apr_pool_t *pool);
+/** Create signaling app_message_t event */
+mrcp_app_message_t* mrcp_client_app_signaling_event_create(mrcp_sig_event_e event_id, apr_pool_t *pool);
+/** Create control app_message_t */
+mrcp_app_message_t* mrcp_client_app_control_message_create(apr_pool_t *pool);
+/** Create response to app_message_t request */
+mrcp_app_message_t* mrcp_client_app_response_create(const mrcp_app_message_t *app_request, mrcp_sig_status_code_e status, apr_pool_t *pool);
+
+/** Process application message */
+apt_bool_t mrcp_client_app_message_process(mrcp_app_message_t *app_message);
+/** Process MPF message */
+apt_bool_t mrcp_client_mpf_message_process(mpf_message_t *mpf_message);
+
+/** Process session answer */
+apt_bool_t mrcp_client_session_answer_process(mrcp_client_session_t *session, mrcp_session_descriptor_t *descriptor);
+/** Process session termination response */
+apt_bool_t mrcp_client_session_terminate_response_process(mrcp_client_session_t *session);
+/** Process session control response */
+apt_bool_t mrcp_client_session_control_response_process(mrcp_client_session_t *session, mrcp_message_t *message);
+/** Process resource discovery response */
+apt_bool_t mrcp_client_session_discover_response_process(mrcp_client_session_t *session, mrcp_session_descriptor_t *descriptor);
+/** Process session termination event */
+apt_bool_t mrcp_client_session_terminate_event_process(mrcp_client_session_t *session);
+
+/** Process channel add event */
+apt_bool_t mrcp_client_on_channel_add(mrcp_channel_t *channel, mrcp_control_descriptor_t *descriptor, apt_bool_t status);
+/** Process channel modify event */
+apt_bool_t mrcp_client_on_channel_modify(mrcp_channel_t *channel, mrcp_control_descriptor_t *descriptor, apt_bool_t status);
+/** Process channel remove event */
+apt_bool_t mrcp_client_on_channel_remove(mrcp_channel_t *channel, apt_bool_t status);
+/** Process message receive event */
+apt_bool_t mrcp_client_on_message_receive(mrcp_channel_t *channel, mrcp_message_t *message);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_CLIENT_SESSION_H__*/
diff --git a/libs/unimrcp/libs/mrcp-client/include/mrcp_client_types.h b/libs/unimrcp/libs/mrcp-client/include/mrcp_client_types.h
new file mode 100644 (file)
index 0000000..4da19f0
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_CLIENT_TYPES_H__
+#define __MRCP_CLIENT_TYPES_H__
+
+/**
+ * @file mrcp_client_types.h
+ * @brief MRCP Client Types
+ */ 
+
+#include "mrcp_sig_types.h"
+#include "mrcp_connection_types.h"
+#include "mpf_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque MRCP client declaration */
+typedef struct mrcp_client_t mrcp_client_t;
+
+/** Opaque MRCP profile declaration */
+typedef struct mrcp_profile_t mrcp_profile_t;
+
+/** Opaque MRCP application declaration */
+typedef struct mrcp_application_t mrcp_application_t;
+
+/** Opaque MRCP channel declaration */
+typedef struct mrcp_channel_t mrcp_channel_t;
+
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_CLIENT_TYPES_H__*/
diff --git a/libs/unimrcp/libs/mrcp-client/mrcpclient.vcproj b/libs/unimrcp/libs/mrcp-client/mrcpclient.vcproj
new file mode 100644 (file)
index 0000000..ed211a0
--- /dev/null
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="mrcpclient"
+       ProjectGUID="{72782932-37CC-46AE-8C7F-9A7B1A6EE108}"
+       RootNamespace="mrcpclient"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\mrcpclient.vsprops"
+                       CharacterSet="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\mrcpclient.vsprops"
+                       CharacterSet="1"
+                       WholeProgramOptimization="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+                       <File
+                               RelativePath=".\include\mrcp_application.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_client.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_client_session.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_client_types.h"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       >
+                       <File
+                               RelativePath=".\src\mrcp_client.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\mrcp_client_session.c"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/libs/mrcp-client/src/mrcp_client.c b/libs/unimrcp/libs/mrcp-client/src/mrcp_client.c
new file mode 100644 (file)
index 0000000..e2e303f
--- /dev/null
@@ -0,0 +1,983 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_hash.h>
+#include "mrcp_client.h"
+#include "mrcp_resource_factory.h"
+#include "mrcp_sig_agent.h"
+#include "mrcp_client_session.h"
+#include "mrcp_client_connection.h"
+#include "mrcp_message.h"
+#include "mpf_engine.h"
+#include "mpf_termination.h"
+#include "mpf_codec_manager.h"
+#include "apt_pool.h"
+#include "apt_consumer_task.h"
+#include "apt_log.h"
+
+#define CLIENT_TASK_NAME "MRCP Client"
+
+/** MRCP client */
+struct mrcp_client_t {
+       /** Main message processing task */
+       apt_consumer_task_t     *task;
+
+       /** MRCP resource factory */
+       mrcp_resource_factory_t *resource_factory;
+       /** Codec manager */
+       mpf_codec_manager_t     *codec_manager;
+       /** Table of media processing engines (mpf_engine_t*) */
+       apr_hash_t              *media_engine_table;
+       /** Table of RTP termination factories (mpf_termination_factory_t*) */
+       apr_hash_t              *rtp_factory_table;
+       /** Table of signaling agents (mrcp_sig_agent_t*) */
+       apr_hash_t              *sig_agent_table;
+       /** Table of connection agents (mrcp_connection_agent_t*) */
+       apr_hash_t              *cnt_agent_table;
+       /** Table of profiles (mrcp_profile_t*) */
+       apr_hash_t              *profile_table;
+
+       /** Table of applications (mrcp_application_t*) */
+       apr_hash_t              *app_table;
+
+       /** Table of sessions/handles */
+       apr_hash_t              *session_table;
+
+       /** Connection task message pool */
+       apt_task_msg_pool_t     *cnt_msg_pool;
+       /** Dir layout structure */
+       apt_dir_layout_t        *dir_layout;
+       /** Memory pool */
+       apr_pool_t              *pool;
+};
+
+
+typedef enum {
+       MRCP_CLIENT_SIGNALING_TASK_MSG = TASK_MSG_USER,
+       MRCP_CLIENT_CONNECTION_TASK_MSG,
+       MRCP_CLIENT_MEDIA_TASK_MSG,
+       MRCP_CLIENT_APPLICATION_TASK_MSG
+} mrcp_client_task_msg_type_e;
+
+/* Signaling agent interface */
+typedef enum {
+       SIG_AGENT_TASK_MSG_ANSWER,
+       SIG_AGENT_TASK_MSG_TERMINATE_RESPONSE,
+       SIG_AGENT_TASK_MSG_CONTROL_RESPONSE,
+       SIG_AGENT_TASK_MSG_DISCOVER_RESPONSE,
+       SIG_AGENT_TASK_MSG_TERMINATE_EVENT
+} sig_agent_task_msg_type_e;
+
+typedef struct sig_agent_task_msg_data_t sig_agent_task_msg_data_t;
+struct sig_agent_task_msg_data_t {
+       mrcp_client_session_t     *session;
+       mrcp_session_descriptor_t *descriptor;
+       mrcp_message_t            *message;
+};
+
+static apt_bool_t mrcp_client_answer_signal(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor);
+static apt_bool_t mrcp_client_terminate_response_signal(mrcp_session_t *session);
+static apt_bool_t mrcp_client_control_response_signal(mrcp_session_t *session, mrcp_message_t *message);
+static apt_bool_t mrcp_client_discover_response_signal(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor);
+
+static apt_bool_t mrcp_client_terminate_event_signal(mrcp_session_t *session);
+
+static const mrcp_session_response_vtable_t session_response_vtable = {
+       mrcp_client_answer_signal,
+       mrcp_client_terminate_response_signal,
+       mrcp_client_control_response_signal,
+       mrcp_client_discover_response_signal
+};
+
+static const mrcp_session_event_vtable_t session_event_vtable = {
+       mrcp_client_terminate_event_signal
+};
+
+/* Connection agent interface */
+typedef enum {
+       CONNECTION_AGENT_TASK_MSG_ADD_CHANNEL,
+       CONNECTION_AGENT_TASK_MSG_MODIFY_CHANNEL,
+       CONNECTION_AGENT_TASK_MSG_REMOVE_CHANNEL,
+       CONNECTION_AGENT_TASK_MSG_RECEIVE_MESSAGE,
+} connection_agent_task_msg_type_e ;
+
+typedef struct connection_agent_task_msg_data_t connection_agent_task_msg_data_t;
+struct connection_agent_task_msg_data_t {
+       mrcp_channel_t            *channel;
+       mrcp_control_descriptor_t *descriptor;
+       mrcp_message_t            *message;
+       apt_bool_t                 status;
+};
+
+static apt_bool_t mrcp_client_channel_add_signal(mrcp_control_channel_t *channel, mrcp_control_descriptor_t *descriptor, apt_bool_t status);
+static apt_bool_t mrcp_client_channel_modify_signal(mrcp_control_channel_t *channel, mrcp_control_descriptor_t *descriptor, apt_bool_t status);
+static apt_bool_t mrcp_client_channel_remove_signal(mrcp_control_channel_t *channel, apt_bool_t status);
+static apt_bool_t mrcp_client_message_signal(mrcp_control_channel_t *channel, mrcp_message_t *message);
+
+static const mrcp_connection_event_vtable_t connection_method_vtable = {
+       mrcp_client_channel_add_signal,
+       mrcp_client_channel_modify_signal,
+       mrcp_client_channel_remove_signal,
+       mrcp_client_message_signal
+};
+
+/* Task interface */
+static void mrcp_client_on_start_complete(apt_task_t *task);
+static void mrcp_client_on_terminate_complete(apt_task_t *task);
+static apt_bool_t mrcp_client_msg_process(apt_task_t *task, apt_task_msg_t *msg);
+static apt_bool_t mrcp_app_signaling_task_msg_signal(mrcp_sig_command_e command_id, mrcp_session_t *session, mrcp_channel_t *channel);
+static apt_bool_t mrcp_app_control_task_msg_signal(mrcp_session_t *session, mrcp_channel_t *channel, mrcp_message_t *message);
+
+
+/** Create MRCP client instance */
+MRCP_DECLARE(mrcp_client_t*) mrcp_client_create(apt_dir_layout_t *dir_layout)
+{
+       mrcp_client_t *client;
+       apr_pool_t *pool;
+       apt_task_t *task;
+       apt_task_vtable_t *vtable;
+       apt_task_msg_pool_t *msg_pool;
+       
+       pool = apt_pool_create();
+       if(!pool) {
+               return NULL;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create "CLIENT_TASK_NAME);
+       client = apr_palloc(pool,sizeof(mrcp_client_t));
+       client->pool = pool;
+       client->dir_layout = dir_layout;
+       client->resource_factory = NULL;
+       client->media_engine_table = NULL;
+       client->rtp_factory_table = NULL;
+       client->sig_agent_table = NULL;
+       client->cnt_agent_table = NULL;
+       client->profile_table = NULL;
+       client->app_table = NULL;
+       client->session_table = NULL;
+       client->cnt_msg_pool = NULL;
+
+       msg_pool = apt_task_msg_pool_create_dynamic(0,pool);
+       client->task = apt_consumer_task_create(client,msg_pool,pool);
+       if(!client->task) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Client Task");
+               return NULL;
+       }
+       task = apt_consumer_task_base_get(client->task);
+       apt_task_name_set(task,CLIENT_TASK_NAME);
+       vtable = apt_task_vtable_get(task);
+       if(vtable) {
+               vtable->process_msg = mrcp_client_msg_process;
+               vtable->on_start_complete = mrcp_client_on_start_complete;
+               vtable->on_terminate_complete = mrcp_client_on_terminate_complete;
+       }
+
+       client->media_engine_table = apr_hash_make(client->pool);
+       client->rtp_factory_table = apr_hash_make(client->pool);
+       client->sig_agent_table = apr_hash_make(client->pool);
+       client->cnt_agent_table = apr_hash_make(client->pool);
+       client->profile_table = apr_hash_make(client->pool);
+       client->app_table = apr_hash_make(client->pool);
+       
+       client->session_table = apr_hash_make(client->pool);
+       return client;
+}
+
+/** Start message processing loop */
+MRCP_DECLARE(apt_bool_t) mrcp_client_start(mrcp_client_t *client)
+{
+       apt_task_t *task;
+       if(!client || !client->task) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Invalid Client");
+               return FALSE;
+       }
+       task = apt_consumer_task_base_get(client->task);
+       if(apt_task_start(task) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Start Client Task");
+               return FALSE;
+       }
+       return TRUE;
+}
+
+/** Shutdown message processing loop */
+MRCP_DECLARE(apt_bool_t) mrcp_client_shutdown(mrcp_client_t *client)
+{
+       apt_task_t *task;
+       if(!client || !client->task) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Invalid Client");
+               return FALSE;
+       }
+       task = apt_consumer_task_base_get(client->task);
+       if(apt_task_terminate(task,TRUE) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Shutdown Client Task");
+               return FALSE;
+       }
+       client->session_table = NULL;
+       return TRUE;
+}
+
+/** Destroy MRCP client */
+MRCP_DECLARE(apt_bool_t) mrcp_client_destroy(mrcp_client_t *client)
+{
+       apt_task_t *task;
+       if(!client || !client->task) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Invalid Client");
+               return FALSE;
+       }
+       task = apt_consumer_task_base_get(client->task);
+       apt_task_destroy(task);
+
+       apr_pool_destroy(client->pool);
+       return TRUE;
+}
+
+
+/** Register MRCP resource factory */
+MRCP_DECLARE(apt_bool_t) mrcp_client_resource_factory_register(mrcp_client_t *client, mrcp_resource_factory_t *resource_factory)
+{
+       if(!resource_factory) {
+               return FALSE;
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Resource Factory");
+       client->resource_factory = resource_factory;
+       return TRUE;
+}
+
+/** Register codec manager */
+MRCP_DECLARE(apt_bool_t) mrcp_client_codec_manager_register(mrcp_client_t *client, mpf_codec_manager_t *codec_manager)
+{
+       if(!codec_manager) {
+               return FALSE;
+       }
+       client->codec_manager = codec_manager;
+       return TRUE;
+}
+
+/** Get registered codec manager */
+MRCP_DECLARE(const mpf_codec_manager_t*) mrcp_client_codec_manager_get(mrcp_client_t *client)
+{
+       return client->codec_manager;
+}
+
+/** Register media engine */
+MRCP_DECLARE(apt_bool_t) mrcp_client_media_engine_register(mrcp_client_t *client, mpf_engine_t *media_engine, const char *name)
+{
+       if(!media_engine || !name) {
+               return FALSE;
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Media Engine [%s]",name);
+       mpf_engine_codec_manager_register(media_engine,client->codec_manager);
+       apr_hash_set(client->media_engine_table,name,APR_HASH_KEY_STRING,media_engine);
+       mpf_engine_task_msg_type_set(media_engine,MRCP_CLIENT_MEDIA_TASK_MSG);
+       if(client->task) {
+               apt_task_t *media_task = mpf_task_get(media_engine);
+               apt_task_t *task = apt_consumer_task_base_get(client->task);
+               apt_task_add(task,media_task);
+       }
+       return TRUE;
+}
+
+/** Get media engine by name */
+MRCP_DECLARE(mpf_engine_t*) mrcp_client_media_engine_get(mrcp_client_t *client, const char *name)
+{
+       return apr_hash_get(client->media_engine_table,name,APR_HASH_KEY_STRING);
+}
+
+/** Register RTP termination factory */
+MRCP_DECLARE(apt_bool_t) mrcp_client_rtp_factory_register(mrcp_client_t *client, mpf_termination_factory_t *rtp_termination_factory, const char *name)
+{
+       if(!rtp_termination_factory || !name) {
+               return FALSE;
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register RTP Termination Factory [%s]",name);
+       apr_hash_set(client->rtp_factory_table,name,APR_HASH_KEY_STRING,rtp_termination_factory);
+       return TRUE;
+}
+
+/** Get RTP termination factory by name */
+MRCP_DECLARE(mpf_termination_factory_t*) mrcp_client_rtp_factory_get(mrcp_client_t *client, const char *name)
+{
+       return apr_hash_get(client->rtp_factory_table,name,APR_HASH_KEY_STRING);
+}
+
+/** Register MRCP signaling agent */
+MRCP_DECLARE(apt_bool_t) mrcp_client_signaling_agent_register(mrcp_client_t *client, mrcp_sig_agent_t *signaling_agent, const char *name)
+{
+       if(!signaling_agent || !name) {
+               return FALSE;
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Signaling Agent [%s]",name);
+       signaling_agent->msg_pool = apt_task_msg_pool_create_dynamic(sizeof(sig_agent_task_msg_data_t),client->pool);
+       signaling_agent->parent = client;
+       signaling_agent->resource_factory = client->resource_factory;
+       apr_hash_set(client->sig_agent_table,name,APR_HASH_KEY_STRING,signaling_agent);
+       if(client->task) {
+               apt_task_t *task = apt_consumer_task_base_get(client->task);
+               apt_task_add(task,signaling_agent->task);
+       }
+       return TRUE;
+}
+
+/** Get signaling agent by name */
+MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_client_signaling_agent_get(mrcp_client_t *client, const char *name)
+{
+       return apr_hash_get(client->sig_agent_table,name,APR_HASH_KEY_STRING);
+}
+
+/** Register MRCP connection agent (MRCPv2 only) */
+MRCP_DECLARE(apt_bool_t) mrcp_client_connection_agent_register(mrcp_client_t *client, mrcp_connection_agent_t *connection_agent, const char *name)
+{
+       if(!connection_agent || !name) {
+               return FALSE;
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Connection Agent [%s]",name);
+       mrcp_client_connection_resource_factory_set(connection_agent,client->resource_factory);
+       mrcp_client_connection_agent_handler_set(connection_agent,client,&connection_method_vtable);
+       client->cnt_msg_pool = apt_task_msg_pool_create_dynamic(sizeof(connection_agent_task_msg_data_t),client->pool);
+       apr_hash_set(client->cnt_agent_table,name,APR_HASH_KEY_STRING,connection_agent);
+       if(client->task) {
+               apt_task_t *task = apt_consumer_task_base_get(client->task);
+               apt_task_t *connection_task = mrcp_client_connection_agent_task_get(connection_agent);
+               apt_task_add(task,connection_task);
+       }
+       return TRUE;
+}
+
+/** Get connection agent by name */
+MRCP_DECLARE(mrcp_connection_agent_t*) mrcp_client_connection_agent_get(mrcp_client_t *client, const char *name)
+{
+       return apr_hash_get(client->cnt_agent_table,name,APR_HASH_KEY_STRING);
+}
+
+/** Create MRCP profile */
+MRCP_DECLARE(mrcp_profile_t*) mrcp_client_profile_create(
+                                                                       mrcp_resource_factory_t *resource_factory,
+                                                                       mrcp_sig_agent_t *signaling_agent,
+                                                                       mrcp_connection_agent_t *connection_agent,
+                                                                       mpf_engine_t *media_engine,
+                                                                       mpf_termination_factory_t *rtp_factory,
+                                                                       apr_pool_t *pool)
+{
+       mrcp_profile_t *profile = apr_palloc(pool,sizeof(mrcp_profile_t));
+       profile->resource_factory = resource_factory;
+       profile->media_engine = media_engine;
+       profile->rtp_termination_factory = rtp_factory;
+       profile->signaling_agent = signaling_agent;
+       profile->connection_agent = connection_agent;
+       return profile;
+}
+
+/** Register MRCP profile */
+MRCP_DECLARE(apt_bool_t) mrcp_client_profile_register(mrcp_client_t *client, mrcp_profile_t *profile, const char *name)
+{
+       if(!profile || !name) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Register Profile: no name",name);
+               return FALSE;
+       }
+       if(!profile->resource_factory) {
+               profile->resource_factory = client->resource_factory;
+       }
+       if(!profile->signaling_agent) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Register Profile [%s]: missing signaling agent",name);
+               return FALSE;
+       }
+       if(profile->signaling_agent->mrcp_version == MRCP_VERSION_2 &&
+               !profile->connection_agent) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Register Profile [%s]: missing connection agent",name);
+               return FALSE;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Profile [%s]",name);
+       apr_hash_set(client->profile_table,name,APR_HASH_KEY_STRING,profile);
+       return TRUE;
+}
+
+/** Get profile by name */
+MRCP_DECLARE(mrcp_profile_t*) mrcp_client_profile_get(mrcp_client_t *client, const char *name)
+{
+       return apr_hash_get(client->profile_table,name,APR_HASH_KEY_STRING);
+}
+
+/** Register MRCP application */
+MRCP_DECLARE(apt_bool_t) mrcp_client_application_register(mrcp_client_t *client, mrcp_application_t *application, const char *name)
+{
+       if(!application || !name) {
+               return FALSE;
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Application [%s]",name);
+       application->client = client;
+       application->msg_pool = apt_task_msg_pool_create_dynamic(sizeof(mrcp_app_message_t*),client->pool);
+       apr_hash_set(client->app_table,name,APR_HASH_KEY_STRING,application);
+       return TRUE;
+}
+
+/** Get memory pool */
+MRCP_DECLARE(apr_pool_t*) mrcp_client_memory_pool_get(mrcp_client_t *client)
+{
+       return client->pool;
+}
+
+
+/** Create application instance */
+MRCP_DECLARE(mrcp_application_t*) mrcp_application_create(const mrcp_app_message_handler_f handler, void *obj, apr_pool_t *pool)
+{
+       mrcp_application_t *application;
+       if(!handler) {
+               return FALSE;
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create Application");
+       application = apr_palloc(pool,sizeof(mrcp_application_t));
+       application->obj = obj;
+       application->handler = handler;
+       application->client = NULL;
+       return application;
+}
+
+/** Destroy application instance */
+MRCP_DECLARE(apt_bool_t) mrcp_application_destroy(mrcp_application_t *application)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy Application");
+       return TRUE;
+}
+
+/** Get external object associated with the application */
+MRCP_DECLARE(void*) mrcp_application_object_get(mrcp_application_t *application)
+{
+       return application->obj;
+}
+
+/** Get dir layout structure */
+MRCP_DECLARE(const apt_dir_layout_t*) mrcp_application_dir_layout_get(mrcp_application_t *application)
+{
+       return application->client->dir_layout;
+}
+
+
+
+/** Create client session */
+MRCP_DECLARE(mrcp_session_t*) mrcp_application_session_create(mrcp_application_t *application, const char *profile_name, void *obj)
+{
+       mrcp_profile_t *profile;
+       mrcp_client_session_t *session;
+       if(!application || !application->client) {
+               return NULL;
+       }
+
+       profile = mrcp_client_profile_get(application->client,profile_name);
+       if(!profile) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Such Profile [%s]",profile_name);
+               return NULL;
+       }
+
+       session = mrcp_client_session_create(application,obj);
+       if(!session) {
+               return NULL;
+       }
+       
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create MRCP Handle "APT_PTR_FMT" [%s]",
+               MRCP_SESSION_PTR(session),
+               profile_name);
+       session->profile = profile;
+       session->codec_manager = application->client->codec_manager;
+       session->base.response_vtable = &session_response_vtable;
+       session->base.event_vtable = &session_event_vtable;
+       return &session->base;
+}
+
+/** Get external object associated with the session */
+MRCP_DECLARE(void*) mrcp_application_session_object_get(mrcp_session_t *session)
+{
+       mrcp_client_session_t *client_session = (mrcp_client_session_t*)session;
+       if(!client_session) {
+               return NULL;
+       }
+       return client_session->app_obj;
+}
+
+
+/** Send session update request */
+MRCP_DECLARE(apt_bool_t) mrcp_application_session_update(mrcp_session_t *session)
+{
+       if(!session) {
+               return FALSE;
+       }
+       return mrcp_app_signaling_task_msg_signal(MRCP_SIG_COMMAND_SESSION_UPDATE,session,NULL);
+}
+
+/** Send session termination request */
+MRCP_DECLARE(apt_bool_t) mrcp_application_session_terminate(mrcp_session_t *session)
+{
+       if(!session) {
+               return FALSE;
+       }
+       return mrcp_app_signaling_task_msg_signal(MRCP_SIG_COMMAND_SESSION_TERMINATE,session,NULL);
+}
+
+/** Destroy client session (session must be terminated prior to destroy) */
+MRCP_DECLARE(apt_bool_t) mrcp_application_session_destroy(mrcp_session_t *session)
+{
+       if(!session) {
+               return FALSE;
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy MRCP Handle "APT_PTR_FMT,MRCP_SESSION_PTR(session));
+       mrcp_session_destroy(session);
+       return TRUE;
+}
+
+
+/** Create control channel */
+MRCP_DECLARE(mrcp_channel_t*) mrcp_application_channel_create(
+                                                                       mrcp_session_t *session, 
+                                                                       mrcp_resource_id resource_id, 
+                                                                       mpf_termination_t *termination, 
+                                                                       mpf_rtp_termination_descriptor_t *rtp_descriptor, 
+                                                                       void *obj)
+{
+       mrcp_client_session_t *client_session = (mrcp_client_session_t*)session;
+       if(!client_session || !client_session->profile) {
+               /* Invalid params */
+               return FALSE;
+       }
+       if(termination) {
+               /* Media engine and RTP factory must be specified in this case */
+               if(!client_session->profile->media_engine || !client_session->profile->rtp_termination_factory) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Channel: invalid profile");
+                       return FALSE;
+               }
+       }
+       else {
+               /* Either termination or rtp_descriptor must be specified */
+               if(!rtp_descriptor) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Channel: missing both termination and RTP descriptor");
+                       return FALSE;
+               }
+       }
+       return mrcp_client_channel_create(session,resource_id,termination,rtp_descriptor,obj);
+}
+
+/** Get external object associated with the channel */
+MRCP_DECLARE(void*) mrcp_application_channel_object_get(mrcp_channel_t *channel)
+{
+       if(!channel) {
+               return FALSE;
+       }
+       return channel->obj;
+}
+
+/** Get RTP termination descriptor */
+MRCP_DECLARE(mpf_rtp_termination_descriptor_t*) mrcp_application_rtp_descriptor_get(mrcp_channel_t *channel)
+{
+       if(!channel || !channel->rtp_termination_slot) {
+               return FALSE;
+       }
+       return channel->rtp_termination_slot->descriptor;
+}
+
+/** Send channel add request */
+MRCP_DECLARE(apt_bool_t) mrcp_application_channel_add(mrcp_session_t *session, mrcp_channel_t *channel)
+{
+       if(!session || !channel) {
+               return FALSE;
+       }
+       return mrcp_app_signaling_task_msg_signal(MRCP_SIG_COMMAND_CHANNEL_ADD,session,channel);
+}
+
+/** Send channel removal request */
+MRCP_DECLARE(apt_bool_t) mrcp_application_channel_remove(mrcp_session_t *session, mrcp_channel_t *channel)
+{
+       if(!session || !channel) {
+               return FALSE;
+       }
+       return mrcp_app_signaling_task_msg_signal(MRCP_SIG_COMMAND_CHANNEL_REMOVE,session,channel);
+}
+
+/** Send resource discovery request */
+MRCP_DECLARE(apt_bool_t) mrcp_application_resource_discover(mrcp_session_t *session)
+{
+       if(!session) {
+               return FALSE;
+       }
+       return mrcp_app_signaling_task_msg_signal(MRCP_SIG_COMMAND_RESOURCE_DISCOVER,session,NULL);
+}
+
+/** Create MRCP message */
+MRCP_DECLARE(mrcp_message_t*) mrcp_application_message_create(mrcp_session_t *session, mrcp_channel_t *channel, mrcp_method_id method_id)
+{
+       mrcp_message_t *mrcp_message;
+       mrcp_profile_t *profile;
+       mrcp_client_session_t *client_session = (mrcp_client_session_t*)session;
+       if(!client_session || !channel) {
+               return NULL;
+       }
+       profile = client_session->profile;
+       if(!profile || !profile->resource_factory) {
+               return NULL;
+       }
+       mrcp_message = mrcp_request_create(channel->resource_id,method_id,session->pool);
+       if(mrcp_message) {
+               mrcp_message->start_line.version = profile->signaling_agent->mrcp_version;
+               mrcp_message_resourcify_by_id(profile->resource_factory,mrcp_message);
+       }
+       return mrcp_message;
+}
+
+/** Send MRCP message */
+MRCP_DECLARE(apt_bool_t) mrcp_application_message_send(mrcp_session_t *session, mrcp_channel_t *channel, mrcp_message_t *message)
+{
+       if(!session || !channel || !message) {
+               return FALSE;
+       }
+       return mrcp_app_control_task_msg_signal(session,channel,message);
+}
+
+/** Create source media termination */
+MRCP_DECLARE(mpf_termination_t*) mrcp_application_source_termination_create(
+                                                                               mrcp_session_t *session,
+                                                                               const mpf_audio_stream_vtable_t *stream_vtable,
+                                                                               mpf_codec_descriptor_t *codec_descriptor,
+                                                                               void *obj)
+{
+       mpf_audio_stream_t *audio_stream;
+       /* create audio stream */
+       audio_stream = mpf_audio_stream_create(
+                       obj,                  /* object to associate */
+                       stream_vtable,        /* virtual methods table of audio stream */
+                       STREAM_MODE_RECEIVE,  /* stream mode/direction */
+                       session->pool);       /* memory pool to allocate memory from */
+
+       if(codec_descriptor) {
+               mrcp_client_session_t *client_session = (mrcp_client_session_t*)session;
+               audio_stream->rx_codec = mpf_codec_manager_codec_get(client_session->codec_manager,codec_descriptor,session->pool);
+       }
+
+       /* create raw termination */
+       return mpf_raw_termination_create(
+                       NULL,                 /* no object to associate */
+                       audio_stream,         /* audio stream */
+                       NULL,                 /* no video stream */
+                       session->pool);       /* memory pool to allocate memory from */
+}
+
+MRCP_DECLARE(mpf_termination_t*) mrcp_application_sink_termination_create(
+                                                                               mrcp_session_t *session,
+                                                                               const mpf_audio_stream_vtable_t *stream_vtable,
+                                                                               mpf_codec_descriptor_t *codec_descriptor,
+                                                                               void *obj)
+{
+       mpf_audio_stream_t *audio_stream;
+       /* create audio stream */
+       audio_stream = mpf_audio_stream_create(
+                       obj,                  /* object to associate */
+                       stream_vtable,        /* virtual methods table of audio stream */
+                       STREAM_MODE_SEND,     /* stream mode/direction */
+                       session->pool);       /* memory pool to allocate memory from */
+
+       if(codec_descriptor) {
+               mrcp_client_session_t *client_session = (mrcp_client_session_t*)session;
+               audio_stream->tx_codec = mpf_codec_manager_codec_get(client_session->codec_manager,codec_descriptor,session->pool);
+       }
+
+       /* create raw termination */
+       return mpf_raw_termination_create(
+                       NULL,                 /* no object to associate */
+                       audio_stream,         /* audio stream */
+                       NULL,                 /* no video stream */
+                       session->pool);       /* memory pool to allocate memory from */
+}
+
+void mrcp_client_session_add(mrcp_client_t *client, mrcp_client_session_t *session)
+{
+       if(session) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Add MRCP Handle "APT_PTR_FMT,MRCP_SESSION_PTR(session));
+               apr_hash_set(client->session_table,session,sizeof(session),session);
+       }
+}
+
+void mrcp_client_session_remove(mrcp_client_t *client, mrcp_client_session_t *session)
+{
+       if(session) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remove MRCP Handle "APT_PTR_FMT,MRCP_SESSION_PTR(session));
+               apr_hash_set(client->session_table,session,sizeof(session),NULL);
+       }
+}
+
+static void mrcp_client_on_start_complete(apt_task_t *task)
+{
+       apt_consumer_task_t *consumer_task = apt_task_object_get(task);
+       mrcp_client_t *client = apt_consumer_task_object_get(consumer_task);
+       void *val;
+       mrcp_application_t *application;
+       mrcp_app_message_t *app_message;
+       apr_hash_index_t *it;
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,CLIENT_TASK_NAME" Started");
+       it = apr_hash_first(client->pool,client->app_table);
+       for(; it; it = apr_hash_next(it)) {
+               apr_hash_this(it,NULL,NULL,&val);
+               application = val;
+               if(!application) continue;
+
+               /* raise one-time application-ready event */
+               app_message = mrcp_client_app_signaling_event_create(MRCP_SIG_EVENT_READY,client->pool);
+               app_message->sig_message.status = MRCP_SIG_STATUS_CODE_SUCCESS;
+               app_message->application = application;
+               application->handler(app_message);
+       }
+}
+
+static void mrcp_client_on_terminate_complete(apt_task_t *task)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,CLIENT_TASK_NAME" Terminated");
+}
+
+
+static apt_bool_t mrcp_client_msg_process(apt_task_t *task, apt_task_msg_t *msg)
+{
+       apt_consumer_task_t *consumer_task = apt_task_object_get(task);
+       mrcp_client_t *client = apt_consumer_task_object_get(consumer_task);
+       if(!client) {
+               return FALSE;
+       }
+       switch(msg->type) {
+               case MRCP_CLIENT_SIGNALING_TASK_MSG:
+               {
+                       const sig_agent_task_msg_data_t *sig_message = (const sig_agent_task_msg_data_t*)msg->data;
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Receive Signaling Task Message [%d]", msg->sub_type);
+                       switch(msg->sub_type) {
+                               case SIG_AGENT_TASK_MSG_ANSWER:
+                                       mrcp_client_session_answer_process(sig_message->session,sig_message->descriptor);
+                                       break;
+                               case SIG_AGENT_TASK_MSG_TERMINATE_RESPONSE:
+                                       mrcp_client_session_terminate_response_process(sig_message->session);
+                                       break;
+                               case SIG_AGENT_TASK_MSG_CONTROL_RESPONSE:
+                                       mrcp_client_session_control_response_process(sig_message->session,sig_message->message);
+                                       break;
+                               case SIG_AGENT_TASK_MSG_DISCOVER_RESPONSE:
+                                       mrcp_client_session_discover_response_process(sig_message->session,sig_message->descriptor);
+                                       break;
+                               case SIG_AGENT_TASK_MSG_TERMINATE_EVENT:
+                                       mrcp_client_session_terminate_event_process(sig_message->session);
+                                       break;
+                               default:
+                                       break;
+                       }
+                       break;
+               }
+               case MRCP_CLIENT_CONNECTION_TASK_MSG:
+               {
+                       const connection_agent_task_msg_data_t *data = (const connection_agent_task_msg_data_t*)msg->data;
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Receive Connection Task Message [%d]", msg->sub_type);
+                       switch(msg->sub_type) {
+                               case CONNECTION_AGENT_TASK_MSG_ADD_CHANNEL:
+                                       mrcp_client_on_channel_add(data->channel,data->descriptor,data->status);
+                                       break;
+                               case CONNECTION_AGENT_TASK_MSG_MODIFY_CHANNEL:
+                                       mrcp_client_on_channel_modify(data->channel,data->descriptor,data->status);
+                                       break;
+                               case CONNECTION_AGENT_TASK_MSG_REMOVE_CHANNEL:
+                                       mrcp_client_on_channel_remove(data->channel,data->status);
+                                       break;
+                               case CONNECTION_AGENT_TASK_MSG_RECEIVE_MESSAGE:
+                                       mrcp_client_on_message_receive(data->channel,data->message);
+                                       break;
+                               default:
+                                       break;
+                       }
+                       break;
+               }
+               case MRCP_CLIENT_MEDIA_TASK_MSG:
+               {
+                       mpf_message_t *mpf_message = (mpf_message_t*) msg->data;
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Receive Media Task Message [%d]", mpf_message->command_id);
+                       mrcp_client_mpf_message_process(mpf_message);
+                       break;
+               }
+               case MRCP_CLIENT_APPLICATION_TASK_MSG:
+               {
+                       mrcp_app_message_t **app_message = (mrcp_app_message_t**) msg->data;
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Receive Application Task Message [%d]", (*app_message)->message_type);
+                       mrcp_client_app_message_process(*app_message);
+                       break;
+               }
+               default:
+               {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Receive Unknown Task Message [%d]", msg->type);
+                       break;
+               }
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_app_signaling_task_msg_signal(mrcp_sig_command_e command_id, mrcp_session_t *session, mrcp_channel_t *channel)
+{
+       mrcp_client_session_t *client_session = (mrcp_client_session_t*)session;
+       mrcp_application_t *application = client_session->application;
+       apt_task_t *task = apt_consumer_task_base_get(application->client->task);
+       apt_task_msg_t *task_msg = apt_task_msg_acquire(application->msg_pool);
+       if(task_msg) {
+               mrcp_app_message_t **slot = ((mrcp_app_message_t**)task_msg->data);
+               mrcp_app_message_t *app_message;
+               task_msg->type = MRCP_CLIENT_APPLICATION_TASK_MSG;
+
+               app_message = mrcp_client_app_signaling_request_create(command_id,session->pool);
+               app_message->application = client_session->application;
+               app_message->session = session;
+               app_message->channel = channel;
+               app_message->control_message = NULL;
+               app_message->descriptor = NULL;
+               *slot = app_message;
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Signal Application Task Message");
+       return apt_task_msg_signal(task,task_msg);
+}
+
+static apt_bool_t mrcp_app_control_task_msg_signal(mrcp_session_t *session, mrcp_channel_t *channel, mrcp_message_t *message)
+{
+       mrcp_client_session_t *client_session = (mrcp_client_session_t*)session;
+       mrcp_application_t *application = client_session->application;
+       apt_task_t *task = apt_consumer_task_base_get(application->client->task);
+       apt_task_msg_t *task_msg = apt_task_msg_acquire(application->msg_pool);
+       if(task_msg) {
+               mrcp_app_message_t **slot = ((mrcp_app_message_t**)task_msg->data);
+               mrcp_app_message_t *app_message;
+               task_msg->type = MRCP_CLIENT_APPLICATION_TASK_MSG;
+
+               app_message = mrcp_client_app_control_message_create(session->pool);
+               app_message->application = client_session->application;
+               app_message->session = session;
+               app_message->channel = channel;
+               app_message->control_message = message;
+               *slot = app_message;
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Signal Application Task Message");
+       return apt_task_msg_signal(task,task_msg);
+}
+
+static apt_bool_t mrcp_client_signaling_task_msg_signal(sig_agent_task_msg_type_e type, mrcp_session_t *session, mrcp_session_descriptor_t *descriptor, mrcp_message_t *message)
+{
+       sig_agent_task_msg_data_t *data;
+       apt_task_msg_t *task_msg = apt_task_msg_acquire(session->signaling_agent->msg_pool);
+       task_msg->type = MRCP_CLIENT_SIGNALING_TASK_MSG;
+       task_msg->sub_type = type;
+       data = (sig_agent_task_msg_data_t*) task_msg->data;
+       data->session = (mrcp_client_session_t*)session;
+       data->descriptor = descriptor;
+       data->message = message;
+
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Signal Signaling Task Message");
+       return apt_task_msg_parent_signal(session->signaling_agent->task,task_msg);
+}
+
+static apt_bool_t mrcp_client_connection_task_msg_signal(
+                                                       connection_agent_task_msg_type_e type,
+                                                       mrcp_connection_agent_t         *agent, 
+                                                       mrcp_control_channel_t          *channel,
+                                                       mrcp_control_descriptor_t       *descriptor,
+                                                       mrcp_message_t                  *message,
+                                                       apt_bool_t                       status)
+{
+       apt_task_t *task;
+       apt_task_msg_t *task_msg;
+       connection_agent_task_msg_data_t *data;
+       mrcp_client_t *client = mrcp_client_connection_agent_object_get(agent);
+       if(!client || !client->cnt_msg_pool) {
+               return FALSE;
+       }
+       task = apt_consumer_task_base_get(client->task);
+       task_msg = apt_task_msg_acquire(client->cnt_msg_pool);
+       task_msg->type = MRCP_CLIENT_CONNECTION_TASK_MSG;
+       task_msg->sub_type = type;
+       data = (connection_agent_task_msg_data_t*) task_msg->data;
+       data->channel = channel ? channel->obj : NULL;
+       data->descriptor = descriptor;
+       data->message = message;
+       data->status = status;
+
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Signal Connection Task Message");
+       return apt_task_msg_signal(task,task_msg);
+}
+
+
+
+static apt_bool_t mrcp_client_answer_signal(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor)
+{
+       return mrcp_client_signaling_task_msg_signal(SIG_AGENT_TASK_MSG_ANSWER,session,descriptor,NULL);
+}
+
+static apt_bool_t mrcp_client_terminate_response_signal(mrcp_session_t *session)
+{
+       return mrcp_client_signaling_task_msg_signal(SIG_AGENT_TASK_MSG_TERMINATE_RESPONSE,session,NULL,NULL);
+}
+
+static apt_bool_t mrcp_client_control_response_signal(mrcp_session_t *session, mrcp_message_t *message)
+{
+       return mrcp_client_signaling_task_msg_signal(SIG_AGENT_TASK_MSG_CONTROL_RESPONSE,session,NULL,message);
+}
+
+static apt_bool_t mrcp_client_discover_response_signal(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor)
+{
+       return mrcp_client_signaling_task_msg_signal(SIG_AGENT_TASK_MSG_DISCOVER_RESPONSE,session,descriptor,NULL);
+}
+
+static apt_bool_t mrcp_client_terminate_event_signal(mrcp_session_t *session)
+{
+       return mrcp_client_signaling_task_msg_signal(SIG_AGENT_TASK_MSG_TERMINATE_EVENT,session,NULL,NULL);
+}
+
+
+static apt_bool_t mrcp_client_channel_add_signal(mrcp_control_channel_t *channel, mrcp_control_descriptor_t *descriptor, apt_bool_t status)
+{
+       return mrcp_client_connection_task_msg_signal(
+                                                               CONNECTION_AGENT_TASK_MSG_ADD_CHANNEL,
+                                                               channel->agent,
+                                                               channel,
+                                                               descriptor,
+                                                               NULL,
+                                                               status);
+}
+
+static apt_bool_t mrcp_client_channel_modify_signal(mrcp_control_channel_t *channel, mrcp_control_descriptor_t *descriptor, apt_bool_t status)
+{
+       return mrcp_client_connection_task_msg_signal(
+                                                               CONNECTION_AGENT_TASK_MSG_MODIFY_CHANNEL,
+                                                               channel->agent,
+                                                               channel,
+                                                               descriptor,
+                                                               NULL,
+                                                               status);
+}
+
+static apt_bool_t mrcp_client_channel_remove_signal(mrcp_control_channel_t *channel, apt_bool_t status)
+{
+       return mrcp_client_connection_task_msg_signal(
+                                                               CONNECTION_AGENT_TASK_MSG_REMOVE_CHANNEL,
+                                                               channel->agent,
+                                                               channel,
+                                                               NULL,
+                                                               NULL,
+                                                               status);
+}
+
+static apt_bool_t mrcp_client_message_signal(mrcp_control_channel_t *channel, mrcp_message_t *mrcp_message)
+{
+       return mrcp_client_connection_task_msg_signal(
+                                                               CONNECTION_AGENT_TASK_MSG_RECEIVE_MESSAGE,
+                                                               channel->agent,
+                                                               channel,
+                                                               NULL,
+                                                               mrcp_message,
+                                                               TRUE);
+}
diff --git a/libs/unimrcp/libs/mrcp-client/src/mrcp_client_session.c b/libs/unimrcp/libs/mrcp-client/src/mrcp_client_session.c
new file mode 100644 (file)
index 0000000..0832fc8
--- /dev/null
@@ -0,0 +1,1220 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mrcp_client_session.h"
+#include "mrcp_resource.h"
+#include "mrcp_resource_factory.h"
+#include "mrcp_sig_agent.h"
+#include "mrcp_client_connection.h"
+#include "mrcp_session.h"
+#include "mrcp_session_descriptor.h"
+#include "mrcp_control_descriptor.h"
+#include "mrcp_message.h"
+#include "mpf_termination.h"
+#include "mpf_stream.h"
+#include "mpf_engine.h"
+#include "mpf_user.h"
+#include "apt_consumer_task.h"
+#include "apt_obj_list.h"
+#include "apt_log.h"
+
+
+void mrcp_client_session_add(mrcp_client_t *client, mrcp_client_session_t *session);
+void mrcp_client_session_remove(mrcp_client_t *client, mrcp_client_session_t *session);
+
+static apt_bool_t mrcp_client_session_offer_send(mrcp_client_session_t *session);
+
+static apt_bool_t mrcp_app_session_terminate_raise(mrcp_client_session_t *session, mrcp_sig_status_code_e status);
+static apt_bool_t mrcp_app_sig_response_raise(mrcp_client_session_t *session, mrcp_sig_status_code_e status, apt_bool_t process_pending_requests);
+static apt_bool_t mrcp_app_sig_event_raise(mrcp_client_session_t *session, mrcp_channel_t *channel);
+static apt_bool_t mrcp_app_control_message_raise(mrcp_client_session_t *session, mrcp_channel_t *channel, mrcp_message_t *mrcp_message);
+static apt_bool_t mrcp_app_request_dispatch(mrcp_client_session_t *session, const mrcp_app_message_t *app_message);
+
+static apt_bool_t mrcp_client_resource_answer_process(mrcp_client_session_t *session, mrcp_session_descriptor_t *descriptor);
+static apt_bool_t mrcp_client_control_media_answer_process(mrcp_client_session_t *session, mrcp_session_descriptor_t *descriptor);
+static apt_bool_t mrcp_client_av_media_answer_process(mrcp_client_session_t *session, mrcp_session_descriptor_t *descriptor);
+
+static mrcp_channel_t* mrcp_client_channel_find_by_name(mrcp_client_session_t *session, const apt_str_t *resource_name);
+
+static apt_bool_t mrcp_client_mpf_request_send(
+                                               mpf_engine_t *engine, 
+                                               mpf_command_type_e command_id, 
+                                               mpf_context_t *context, 
+                                               mpf_termination_t *termination, 
+                                               void *descriptor);
+
+mrcp_client_session_t* mrcp_client_session_create(mrcp_application_t *application, void *obj)
+{
+       apr_pool_t *pool;
+       mrcp_client_session_t *session = (mrcp_client_session_t*) mrcp_session_create(sizeof(mrcp_client_session_t)-sizeof(mrcp_session_t));
+       pool = session->base.pool;
+       session->application = application;
+       session->codec_manager = NULL;
+       session->app_obj = obj;
+       session->profile = NULL;
+       session->context = NULL;
+       session->terminations = apr_array_make(pool,2,sizeof(rtp_termination_slot_t));
+       session->channels = apr_array_make(pool,2,sizeof(mrcp_channel_t*));
+       session->registered = FALSE;
+       session->offer = NULL;
+       session->answer = NULL;
+       session->active_request = NULL;
+       session->request_queue = apt_list_create(pool);
+       session->offer_flag_count = 0;
+       session->answer_flag_count = 0;
+       session->terminate_flag_count = 0;
+       return session;
+}
+
+mrcp_channel_t* mrcp_client_channel_create(
+                                       mrcp_session_t *session, 
+                                       mrcp_resource_id resource_id, 
+                                       mpf_termination_t *termination, 
+                                       mpf_rtp_termination_descriptor_t *rtp_descriptor, 
+                                       void *obj)
+{
+       mrcp_channel_t *channel = apr_palloc(session->pool,sizeof(mrcp_channel_t));
+       channel->pool = session->pool;
+       channel->obj = obj;
+       channel->session = session;
+       channel->resource_id = resource_id;
+       channel->resource_name = NULL;
+       channel->control_channel = NULL;
+       channel->termination = termination;
+       channel->rtp_termination_slot = NULL;
+       channel->resource = NULL;
+       channel->waiting_for_channel = FALSE;
+       channel->waiting_for_termination = FALSE;
+
+       if(rtp_descriptor) {
+               channel->rtp_termination_slot = apr_palloc(session->pool,sizeof(rtp_termination_slot_t));
+               channel->rtp_termination_slot->descriptor = rtp_descriptor;
+               channel->rtp_termination_slot->termination = NULL;
+               channel->rtp_termination_slot->waiting = FALSE;
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create Channel "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(session));
+       return channel;
+}
+
+apt_bool_t mrcp_client_session_answer_process(mrcp_client_session_t *session, mrcp_session_descriptor_t *descriptor)
+{
+       mrcp_sig_status_code_e status_code = MRCP_SIG_STATUS_CODE_SUCCESS;
+       if(!session->offer) {
+               return FALSE;
+       }
+       if(!descriptor) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive Answer "APT_PTRSID_FMT" [null descriptor]", MRCP_SESSION_PTRSID(&session->base));
+               status_code = MRCP_SIG_STATUS_CODE_FAILURE;
+               /* raise app response */
+               return mrcp_app_sig_response_raise(session,status_code,TRUE);
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive Answer "APT_PTRSID_FMT" [c:%d a:%d v:%d]",
+               MRCP_SESSION_PTRSID(&session->base),
+               descriptor->control_media_arr->nelts,
+               descriptor->audio_media_arr->nelts,
+               descriptor->video_media_arr->nelts);
+
+       if(session->base.signaling_agent->mrcp_version == MRCP_VERSION_1) {
+               if(mrcp_client_resource_answer_process(session,descriptor) != TRUE) {
+                       status_code = MRCP_SIG_STATUS_CODE_FAILURE;
+               }
+       }
+       else {
+               mrcp_client_control_media_answer_process(session,descriptor);
+               mrcp_client_av_media_answer_process(session,descriptor);
+       }
+
+       /* store received answer */
+       session->answer = descriptor;
+
+       if(!session->answer_flag_count) {
+               /* raise app response */
+               mrcp_app_sig_response_raise(session,status_code,TRUE);
+       }
+
+       return TRUE;
+}
+
+apt_bool_t mrcp_client_session_terminate_response_process(mrcp_client_session_t *session)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive Terminate Response "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+
+       if(session->terminate_flag_count) {
+               session->terminate_flag_count--;
+       }
+
+       if(!session->terminate_flag_count) {
+               mrcp_app_session_terminate_raise(session,MRCP_SIG_STATUS_CODE_SUCCESS);
+       }
+       return TRUE;
+}
+
+apt_bool_t mrcp_client_session_terminate_event_process(mrcp_client_session_t *session)
+{
+       if(session->active_request) {
+               /* raise app response */
+               mrcp_app_sig_response_raise(session,MRCP_SIG_STATUS_CODE_TERMINATE,FALSE);
+
+               /* cancel remaing requests (if any) */
+               do {
+                       session->active_request = apt_list_pop_front(session->request_queue);
+                       if(session->active_request) {
+                               mrcp_app_sig_response_raise(session,MRCP_SIG_STATUS_CODE_CANCEL,FALSE);
+                       }
+               }
+               while(session->active_request);
+       }
+       else {
+               /* raise app event */
+               mrcp_app_sig_event_raise(session,NULL);
+       }
+       return TRUE;
+}
+
+apt_bool_t mrcp_client_session_control_response_process(mrcp_client_session_t *session, mrcp_message_t *message)
+{
+       mrcp_channel_t *channel = mrcp_client_channel_find_by_name(session,&message->channel_id.resource_name);
+       if(!channel) {
+               return FALSE;
+       }
+       return mrcp_app_control_message_raise(session,channel,message);
+}
+
+apt_bool_t mrcp_client_session_discover_response_process(mrcp_client_session_t *session, mrcp_session_descriptor_t *descriptor)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive Resource Discovery Response "APT_PTR_FMT, MRCP_SESSION_PTR(&session->base));
+       if(!session->active_request) {
+               return FALSE;
+       }
+
+       if(!descriptor) {
+               /* raise app response */
+               return mrcp_app_sig_response_raise(session,MRCP_SIG_STATUS_CODE_FAILURE,TRUE);
+       }
+
+       if(session->base.signaling_agent->mrcp_version == MRCP_VERSION_1) {
+               if(descriptor->resource_state == TRUE) {
+                       mrcp_control_descriptor_t *control_media;
+                       if(!session->answer) {
+                               session->answer = descriptor;
+                       }
+                       control_media = apr_palloc(session->base.pool,sizeof(mrcp_control_descriptor_t));
+                       mrcp_control_descriptor_init(control_media);
+                       control_media->id = mrcp_session_control_media_add(session->answer,control_media);
+                       control_media->resource_name = descriptor->resource_name;
+               }
+       }
+
+       if(session->answer_flag_count) {
+               session->answer_flag_count--;
+       }
+
+       if(!session->answer_flag_count) {
+               mrcp_app_message_t *response;
+               response = mrcp_client_app_response_create(session->active_request,MRCP_SIG_STATUS_CODE_SUCCESS,session->base.pool);
+               response->descriptor = session->answer;
+               session->answer = NULL;
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Raise App Resource Discovery Response "APT_PTR_FMT, MRCP_SESSION_PTR(&session->base));
+               session->application->handler(response);
+
+               session->active_request = apt_list_pop_front(session->request_queue);
+               if(session->active_request) {
+                       mrcp_app_request_dispatch(session,session->active_request);
+               }
+       }
+       return TRUE;
+}
+
+apt_bool_t mrcp_client_on_channel_add(mrcp_channel_t *channel, mrcp_control_descriptor_t *descriptor, apt_bool_t status)
+{
+       mrcp_client_session_t *session = (mrcp_client_session_t*)channel->session;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Control Channel Add "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+       if(!channel->waiting_for_channel) {
+               return FALSE;
+       }
+       channel->waiting_for_channel = FALSE;
+       if(session->offer_flag_count) {
+               session->offer_flag_count--;
+               if(!session->offer_flag_count) {
+                       /* send offer to server */
+                       mrcp_client_session_offer_send(session);
+               }
+       }
+       return TRUE;
+}
+
+apt_bool_t mrcp_client_on_channel_modify(mrcp_channel_t *channel, mrcp_control_descriptor_t *descriptor, apt_bool_t status)
+{
+       mrcp_client_session_t *session = (mrcp_client_session_t*)channel->session;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Control Channel Modify "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+       if(!channel->waiting_for_channel) {
+               return FALSE;
+       }
+       channel->waiting_for_channel = FALSE;
+       if(session->answer_flag_count) {
+               session->answer_flag_count--;
+               if(!session->answer_flag_count) {
+                       /* raise app response */
+                       mrcp_app_sig_response_raise(
+                               session,
+                               status == TRUE ? MRCP_SIG_STATUS_CODE_SUCCESS : MRCP_SIG_STATUS_CODE_FAILURE,
+                               TRUE);
+               }
+       }
+       return TRUE;
+}
+
+apt_bool_t mrcp_client_on_channel_remove(mrcp_channel_t *channel, apt_bool_t status)
+{
+       mrcp_client_session_t *session = (mrcp_client_session_t*)channel->session;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Control Channel Remove "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+       if(!channel->waiting_for_channel) {
+               return FALSE;
+       }
+       channel->waiting_for_channel = FALSE;
+       if(session->terminate_flag_count) {
+               session->terminate_flag_count--;
+               if(!session->terminate_flag_count) {
+                       mrcp_app_session_terminate_raise(
+                               session,
+                               status == TRUE ? MRCP_SIG_STATUS_CODE_SUCCESS : MRCP_SIG_STATUS_CODE_FAILURE);
+               }
+       }
+       return TRUE;
+}
+
+apt_bool_t mrcp_client_on_message_receive(mrcp_channel_t *channel, mrcp_message_t *message)
+{
+       mrcp_client_session_t *session = (mrcp_client_session_t*)channel->session;
+       return mrcp_app_control_message_raise(session,channel,message);
+}
+
+mrcp_app_message_t* mrcp_client_app_signaling_request_create(mrcp_sig_command_e command_id, apr_pool_t *pool)
+{
+       mrcp_app_message_t *app_message = apr_palloc(pool,sizeof(mrcp_app_message_t));
+       app_message->message_type = MRCP_APP_MESSAGE_TYPE_SIGNALING;
+       app_message->sig_message.message_type = MRCP_SIG_MESSAGE_TYPE_REQUEST;
+       app_message->sig_message.command_id = command_id;
+       return app_message;
+}
+
+mrcp_app_message_t* mrcp_client_app_signaling_event_create(mrcp_sig_event_e event_id, apr_pool_t *pool)
+{
+       mrcp_app_message_t *app_message = apr_palloc(pool,sizeof(mrcp_app_message_t));
+       app_message->message_type = MRCP_APP_MESSAGE_TYPE_SIGNALING;
+       app_message->sig_message.message_type = MRCP_SIG_MESSAGE_TYPE_EVENT;
+       app_message->sig_message.event_id = event_id;
+       return app_message;
+}
+
+mrcp_app_message_t* mrcp_client_app_control_message_create(apr_pool_t *pool)
+{
+       mrcp_app_message_t *app_message = apr_palloc(pool,sizeof(mrcp_app_message_t));
+       app_message->message_type = MRCP_APP_MESSAGE_TYPE_CONTROL;
+       return app_message;
+}
+
+mrcp_app_message_t* mrcp_client_app_response_create(const mrcp_app_message_t *app_request, mrcp_sig_status_code_e status, apr_pool_t *pool)
+{
+       mrcp_app_message_t *app_response = apr_palloc(pool,sizeof(mrcp_app_message_t));
+       *app_response = *app_request;
+       app_response->sig_message.message_type = MRCP_SIG_MESSAGE_TYPE_RESPONSE;
+       app_response->sig_message.status = status;
+       return app_response;
+}
+
+apt_bool_t mrcp_client_app_message_process(mrcp_app_message_t *app_message)
+{
+       mrcp_client_session_t *session = (mrcp_client_session_t*)app_message->session;
+       if(app_message->message_type == MRCP_APP_MESSAGE_TYPE_SIGNALING) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive App Request "APT_PTRSID_FMT" [%d]",
+                       MRCP_SESSION_PTRSID(&session->base),
+                       app_message->sig_message.command_id);
+       }
+       else {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive App MRCP Request "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+       }
+
+       if(session->active_request) {
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Push Request to Queue "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+               apt_list_push_back(session->request_queue,app_message,session->base.pool);
+               return TRUE;
+       }
+
+       session->active_request = app_message;
+       mrcp_app_request_dispatch(session,app_message);
+       return TRUE;
+}
+
+static apt_bool_t mrcp_client_session_offer_send(mrcp_client_session_t *session)
+{
+       mrcp_session_descriptor_t *descriptor = session->offer;
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Send Offer "APT_PTRSID_FMT" [c:%d a:%d v:%d]",
+               MRCP_SESSION_PTRSID(&session->base),
+               descriptor->control_media_arr->nelts,
+               descriptor->audio_media_arr->nelts,
+               descriptor->video_media_arr->nelts);
+       return mrcp_session_offer(&session->base,descriptor);
+}
+
+static apt_bool_t mrcp_app_session_terminate_raise(mrcp_client_session_t *session, mrcp_sig_status_code_e status)
+{
+       int i;
+       mrcp_channel_t *channel;
+       for(i=0; i<session->channels->nelts; i++) {
+               channel = ((mrcp_channel_t**)session->channels->elts)[i];
+               if(!channel) continue;
+
+               if(channel->control_channel) {
+                       mrcp_client_control_channel_destroy(channel->control_channel);
+                       channel->control_channel = NULL;
+               }
+       }
+
+       mrcp_client_session_remove(session->application->client,session);
+       /* raise app response */
+       return mrcp_app_sig_response_raise(session,status,FALSE);
+}
+
+static apt_bool_t mrcp_app_sig_response_raise(mrcp_client_session_t *session, mrcp_sig_status_code_e status, apt_bool_t process_pending_requests)
+{
+       mrcp_app_message_t *response;
+       const mrcp_app_message_t *request = session->active_request;
+       if(!request) {
+               return FALSE;
+       }
+       session->active_request = NULL;
+       response = mrcp_client_app_response_create(request,status,session->base.pool);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Raise App Response "APT_PTRSID_FMT" [%d] %s [%d]", 
+               MRCP_SESSION_PTRSID(&session->base),
+               response->sig_message.command_id,
+               status == MRCP_SIG_STATUS_CODE_SUCCESS ? "SUCCESS" : "FAILURE",
+               status);
+       session->application->handler(response);
+
+       if(process_pending_requests) {
+               session->active_request = apt_list_pop_front(session->request_queue);
+               if(session->active_request) {
+                       mrcp_app_request_dispatch(session,session->active_request);
+               }
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_app_sig_event_raise(mrcp_client_session_t *session, mrcp_channel_t *channel)
+{
+       mrcp_app_message_t *app_event;
+       if(!session) {
+               return FALSE;
+       }
+       app_event = mrcp_client_app_signaling_event_create(MRCP_SIG_EVENT_TERMINATE,session->base.pool);
+       app_event->application = session->application;
+       app_event->session = &session->base;
+       app_event->channel = channel;
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Raise App Event "APT_PTRSID_FMT" [%d]", 
+               MRCP_SESSION_PTRSID(&session->base),
+               app_event->sig_message.event_id);
+       return session->application->handler(app_event);
+}
+
+static apt_bool_t mrcp_app_control_message_raise(mrcp_client_session_t *session, mrcp_channel_t *channel, mrcp_message_t *mrcp_message)
+{
+       if(mrcp_message->start_line.message_type == MRCP_MESSAGE_TYPE_RESPONSE) {
+               mrcp_app_message_t *response;
+               mrcp_message_t *mrcp_request;
+               if(!session->active_request || !session->active_request->control_message) {
+                       return FALSE;
+               }
+               response = mrcp_client_app_response_create(session->active_request,0,session->base.pool);
+               mrcp_request = session->active_request->control_message;
+               mrcp_message->start_line.method_id = mrcp_request->start_line.method_id;
+               mrcp_message->start_line.method_name = mrcp_request->start_line.method_name;
+               response->control_message = mrcp_message;
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Raise App MRCP Response "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+               session->application->handler(response);
+
+               session->active_request = apt_list_pop_front(session->request_queue);
+               if(session->active_request) {
+                       mrcp_app_request_dispatch(session,session->active_request);
+               }
+       }
+       else if(mrcp_message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
+               mrcp_app_message_t *app_message;
+               app_message = mrcp_client_app_control_message_create(session->base.pool);
+               app_message->control_message = mrcp_message;
+               app_message->application = session->application;
+               app_message->session = &session->base;
+               app_message->channel = channel;
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Raise App MRCP Event "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+               session->application->handler(app_message);
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_client_channel_find(mrcp_client_session_t *session, mrcp_channel_t *channel, int *index)
+{
+       int i;
+       for(i=0; i<session->channels->nelts; i++) {
+               mrcp_channel_t *existing_channel = ((mrcp_channel_t**)session->channels->elts)[i];
+               if(existing_channel == channel) {
+                       if(index) {
+                               *index = i;
+                       }
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+static rtp_termination_slot_t* mrcp_client_rtp_termination_find(mrcp_client_session_t *session, mpf_termination_t *termination)
+{
+       int i;
+       rtp_termination_slot_t *slot;
+       for(i=0; i<session->terminations->nelts; i++) {
+               slot = &((rtp_termination_slot_t*)session->terminations->elts)[i];
+               if(slot && slot->termination == termination) {
+                       return slot;
+               }
+       }
+       return NULL;
+}
+
+static int mrcp_client_audio_media_find_by_mid(const mrcp_session_descriptor_t *descriptor, apr_size_t mid)
+{
+       int i;
+       mpf_rtp_media_descriptor_t *media;
+       for(i=0; i<descriptor->audio_media_arr->nelts; i++) {
+               media = ((mpf_rtp_media_descriptor_t**)descriptor->audio_media_arr->elts)[i];
+               if(media->mid == mid) {
+                       return i;
+               }
+       }
+       return -1;
+}
+
+static mrcp_channel_t* mrcp_client_channel_termination_find(mrcp_client_session_t *session, mpf_termination_t *termination)
+{
+       int i;
+       mrcp_channel_t *channel;
+       for(i=0; i<session->channels->nelts; i++) {
+               channel = ((mrcp_channel_t**)session->channels->elts)[i];
+               if(!channel) continue;
+
+               if(channel->termination == termination) {
+                       return channel;
+               }
+       }
+       return NULL;
+}
+
+static mrcp_channel_t* mrcp_client_channel_find_by_name(mrcp_client_session_t *session, const apt_str_t *resource_name)
+{
+       int i;
+       mrcp_channel_t *channel;
+       for(i=0; i<session->channels->nelts; i++) {
+               channel = ((mrcp_channel_t**)session->channels->elts)[i];
+               if(!channel) continue;
+
+               if(apt_string_compare(channel->resource_name,resource_name) == TRUE) {
+                       return channel;
+               }
+       }
+       return NULL;
+}
+
+static apt_bool_t mrcp_client_message_send(mrcp_client_session_t *session, mrcp_channel_t *channel, mrcp_message_t *message)
+{
+       if(!session->base.id.length) {
+               mrcp_message_t *response = mrcp_response_create(message,message->pool);
+               response->start_line.status_code = MRCP_STATUS_CODE_METHOD_FAILED;
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Raise App Failure MRCP Response "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+               mrcp_app_control_message_raise(session,channel,response);
+               return TRUE;
+       }
+
+       message->channel_id.session_id = session->base.id;
+       message->start_line.request_id = ++session->base.last_request_id;
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Send MRCP Request "APT_PTRSIDRES_FMT" [%d]",
+                                       MRCP_SESSION_PTRSID(&session->base),
+                                       channel->resource_name->buf,
+                                       message->start_line.request_id);
+
+       if(channel->control_channel) {
+               /* MRCPv2 */
+               mrcp_client_control_message_send(channel->control_channel,message);
+       }
+       else {
+               /* MRCPv1 */
+               mrcp_session_control_request(channel->session,message);
+       }
+
+       return TRUE;
+}
+
+static apt_bool_t mrcp_client_channel_modify(mrcp_client_session_t *session, mrcp_channel_t *channel, apt_bool_t enable)
+{
+       int index;
+       if(!session->offer) {
+               return FALSE;
+       }
+       if(!channel->resource_name) {
+               return FALSE;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Modify Control Channel "APT_PTRSIDRES_FMT" [%d]",
+                                       MRCP_SESSION_PTRSID(&session->base),
+                                       channel->resource_name->buf,
+                                       enable);
+       if(mrcp_client_channel_find(session,channel,&index) == TRUE) {
+               mrcp_control_descriptor_t *control_media = mrcp_session_control_media_get(session->offer,(apr_size_t)index);
+               if(control_media) {
+                       control_media->port = (enable == TRUE) ? 9 : 0;
+                       if(channel->termination && channel->termination->audio_stream) {
+                               int i = mrcp_client_audio_media_find_by_mid(session->offer,control_media->cmid);
+                               if(i >= 0) {
+                                       mpf_stream_mode_e mode = mpf_stream_mode_negotiate(channel->termination->audio_stream->mode);
+                                       mpf_rtp_media_descriptor_t *audio_media = mrcp_session_audio_media_get(session->offer,(apr_size_t)i);
+                                       if(audio_media) {
+                                               if(enable == TRUE) {
+                                                       audio_media->mode |= mode;
+                                               }
+                                               else {
+                                                       audio_media->mode &= ~mode;
+                                               }
+                                               audio_media->base.state = (audio_media->mode != STREAM_MODE_NONE) ? MPF_MEDIA_ENABLED : MPF_MEDIA_DISABLED;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       session->offer->resource_name = *channel->resource_name;
+       session->offer->resource_state = enable;
+       return mrcp_client_session_offer_send(session);
+}
+
+static apt_bool_t mrcp_client_channel_add(mrcp_client_session_t *session, mrcp_channel_t *channel)
+{
+       mrcp_channel_t **channel_slot;
+       mrcp_control_descriptor_t *control_media;
+       mpf_rtp_termination_descriptor_t *rtp_descriptor = NULL;
+       rtp_termination_slot_t *termination_slot;
+       apr_pool_t *pool = session->base.pool;
+       mrcp_profile_t *profile = session->profile;
+       if(mrcp_client_channel_find(session,channel,NULL) == TRUE) {
+               /* update */
+               return mrcp_client_channel_modify(session,channel,TRUE);
+       }
+
+       if(!session->offer) {
+               session->offer = mrcp_session_descriptor_create(pool);
+               session->context = mpf_context_create(session,5,pool);
+       }
+       if(!channel->resource) {
+               channel->resource = mrcp_resource_get(profile->resource_factory,channel->resource_id);
+               if(!channel->resource) {
+                       return FALSE;
+               }
+               channel->resource_name = mrcp_resource_name_get(profile->resource_factory,channel->resource_id);
+               if(!channel->resource_name) {
+                       return FALSE;
+               }
+       }
+       if(session->base.signaling_agent->mrcp_version == MRCP_VERSION_1) {
+               session->offer->resource_name = *channel->resource_name;
+               session->offer->resource_state = TRUE;
+       }
+       else {
+               if(!channel->control_channel) {
+                       channel->control_channel = mrcp_client_control_channel_create(profile->connection_agent,channel,pool);
+               }
+               control_media = mrcp_control_offer_create(pool);
+               control_media->id = mrcp_session_control_media_add(session->offer,control_media);
+               control_media->cmid = session->offer->control_media_arr->nelts;
+               control_media->resource_name = *channel->resource_name;
+               if(mrcp_client_control_channel_add(channel->control_channel,control_media) == TRUE) {
+                       channel->waiting_for_channel = TRUE;
+                       session->offer_flag_count++;
+               }
+       }
+
+       /* add to channel array */
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Add Control Channel "APT_PTRSIDRES_FMT,
+                                       MRCP_SESSION_PTRSID(&session->base),
+                                       channel->resource_name->buf);
+       channel_slot = apr_array_push(session->channels);
+       *channel_slot = channel;
+
+       if(channel->termination) {
+               if(mrcp_client_mpf_request_send(profile->media_engine,MPF_COMMAND_ADD,session->context,channel->termination,NULL) == TRUE) {
+                       channel->waiting_for_termination = TRUE;
+                       session->offer_flag_count++;
+               }
+       }
+
+       if(channel->rtp_termination_slot) {
+               rtp_descriptor = channel->rtp_termination_slot->descriptor;
+       }       
+       /* add to rtp termination array */
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add RTP Termination "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+       termination_slot = apr_array_push(session->terminations);
+       termination_slot->waiting = FALSE;
+       termination_slot->termination = NULL;
+       termination_slot->descriptor = NULL;
+       if(rtp_descriptor) {
+               if(rtp_descriptor->audio.local) {
+                       session->offer->ip = rtp_descriptor->audio.local->base.ip;
+                       session->offer->ext_ip = rtp_descriptor->audio.local->base.ext_ip;
+                       rtp_descriptor->audio.local->base.id = mrcp_session_audio_media_add(session->offer,rtp_descriptor->audio.local);
+                       rtp_descriptor->audio.local->mid = session->offer->audio_media_arr->nelts;
+               }
+       }
+       else {
+               /* create rtp termination */
+               mpf_termination_t *termination = mpf_termination_create(profile->rtp_termination_factory,session,session->base.pool);
+               termination_slot->termination = termination;
+
+               /* initialize rtp descriptor */
+               rtp_descriptor = apr_palloc(pool,sizeof(mpf_rtp_termination_descriptor_t));
+               mpf_rtp_termination_descriptor_init(rtp_descriptor);
+               if(channel->termination && channel->termination->audio_stream) {
+                       mpf_rtp_media_descriptor_t *media;
+                       media = apr_palloc(pool,sizeof(mpf_rtp_media_descriptor_t));
+                       mpf_rtp_media_descriptor_init(media);
+                       media->base.state = MPF_MEDIA_ENABLED;
+                       media->mode = mpf_stream_mode_negotiate(channel->termination->audio_stream->mode);
+                       rtp_descriptor->audio.local = media;
+               }
+               /* send add termination request (add to media context) */
+               if(mrcp_client_mpf_request_send(profile->media_engine,MPF_COMMAND_ADD,session->context,termination,rtp_descriptor) == TRUE) {
+                       termination_slot->waiting = TRUE;
+                       session->offer_flag_count++;
+               }
+       }
+       termination_slot->descriptor = rtp_descriptor;
+       channel->rtp_termination_slot = termination_slot;
+
+       if(!session->offer_flag_count) {
+               /* send offer to server */
+               mrcp_client_session_offer_send(session);
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_client_session_update(mrcp_client_session_t *session)
+{
+       if(!session->offer) {
+               return FALSE;
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Update Session "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+       return mrcp_client_session_offer_send(session);
+}
+
+static apt_bool_t mrcp_client_session_terminate(mrcp_client_session_t *session)
+{
+       mrcp_profile_t *profile;
+       mrcp_channel_t *channel;
+       rtp_termination_slot_t *slot;
+       int i;
+       
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Terminate Session "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+       profile = session->profile;
+       /* remove existing control channels */
+       for(i=0; i<session->channels->nelts; i++) {
+               /* get existing channel */
+               channel = *((mrcp_channel_t**)session->channels->elts + i);
+               if(!channel) continue;
+
+               if(channel->control_channel) {
+                       /* remove channel */
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Remove Control Channel "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+                       if(mrcp_client_control_channel_remove(channel->control_channel) == TRUE) {
+                               channel->waiting_for_channel = TRUE;
+                               session->terminate_flag_count++;
+                       }
+               }
+
+               if(channel->termination) {              
+                       /* send subtract termination request */
+                       if(channel->termination) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Subtract Channel Termination "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+                               if(mrcp_client_mpf_request_send(profile->media_engine,MPF_COMMAND_SUBTRACT,session->context,channel->termination,NULL) == TRUE) {
+                                       channel->waiting_for_termination = TRUE;
+                                       session->terminate_flag_count++;
+                               }
+                       }
+               }
+       }
+
+       /* subtract existing terminations */
+       for(i=0; i<session->terminations->nelts; i++) {
+               /* get existing termination */
+               slot = &((rtp_termination_slot_t*)session->terminations->elts)[i];
+               if(!slot || !slot->termination) continue;
+
+               /* send subtract termination request */
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Subtract Termination "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+               if(mrcp_client_mpf_request_send(profile->media_engine,MPF_COMMAND_SUBTRACT,session->context,slot->termination,NULL) == TRUE) {
+                       slot->waiting = TRUE;
+                       session->terminate_flag_count++;
+               }
+       }
+
+       session->terminate_flag_count++;
+       mrcp_session_terminate_request(&session->base);
+       return TRUE;
+}
+
+static apt_bool_t mrcp_client_resource_discover(mrcp_client_session_t *session)
+{
+       mrcp_session_descriptor_t *descriptor = NULL;
+       
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Send Resource Discovery Request "APT_PTR_FMT, MRCP_SESSION_PTR(&session->base));
+       session->answer = NULL;
+       if(session->base.signaling_agent->mrcp_version == MRCP_VERSION_1) {
+               const apt_str_t *resource_name;
+               mrcp_resource_id i;
+
+               for(i=0; i<MRCP_RESOURCE_TYPE_COUNT; i++) {
+                       resource_name = mrcp_resource_name_get(session->profile->resource_factory,i);
+                       if(!resource_name) continue;
+               
+                       descriptor = mrcp_session_descriptor_create(session->base.pool);
+                       apt_string_copy(&descriptor->resource_name,resource_name,session->base.pool);
+                       if(mrcp_session_discover_request(&session->base,descriptor) == TRUE) {
+                               session->answer_flag_count++;
+                       }
+               }
+       }
+       else {
+               if(mrcp_session_discover_request(&session->base,descriptor) == TRUE) {
+                       session->answer_flag_count++;
+               }
+       }
+
+       if(session->answer_flag_count == 0) {
+               mrcp_app_sig_response_raise(session,MRCP_SIG_STATUS_CODE_FAILURE,TRUE);
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_client_on_termination_add(mrcp_client_session_t *session, mpf_message_t *mpf_message)
+{
+       rtp_termination_slot_t *termination_slot;
+       if(!session) {
+               return FALSE;
+       }
+       termination_slot = mrcp_client_rtp_termination_find(session,mpf_message->termination);
+       if(termination_slot) {
+               /* rtp termination */
+               mpf_rtp_termination_descriptor_t *rtp_descriptor;
+               if(termination_slot->waiting == FALSE) {
+                       return FALSE;
+               }
+               termination_slot->waiting = FALSE;
+               rtp_descriptor = mpf_message->descriptor;
+               if(rtp_descriptor->audio.local) {
+                       session->offer->ip = rtp_descriptor->audio.local->base.ip;
+                       session->offer->ext_ip = rtp_descriptor->audio.local->base.ext_ip;
+                       rtp_descriptor->audio.local->base.id = mrcp_session_audio_media_add(session->offer,rtp_descriptor->audio.local);
+                       rtp_descriptor->audio.local->mid = session->offer->audio_media_arr->nelts;
+               }
+               if(session->offer_flag_count) {
+                       session->offer_flag_count--;
+                       if(!session->offer_flag_count) {
+                               /* send offer to server */
+                               mrcp_client_session_offer_send(session);
+                       }
+               }
+       }
+       else {
+               /* channel termination */
+               mrcp_channel_t *channel = mrcp_client_channel_termination_find(session,mpf_message->termination);
+               if(channel && channel->waiting_for_termination == TRUE) {
+                       channel->waiting_for_termination = FALSE;
+                       if(session->offer_flag_count) {
+                               session->offer_flag_count--;
+                               if(!session->offer_flag_count) {
+                                       /* send offer to server */
+                                       mrcp_client_session_offer_send(session);
+                               }
+                       }
+               }
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_client_on_termination_modify(mrcp_client_session_t *session, mpf_message_t *mpf_message)
+{
+       rtp_termination_slot_t *termination_slot;
+       if(!session) {
+               return FALSE;
+       }
+       termination_slot = mrcp_client_rtp_termination_find(session,mpf_message->termination);
+       if(termination_slot) {
+               /* rtp termination */
+               if(termination_slot->waiting == FALSE) {
+                       return FALSE;
+               }
+               termination_slot->waiting = FALSE;
+               termination_slot->descriptor = mpf_message->descriptor;;
+
+               if(session->offer_flag_count) {
+                       session->offer_flag_count--;
+                       if(!session->offer_flag_count) {
+                               /* send offer to server */
+                               mrcp_client_session_offer_send(session);
+                       }
+               }
+               if(session->answer_flag_count) {
+                       session->answer_flag_count--;
+                       if(!session->answer_flag_count) {
+                               /* raise app response */
+                               mrcp_app_sig_response_raise(session,MRCP_SIG_STATUS_CODE_SUCCESS,TRUE);
+                       }
+               }
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_client_on_termination_subtract(mrcp_client_session_t *session, mpf_message_t *mpf_message)
+{
+       rtp_termination_slot_t *termination_slot;
+       if(!session) {
+               return FALSE;
+       }
+       termination_slot = mrcp_client_rtp_termination_find(session,mpf_message->termination);
+       if(termination_slot) {
+               /* rtp termination */
+               if(termination_slot->waiting == FALSE) {
+                       return FALSE;
+               }
+               termination_slot->waiting = FALSE;
+               if(session->terminate_flag_count) {
+                       session->terminate_flag_count--;
+                       if(!session->terminate_flag_count) {
+                               mrcp_app_session_terminate_raise(session,MRCP_SIG_STATUS_CODE_SUCCESS);
+                       }
+               }
+       }
+       else {
+               /* channel termination */
+               mrcp_channel_t *channel = mrcp_client_channel_termination_find(session,mpf_message->termination);
+               if(channel && channel->waiting_for_termination == TRUE) {
+                       channel->waiting_for_termination = FALSE;
+                       if(session->terminate_flag_count) {
+                               session->terminate_flag_count--;
+                               if(!session->terminate_flag_count) {
+                                       /* raise app response */
+                                       mrcp_app_sig_response_raise(session,MRCP_SIG_STATUS_CODE_SUCCESS,TRUE);
+                               }
+                       }
+               }
+       }
+       return TRUE;
+}
+
+apt_bool_t mrcp_client_mpf_message_process(mpf_message_t *mpf_message)
+{
+       mrcp_client_session_t *session = NULL;
+       if(mpf_message->context) {
+               session = mpf_context_object_get(mpf_message->context);
+       }
+       if(!session) {
+               return FALSE;
+       }
+       if(mpf_message->message_type == MPF_MESSAGE_TYPE_RESPONSE) {
+               switch(mpf_message->command_id) {
+                       case MPF_COMMAND_ADD:
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Termination Add "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+                               mrcp_client_on_termination_add(session,mpf_message);
+                               break;
+                       case MPF_COMMAND_MODIFY:
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Termination Modify "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+                               mrcp_client_on_termination_modify(session,mpf_message);
+                               break;
+                       case MPF_COMMAND_SUBTRACT:
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Termination Subtract "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+                               mrcp_client_on_termination_subtract(session,mpf_message);
+                               break;
+                       default:
+                               break;
+               }
+       }
+       else if(mpf_message->message_type == MPF_MESSAGE_TYPE_EVENT) {
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process MPF Event "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_client_resource_answer_process(mrcp_client_session_t *session, mrcp_session_descriptor_t *descriptor)
+{
+       apt_bool_t status = TRUE;
+       if(session->offer->resource_state == TRUE) {
+               if(descriptor->resource_state == TRUE) {
+                       mrcp_client_av_media_answer_process(session,descriptor);
+               }
+               else {
+                       status = FALSE;
+               }
+       }
+       return status;
+}
+
+static apt_bool_t mrcp_client_control_media_answer_process(mrcp_client_session_t *session, mrcp_session_descriptor_t *descriptor)
+{
+       mrcp_channel_t *channel;
+       mrcp_control_descriptor_t *control_descriptor;
+       int i;
+       int count = session->channels->nelts;
+       if(count != descriptor->control_media_arr->nelts) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Number of control channels [%d] != Number of control media in answer [%d]",
+                       count,descriptor->control_media_arr->nelts);
+               count = descriptor->control_media_arr->nelts;
+       }
+
+       if(!session->base.id.length) {
+               /* initial answer received, store session id and add to session's table */
+               control_descriptor = mrcp_session_control_media_get(descriptor,0);
+               if(control_descriptor) {
+                       session->base.id = control_descriptor->session_id;
+               }
+       }
+
+       /* update existing control channels */
+       for(i=0; i<count; i++) {
+               /* get existing channel */
+               channel = *((mrcp_channel_t**)session->channels->elts + i);
+               if(!channel) continue;
+
+               /* get control descriptor */
+               control_descriptor = mrcp_session_control_media_get(descriptor,i);
+               /* modify channel */
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Modify Control Channel "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+               if(mrcp_client_control_channel_modify(channel->control_channel,control_descriptor) == TRUE) {
+                       channel->waiting_for_channel = TRUE;
+                       session->answer_flag_count++;
+               }
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_client_av_media_answer_process(mrcp_client_session_t *session, mrcp_session_descriptor_t *descriptor)
+{
+       rtp_termination_slot_t *slot;
+       int i;
+       int count = session->terminations->nelts;
+       if(count != descriptor->audio_media_arr->nelts) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Number of terminations [%d] != Number of audio media in answer [%d]",
+                       count,descriptor->audio_media_arr->nelts);
+               count = descriptor->audio_media_arr->nelts;
+       }
+       
+       /* update existing terminations */
+       for(i=0; i<count; i++) {
+               mpf_rtp_media_descriptor_t *remote_media;
+               mpf_rtp_termination_descriptor_t *rtp_descriptor;
+               /* get existing termination */
+               slot = &((rtp_termination_slot_t*)session->terminations->elts)[i];
+               if(!slot) continue;
+
+               remote_media = mrcp_session_audio_media_get(descriptor,i);
+               if(slot->descriptor) {
+                       slot->descriptor->audio.remote = remote_media;
+               }
+               if(slot->termination) {
+                       /* construct termination descriptor */
+                       rtp_descriptor = apr_palloc(session->base.pool,sizeof(mpf_rtp_termination_descriptor_t));
+                       mpf_rtp_termination_descriptor_init(rtp_descriptor);
+                       rtp_descriptor->audio.local = NULL;
+                       rtp_descriptor->audio.remote = remote_media;
+
+                       /* send modify termination request */
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Modify Termination "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+                       if(mrcp_client_mpf_request_send(session->profile->media_engine,MPF_COMMAND_MODIFY,session->context,slot->termination,rtp_descriptor) == TRUE) {
+                               slot->waiting = TRUE;
+                               session->answer_flag_count++;
+                       }
+               }
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_app_request_dispatch(mrcp_client_session_t *session, const mrcp_app_message_t *app_message)
+{
+       if(session->registered == FALSE) {
+               session->base.signaling_agent = session->profile->signaling_agent;
+               session->base.signaling_agent->create_client_session(&session->base);
+
+               mrcp_client_session_add(session->application->client,session);
+               session->registered = TRUE;
+       }
+       switch(app_message->message_type) {
+               case MRCP_APP_MESSAGE_TYPE_SIGNALING:
+               {
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Dispatch Application Request "APT_PTRSID_FMT" [%d]",
+                               MRCP_SESSION_PTRSID(&session->base),
+                               app_message->sig_message.command_id);
+                       switch(app_message->sig_message.command_id) {
+                               case MRCP_SIG_COMMAND_SESSION_UPDATE:
+                                       mrcp_client_session_update(session);
+                                       break;
+                               case MRCP_SIG_COMMAND_SESSION_TERMINATE:
+                                       mrcp_client_session_terminate(session);
+                                       break;
+                               case MRCP_SIG_COMMAND_CHANNEL_ADD:
+                                       mrcp_client_channel_add(session,app_message->channel);
+                                       break;
+                               case MRCP_SIG_COMMAND_CHANNEL_REMOVE:
+                                       mrcp_client_channel_modify(session,app_message->channel,FALSE);
+                                       break;
+                               case MRCP_SIG_COMMAND_RESOURCE_DISCOVER:
+                                       mrcp_client_resource_discover(session);
+                                       break;
+                               default:
+                                       break;
+                       }
+                       break;
+               }
+               case MRCP_APP_MESSAGE_TYPE_CONTROL:
+               {
+                       mrcp_client_message_send(session,app_message->channel,app_message->control_message);
+                       break;
+               }
+       }
+       return TRUE;
+}
+
+/** Dispatch application message */
+MRCP_DECLARE(apt_bool_t) mrcp_application_message_dispatch(const mrcp_app_message_dispatcher_t *dispatcher, const mrcp_app_message_t *app_message)
+{
+       apt_bool_t status = FALSE;
+       switch(app_message->message_type) {
+               case MRCP_APP_MESSAGE_TYPE_SIGNALING:
+               {
+                       if(app_message->sig_message.message_type == MRCP_SIG_MESSAGE_TYPE_RESPONSE) {
+                               switch(app_message->sig_message.command_id) {
+                                       case MRCP_SIG_COMMAND_SESSION_UPDATE:
+                                               if(dispatcher->on_session_update) {
+                                                       status = dispatcher->on_session_update(
+                                                                               app_message->application,
+                                                                               app_message->session,
+                                                                               app_message->sig_message.status);
+                                               }
+                                               break;
+                                       case MRCP_SIG_COMMAND_SESSION_TERMINATE:
+                                               if(dispatcher->on_session_terminate) {
+                                                       status = dispatcher->on_session_terminate(
+                                                                               app_message->application,
+                                                                               app_message->session,
+                                                                               app_message->sig_message.status);
+                                               }
+                                               break;
+                                       case MRCP_SIG_COMMAND_CHANNEL_ADD:
+                                               if(dispatcher->on_channel_add) {
+                                                       status = dispatcher->on_channel_add(
+                                                                               app_message->application,
+                                                                               app_message->session,
+                                                                               app_message->channel,
+                                                                               app_message->sig_message.status);
+                                               }
+                                               break;
+                                       case MRCP_SIG_COMMAND_CHANNEL_REMOVE:
+                                               if(dispatcher->on_channel_remove) {
+                                                       status = dispatcher->on_channel_remove(
+                                                                               app_message->application,
+                                                                               app_message->session,
+                                                                               app_message->channel,
+                                                                               app_message->sig_message.status);
+                                               }
+                                               break;
+                                       case MRCP_SIG_COMMAND_RESOURCE_DISCOVER:
+                                               if(dispatcher->on_resource_discover) {
+                                                       status = dispatcher->on_resource_discover(
+                                                                               app_message->application,
+                                                                               app_message->session,
+                                                                               app_message->descriptor,
+                                                                               app_message->sig_message.status);
+                                               }
+                                               break;
+                                       default:
+                                               break;
+                               }
+                       }
+                       else if(app_message->sig_message.message_type == MRCP_SIG_MESSAGE_TYPE_EVENT) {
+                               switch(app_message->sig_message.event_id) {
+                                       case MRCP_SIG_EVENT_READY:
+                                               if(dispatcher->on_ready) {
+                                                       status = dispatcher->on_ready(
+                                                                               app_message->application,
+                                                                               app_message->sig_message.status);
+                                               }
+                                               break;
+                                       case MRCP_SIG_EVENT_TERMINATE:
+                                               if(dispatcher->on_terminate_event) {
+                                                       status = dispatcher->on_terminate_event(
+                                                                               app_message->application,
+                                                                               app_message->session,
+                                                                               app_message->channel);
+                                               }
+                                               break;
+                                       default:
+                                               break;
+                               }
+                       }
+                       break;
+               }
+               case MRCP_APP_MESSAGE_TYPE_CONTROL:
+               {
+                       if(dispatcher->on_message_receive) {
+                               status = dispatcher->on_message_receive(
+                                                                               app_message->application,
+                                                                               app_message->session,
+                                                                               app_message->channel,
+                                                                               app_message->control_message);
+                       }
+                       break;
+               }
+       }
+       return status;
+}
+
+static apt_bool_t mrcp_client_mpf_request_send(
+                                               mpf_engine_t *engine, 
+                                               mpf_command_type_e command_id,
+                                               mpf_context_t *context, 
+                                               mpf_termination_t *termination, 
+                                               void *descriptor)
+{
+       apt_task_t *media_task;
+       apt_task_msg_t *msg;
+       mpf_message_t *mpf_message;
+       if(!engine) {
+               return FALSE;
+       }
+       media_task = mpf_task_get(engine);
+       msg = apt_task_msg_get(media_task);
+       msg->type = TASK_MSG_USER;
+       mpf_message = (mpf_message_t*) msg->data;
+
+       mpf_message->message_type = MPF_MESSAGE_TYPE_REQUEST;
+       mpf_message->command_id = command_id;
+       mpf_message->context = context;
+       mpf_message->termination = termination;
+       mpf_message->descriptor = descriptor;
+       return apt_task_msg_signal(media_task,msg);
+}
diff --git a/libs/unimrcp/libs/mrcp-engine/Makefile.am b/libs/unimrcp/libs/mrcp-engine/Makefile.am
new file mode 100644 (file)
index 0000000..3dfab1b
--- /dev/null
@@ -0,0 +1,17 @@
+MAINTAINERCLEANFILES       = Makefile.in
+
+INCLUDES                    = -I$(top_srcdir)/libs/mrcp-engine/include \
+                              -I$(top_srcdir)/libs/mrcp/include \
+                              -I$(top_srcdir)/libs/mrcp/message/include \
+                              -I$(top_srcdir)/libs/mrcp/control/include \
+                              -I$(top_srcdir)/libs/mrcp/resources/include \
+                              -I$(top_srcdir)/libs/mpf/include \
+                              -I$(top_srcdir)/libs/apr-toolkit/include \
+                              $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+noinst_LTLIBRARIES          = libmrcpengine.la
+
+include_HEADERS             = include/mrcp_resource_plugin.h \
+                              include/mrcp_resource_engine.h
+
+libmrcpengine_la_SOURCES    = src/mrcp_resource_engine.c
diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_resource_engine.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_resource_engine.h
new file mode 100644 (file)
index 0000000..3df40cc
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_RESOURCE_ENGINE_H__
+#define __MRCP_RESOURCE_ENGINE_H__
+
+/**
+ * @file mrcp_resource_engine.h
+ * @brief MRCP Resource Engine Interface
+ */ 
+
+#include "mrcp_types.h"
+#include "mpf_termination.h"
+#include "mpf_stream.h"
+#include "mrcp_resource_plugin.h"
+
+APT_BEGIN_EXTERN_C
+
+/** MRCP resource engine vtable declaration */
+typedef struct mrcp_engine_method_vtable_t mrcp_engine_method_vtable_t;
+/** MRCP engine channel declaration */
+typedef struct mrcp_engine_channel_t mrcp_engine_channel_t;
+/** MRCP engine channel virtual method table declaration */
+typedef struct mrcp_engine_channel_method_vtable_t mrcp_engine_channel_method_vtable_t;
+/** MRCP engine channel virtual event table declaration */
+typedef struct mrcp_engine_channel_event_vtable_t mrcp_engine_channel_event_vtable_t;
+
+/** Table of channel virtual methods */
+struct mrcp_engine_channel_method_vtable_t {
+       /** Virtual destroy */
+       apt_bool_t (*destroy)(mrcp_engine_channel_t *channel);
+       /** Virtual open */
+       apt_bool_t (*open)(mrcp_engine_channel_t *channel);
+       /** Virtual close */
+       apt_bool_t (*close)(mrcp_engine_channel_t *channel);
+       /** Virtual process_request */
+       apt_bool_t (*process_request)(mrcp_engine_channel_t *channel, mrcp_message_t *request);
+};
+
+/** Table of channel virtual event handlers */
+struct mrcp_engine_channel_event_vtable_t {
+       /** Open event handler */
+       apt_bool_t (*on_open)(mrcp_engine_channel_t *channel, apt_bool_t status);
+       /** Close event handler */
+       apt_bool_t (*on_close)(mrcp_engine_channel_t *channel);
+       /** Message event handler */
+       apt_bool_t (*on_message)(mrcp_engine_channel_t *channel, mrcp_message_t *message);
+};
+
+/** MRCP engine channel declaration */
+struct mrcp_engine_channel_t {
+       /** Table of virtual methods */
+       const mrcp_engine_channel_method_vtable_t *method_vtable;
+       /** External object used with virtual methods */
+       void                                      *method_obj;
+       /** Table of virtual event handlers */
+       const mrcp_engine_channel_event_vtable_t  *event_vtable;
+       /** External object used with event handlers */
+       void                                      *event_obj;
+       /** Media termination */
+       mpf_termination_t                         *termination;
+       /** Back pointer to resource engine */
+       mrcp_resource_engine_t                    *engine;
+       /** Pool to allocate memory from */
+       apr_pool_t                                *pool;
+};
+
+/** Table of MRCP engine virtual methods */
+struct mrcp_engine_method_vtable_t {
+       /** Virtual destroy */
+       apt_bool_t (*destroy)(mrcp_resource_engine_t *engine);
+       /** Virtual open */
+       apt_bool_t (*open)(mrcp_resource_engine_t *engine);
+       /** Virtual close */
+       apt_bool_t (*close)(mrcp_resource_engine_t *engine);
+       /** Virtual channel create */
+       mrcp_engine_channel_t* (*create_channel)(mrcp_resource_engine_t *engine, apr_pool_t *pool);
+};
+
+/** MRCP resource engine */
+struct mrcp_resource_engine_t {
+       /** Plugin version */
+       mrcp_plugin_version_t              plugin_version;
+       /** Resource identifier */
+       mrcp_resource_id                   resource_id;
+       /** External object associated with engine */
+       void                              *obj;
+       /** Table of virtual methods */
+       const mrcp_engine_method_vtable_t *method_vtable;
+       /** Codec manager */
+       const mpf_codec_manager_t         *codec_manager;
+       /** Dir layout structure */
+       const apt_dir_layout_t            *dir_layout;
+       /** Pool to allocate memory from */
+       apr_pool_t                        *pool;
+};
+
+/** Create resource engine */
+mrcp_resource_engine_t* mrcp_resource_engine_create(
+                                                               mrcp_resource_id resource_id,
+                                                               void *obj, 
+                                                               const mrcp_engine_method_vtable_t *vtable,
+                                                               apr_pool_t *pool);
+
+/** Destroy resource engine */
+static APR_INLINE apt_bool_t mrcp_resource_engine_destroy(mrcp_resource_engine_t *engine)
+{
+       return engine->method_vtable->destroy(engine);
+}
+
+/** Open resource engine */
+static APR_INLINE apt_bool_t mrcp_resource_engine_open(mrcp_resource_engine_t *engine)
+{
+       return engine->method_vtable->open(engine);
+}
+
+/** Close resource engine */
+static APR_INLINE apt_bool_t mrcp_resource_engine_close(mrcp_resource_engine_t *engine)
+{
+       return engine->method_vtable->close(engine);
+}
+
+/** Create engine channel */
+mrcp_engine_channel_t* mrcp_engine_channel_create(
+                                                               mrcp_resource_engine_t *engine,
+                                                               const mrcp_engine_channel_method_vtable_t *method_vtable,
+                                                               void *method_obj,
+                                                               mpf_termination_t *termination,
+                                                               apr_pool_t *pool);
+
+/** Create engine channel and source media termination */
+mrcp_engine_channel_t* mrcp_engine_source_channel_create(
+                                                               mrcp_resource_engine_t *engine,
+                                                               const mrcp_engine_channel_method_vtable_t *channel_vtable,
+                                                               const mpf_audio_stream_vtable_t *stream_vtable,
+                                                               void *method_obj,
+                                                               mpf_codec_descriptor_t *codec_descriptor,
+                                                               apr_pool_t *pool);
+
+/** Create engine channel and sink media termination */
+mrcp_engine_channel_t* mrcp_engine_sink_channel_create(
+                                                               mrcp_resource_engine_t *engine,
+                                                               const mrcp_engine_channel_method_vtable_t *channel_vtable,
+                                                               const mpf_audio_stream_vtable_t *stream_vtable,
+                                                               void *method_obj,
+                                                               mpf_codec_descriptor_t *codec_descriptor,
+                                                               apr_pool_t *pool);
+
+/** Destroy engine channel */
+static APR_INLINE apt_bool_t mrcp_engine_channel_destroy(mrcp_engine_channel_t *channel)
+{
+       return channel->method_vtable->destroy(channel);
+}
+
+/** Open engine channel */
+static APR_INLINE apt_bool_t mrcp_engine_channel_open(mrcp_engine_channel_t *channel)
+{
+       return channel->method_vtable->open(channel);
+}
+
+/** Close engine channel */
+static APR_INLINE apt_bool_t mrcp_engine_channel_close(mrcp_engine_channel_t *channel)
+{
+       return channel->method_vtable->close(channel);
+}
+
+/** Process request */
+static APR_INLINE apt_bool_t mrcp_engine_channel_request_process(mrcp_engine_channel_t *channel, mrcp_message_t *message)
+{
+       return channel->method_vtable->process_request(channel,message);
+}
+
+/** Send channel open response */
+static APR_INLINE apt_bool_t mrcp_engine_channel_open_respond(mrcp_engine_channel_t *channel, apt_bool_t status)
+{
+       return channel->event_vtable->on_open(channel,status);
+}
+
+/** Send channel close response */
+static APR_INLINE apt_bool_t mrcp_engine_channel_close_respond(mrcp_engine_channel_t *channel)
+{
+       return channel->event_vtable->on_close(channel);
+}
+
+/** Send response/event message */
+static APR_INLINE apt_bool_t mrcp_engine_channel_message_send(mrcp_engine_channel_t *channel, mrcp_message_t *message)
+{
+       return channel->event_vtable->on_message(channel,message);
+}
+
+/** Get codec of the audio source stream */
+mpf_codec_t* mrcp_engine_source_stream_codec_get(mrcp_engine_channel_t *channel);
+
+/** Get codec of the audio sink stream */
+mpf_codec_t* mrcp_engine_sink_stream_codec_get(mrcp_engine_channel_t *channel);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_RESOURCE_ENGINE_H__*/
diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_resource_plugin.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_resource_plugin.h
new file mode 100644 (file)
index 0000000..4dcc3be
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_RESOURCE_PLUGIN_H__
+#define __MRCP_RESOURCE_PLUGIN_H__
+
+/**
+ * @file mrcp_resource_plugin.h
+ * @brief MRCP Resource Engine Plugin
+ */ 
+
+#include "apr_version.h"
+#include "apt_log.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Plugin export defines */
+#ifdef WIN32
+#define MRCP_PLUGIN_DECLARE(type) EXTERN_C __declspec(dllexport) type
+#else
+#define MRCP_PLUGIN_DECLARE(type) type
+#endif
+
+/** Symbol name of the main entry point in plugin DSO */
+#define MRCP_PLUGIN_ENGINE_SYM_NAME "mrcp_plugin_create"
+/** Symbol name of the log accessor entry point in plugin DSO */
+#define MRCP_PLUGIN_LOGGER_SYM_NAME "mrcp_plugin_logger_set"
+
+/** MRCP resource engine declaration */
+typedef struct mrcp_resource_engine_t mrcp_resource_engine_t;
+/** Prototype of resource engine creator (entry point of plugin DSO) */
+typedef mrcp_resource_engine_t* (*mrcp_plugin_creator_f)(apr_pool_t *pool);
+
+/** Prototype of resource engine creator (entry point of plugin DSO) */
+typedef apt_bool_t (*mrcp_plugin_log_accessor_f)(apt_logger_t *logger);
+
+/** Declare this macro in plugins to use log routine of the server */
+#define MRCP_PLUGIN_LOGGER_IMPLEMENT \
+       MRCP_PLUGIN_DECLARE(apt_bool_t) mrcp_plugin_logger_set(apt_logger_t *logger) \
+               { return apt_log_instance_set(logger); }
+
+
+/** major version 
+ * Major API changes that could cause compatibility problems for older
+ * plugins such as structure size changes.  No binary compatibility is
+ * possible across a change in the major version.
+ */
+#define PLUGIN_MAJOR_VERSION   0
+
+/** minor version
+ * Minor API changes that do not cause binary compatibility problems.
+ * Reset to 0 when upgrading PLUGIN_MAJOR_VERSION
+ */
+#define PLUGIN_MINOR_VERSION   4
+
+/** patch level 
+ * The Patch Level never includes API changes, simply bug fixes.
+ * Reset to 0 when upgrading PLUGIN_MINOR_VERSION
+ */
+#define PLUGIN_PATCH_VERSION   0
+
+
+/**
+ * Check at compile time if the plugin version is at least a certain
+ * level.
+ */
+#define PLUGIN_VERSION_AT_LEAST(major,minor,patch)                    \
+(((major) < PLUGIN_MAJOR_VERSION)                                     \
+ || ((major) == PLUGIN_MAJOR_VERSION && (minor) < PLUGIN_MINOR_VERSION) \
+ || ((major) == PLUGIN_MAJOR_VERSION && (minor) == PLUGIN_MINOR_VERSION && (patch) <= PLUGIN_PATCH_VERSION))
+
+/** The formatted string of plugin's version */
+#define PLUGIN_VERSION_STRING \
+     APR_STRINGIFY(PLUGIN_MAJOR_VERSION) "." \
+     APR_STRINGIFY(PLUGIN_MINOR_VERSION) "." \
+     APR_STRINGIFY(PLUGIN_PATCH_VERSION)
+
+/** Plugin version */
+typedef apr_version_t mrcp_plugin_version_t;
+
+/** Get plugin version */
+static APR_INLINE void mrcp_plugin_version_get(mrcp_plugin_version_t *version)
+{
+       version->major = PLUGIN_MAJOR_VERSION;
+       version->minor = PLUGIN_MINOR_VERSION;
+       version->patch = PLUGIN_PATCH_VERSION;
+}
+
+/** Check plugin version */
+static APR_INLINE int mrcp_plugin_version_check(mrcp_plugin_version_t *version)
+{
+       return PLUGIN_VERSION_AT_LEAST(version->major,version->minor,version->patch);
+}
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_RESOURCE_PLUGIN_H__*/
diff --git a/libs/unimrcp/libs/mrcp-engine/mrcpengine.vcproj b/libs/unimrcp/libs/mrcp-engine/mrcpengine.vcproj
new file mode 100644 (file)
index 0000000..1ac2946
--- /dev/null
@@ -0,0 +1,153 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="mrcpengine"
+       ProjectGUID="{843425BE-9A9A-44F4-A4E3-4B57D6ABD53C}"
+       RootNamespace="mrcpengine"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\mrcpengine.vsprops"
+                       CharacterSet="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\mrcpengine.vsprops"
+                       CharacterSet="1"
+                       WholeProgramOptimization="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+                       <File
+                               RelativePath=".\include\mrcp_resource_engine.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_resource_plugin.h"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       >
+                       <File
+                               RelativePath=".\src\mrcp_resource_engine.c"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/libs/mrcp-engine/src/mrcp_resource_engine.c b/libs/unimrcp/libs/mrcp-engine/src/mrcp_resource_engine.c
new file mode 100644 (file)
index 0000000..280e2a6
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mrcp_resource_engine.h"
+#include "mpf_codec_manager.h"
+
+/** Create resource engine */
+mrcp_resource_engine_t* mrcp_resource_engine_create(
+                                                               mrcp_resource_id resource_id,
+                                                               void *obj, 
+                                                               const mrcp_engine_method_vtable_t *vtable,
+                                                               apr_pool_t *pool)
+{
+       mrcp_resource_engine_t *engine = apr_palloc(pool,sizeof(mrcp_resource_engine_t));
+       mrcp_plugin_version_get(&engine->plugin_version);
+       engine->resource_id = resource_id;
+       engine->obj = obj;
+       engine->method_vtable =vtable;
+       engine->codec_manager = NULL;
+       engine->dir_layout = NULL;
+       engine->pool = pool;
+       return engine;
+}
+
+/** Create engine channel */
+mrcp_engine_channel_t* mrcp_engine_channel_create(
+                                                               mrcp_resource_engine_t *engine, 
+                                                               const mrcp_engine_channel_method_vtable_t *method_vtable,
+                                                               void *method_obj,
+                                                               mpf_termination_t *termination,
+                                                               apr_pool_t *pool)
+{
+       mrcp_engine_channel_t *channel = apr_palloc(pool,sizeof(mrcp_engine_channel_t));
+       channel->method_vtable = method_vtable;
+       channel->method_obj = method_obj;
+       channel->event_vtable = NULL;
+       channel->event_obj = NULL;
+       channel->termination = termination;
+       channel->engine = engine;
+       channel->pool = pool;
+       return channel;
+}
+
+/** Create engine channel and source media termination */
+mrcp_engine_channel_t* mrcp_engine_source_channel_create(
+                                                               mrcp_resource_engine_t *engine,
+                                                               const mrcp_engine_channel_method_vtable_t *channel_vtable,
+                                                               const mpf_audio_stream_vtable_t *stream_vtable,
+                                                               void *method_obj,
+                                                               mpf_codec_descriptor_t *codec_descriptor,
+                                                               apr_pool_t *pool)
+{
+       mpf_audio_stream_t *audio_stream;
+       mpf_termination_t *termination;
+       /* create audio stream */
+       audio_stream = mpf_audio_stream_create(
+                       method_obj,           /* object to associate */
+                       stream_vtable,        /* virtual methods table of audio stream */
+                       STREAM_MODE_RECEIVE,  /* stream mode/direction */
+                       pool);                /* pool to allocate memory from */
+
+       if(engine->codec_manager) {
+               audio_stream->rx_codec = mpf_codec_manager_codec_get(engine->codec_manager,codec_descriptor,pool);
+       }
+       
+       /* create media termination */
+       termination = mpf_raw_termination_create(
+                       NULL,                 /* no object to associate */
+                       audio_stream,         /* audio stream */
+                       NULL,                 /* no video stream */
+                       pool);                /* pool to allocate memory from */
+
+       /* create engine channel base */
+       return mrcp_engine_channel_create(
+                       engine,          /* resource engine */
+                       channel_vtable,  /* virtual methods table of engine channel */
+                       method_obj,      /* object to associate */
+                       termination,     /* media termination, used to terminate audio stream */
+                       pool);           /* pool to allocate memory from */
+}
+
+/** Create engine channel and sink media termination */
+mrcp_engine_channel_t* mrcp_engine_sink_channel_create(
+                                                               mrcp_resource_engine_t *engine,
+                                                               const mrcp_engine_channel_method_vtable_t *channel_vtable,
+                                                               const mpf_audio_stream_vtable_t *stream_vtable,
+                                                               void *method_obj,
+                                                               mpf_codec_descriptor_t *codec_descriptor,
+                                                               apr_pool_t *pool)
+{
+       mpf_audio_stream_t *audio_stream;
+       mpf_termination_t *termination;
+
+       /* create audio stream */
+       audio_stream = mpf_audio_stream_create(
+                       method_obj,             /* object to associate */
+                       stream_vtable,          /* virtual methods table of audio stream */
+                       STREAM_MODE_SEND,       /* stream mode/direction */
+                       pool);                  /* pool to allocate memory from */
+       
+       if(engine->codec_manager) {
+               audio_stream->tx_codec = mpf_codec_manager_codec_get(engine->codec_manager,codec_descriptor,pool);
+       }
+       
+       /* create media termination */
+       termination = mpf_raw_termination_create(
+                       NULL,            /* no object to associate */
+                       audio_stream,    /* audio stream */
+                       NULL,            /* no video stream */
+                       pool);           /* pool to allocate memory from */
+
+       /* create engine channel base */
+       return mrcp_engine_channel_create(
+                       engine,          /* resource engine */
+                       channel_vtable,  /* virtual methods table of engine channel */
+                       method_obj,      /* object to associate */
+                       termination,     /* media termination, used to terminate audio stream */
+                       pool);           /* pool to allocate memory from */
+}
+
+/** Get codec of the audio source stream */
+mpf_codec_t* mrcp_engine_source_stream_codec_get(mrcp_engine_channel_t *channel)
+{
+       if(channel && channel->termination && channel->termination->audio_stream) {
+               return channel->termination->audio_stream->rx_codec;
+       }
+       return NULL;
+}
+
+/** Get codec of the audio sink stream */
+mpf_codec_t* mrcp_engine_sink_stream_codec_get(mrcp_engine_channel_t *channel)
+{
+       if(channel && channel->termination && channel->termination->audio_stream) {
+               return channel->termination->audio_stream->tx_codec;
+       }
+       return NULL;
+}
diff --git a/libs/unimrcp/libs/mrcp-server/Makefile.am b/libs/unimrcp/libs/mrcp-server/Makefile.am
new file mode 100644 (file)
index 0000000..ba1c8ae
--- /dev/null
@@ -0,0 +1,22 @@
+MAINTAINERCLEANFILES       = Makefile.in
+
+INCLUDES                    = -I$(top_srcdir)/libs/mrcp-server/include \
+                              -I$(top_srcdir)/libs/mrcp-engine/include \
+                              -I$(top_srcdir)/libs/mrcp-signaling/include \
+                              -I$(top_srcdir)/libs/mrcpv2-transport/include \
+                              -I$(top_srcdir)/libs/mrcp/include \
+                              -I$(top_srcdir)/libs/mrcp/message/include \
+                              -I$(top_srcdir)/libs/mrcp/control/include \
+                              -I$(top_srcdir)/libs/mrcp/resources/include \
+                              -I$(top_srcdir)/libs/mpf/include \
+                              -I$(top_srcdir)/libs/apr-toolkit/include \
+                              $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+noinst_LTLIBRARIES          = libmrcpserver.la
+
+include_HEADERS             = include/mrcp_server_types.h \
+                              include/mrcp_server.h \
+                              include/mrcp_server_session.h
+
+libmrcpserver_la_SOURCES    = src/mrcp_server.c \
+                              src/mrcp_server_session.c
diff --git a/libs/unimrcp/libs/mrcp-server/include/mrcp_server.h b/libs/unimrcp/libs/mrcp-server/include/mrcp_server.h
new file mode 100644 (file)
index 0000000..e494636
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_SERVER_H__
+#define __MRCP_SERVER_H__
+
+/**
+ * @file mrcp_server.h
+ * @brief MRCP Server
+ */ 
+
+#include "mrcp_server_types.h"
+#include "mrcp_resource_engine.h"
+#include "apt_task.h"
+
+APT_BEGIN_EXTERN_C
+
+/**
+ * Create MRCP server instance.
+ * @return the created server instance
+ */
+MRCP_DECLARE(mrcp_server_t*) mrcp_server_create(apt_dir_layout_t *dir_layout);
+
+/**
+ * Start message processing loop.
+ * @param server the MRCP server to start
+ * @return the created server instance
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_server_start(mrcp_server_t *server);
+
+/**
+ * Shutdown message processing loop.
+ * @param server the MRCP server to shutdown
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_server_shutdown(mrcp_server_t *server);
+
+/**
+ * Destroy MRCP server.
+ * @param server the MRCP server to destroy
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_server_destroy(mrcp_server_t *server);
+
+
+/**
+ * Register MRCP resource factory.
+ * @param server the MRCP server to set resource factory for
+ * @param resource_factory the resource factory to set
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_server_resource_factory_register(mrcp_server_t *server, mrcp_resource_factory_t *resource_factory);
+
+/**
+ * Register MRCP resource engine.
+ * @param server the MRCP server to set engine for
+ * @param engine the resource engine to set
+ * @param name the name of the resource engine
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_server_resource_engine_register(mrcp_server_t *server, mrcp_resource_engine_t *engine, const char *name);
+
+/**
+ * Register codec manager.
+ * @param server the MRCP server to set codec manager for
+ * @param codec_manager the codec manager to set
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_server_codec_manager_register(mrcp_server_t *server, mpf_codec_manager_t *codec_manager);
+
+/**
+ * Get registered codec manager.
+ * @param server the MRCP server to get codec manager from
+ */
+MRCP_DECLARE(const mpf_codec_manager_t*) mrcp_server_codec_manager_get(mrcp_server_t *server);
+
+/**
+ * Register media engine.
+ * @param server the MRCP server to set media engine for
+ * @param media_engine the media engine to set
+ * @param name the name of the media engine
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_server_media_engine_register(mrcp_server_t *server, mpf_engine_t *media_engine, const char *name);
+
+/**
+ * Register RTP termination factory.
+ * @param server the MRCP server to set termination factory for
+ * @param rtp_termination_factory the termination factory
+ * @param name the name of the factory
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_server_rtp_factory_register(mrcp_server_t *server, mpf_termination_factory_t *rtp_termination_factory, const char *name);
+
+/**
+ * Register MRCP signaling agent.
+ * @param server the MRCP server to set signaling agent for
+ * @param signaling_agent the signaling agent to set
+ * @param name the name of the agent
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_server_signaling_agent_register(mrcp_server_t *server, mrcp_sig_agent_t *signaling_agent, const char *name);
+
+/**
+ * Register MRCP connection agent (MRCPv2 only).
+ * @param server the MRCP server to set connection agent for
+ * @param connection_agent the connection agent to set
+ * @param name the name of the agent
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_server_connection_agent_register(mrcp_server_t *server, mrcp_connection_agent_t *connection_agent, const char *name);
+
+/** Create MRCP profile */
+MRCP_DECLARE(mrcp_profile_t*) mrcp_server_profile_create(
+                                                                       mrcp_resource_factory_t *resource_factory,
+                                                                       mrcp_sig_agent_t *signaling_agent,
+                                                                       mrcp_connection_agent_t *connection_agent,
+                                                                       mpf_engine_t *media_engine,
+                                                                       mpf_termination_factory_t *rtp_factory,
+                                                                       apr_pool_t *pool);
+
+/**
+ * Register MRCP profile.
+ * @param server the MRCP server to set profile for
+ * @param profile the profile to set
+ * @param plugin_map the map of resource engines (plugins)
+ * @param name the name of the profile
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_server_profile_register(
+                                                                       mrcp_server_t *server, 
+                                                                       mrcp_profile_t *profile,
+                                                                       apr_table_t *plugin_map,
+                                                                       const char *name);
+
+/**
+ * Register resource engine plugin.
+ * @param server the MRCP server to set engine for
+ * @param path the path to plugin
+ * @param name the name of the plugin
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_server_plugin_register(mrcp_server_t *server, const char *path, const char *name);
+
+/**
+ * Get memory pool.
+ * @param server the MRCP server to get memory pool from
+ */
+MRCP_DECLARE(apr_pool_t*) mrcp_server_memory_pool_get(mrcp_server_t *server);
+
+/**
+ * Get resource engine by name.
+ * @param server the MRCP server to get resource engine from
+ * @param name the name of the resource engine to lookup
+ */
+MRCP_DECLARE(mrcp_resource_engine_t*) mrcp_server_resource_engine_get(mrcp_server_t *server, const char *name);
+
+/**
+ * Get media engine by name.
+ * @param server the MRCP server to get media engine from
+ * @param name the name of the media engine to lookup
+ */
+MRCP_DECLARE(mpf_engine_t*) mrcp_server_media_engine_get(mrcp_server_t *server, const char *name);
+
+/**
+ * Get RTP termination factory by name.
+ * @param server the MRCP server to get from
+ * @param name the name to lookup
+ */
+MRCP_DECLARE(mpf_termination_factory_t*) mrcp_server_rtp_factory_get(mrcp_server_t *server, const char *name);
+
+/**
+ * Get signaling agent by name.
+ * @param server the MRCP server to get from
+ * @param name the name to lookup
+ */
+MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_server_signaling_agent_get(mrcp_server_t *server, const char *name);
+
+/**
+ * Get connection agent by name.
+ * @param server the MRCP server to get from
+ * @param name the name to lookup
+ */
+MRCP_DECLARE(mrcp_connection_agent_t*) mrcp_server_connection_agent_get(mrcp_server_t *server, const char *name);
+
+/**
+ * Get profile by name.
+ * @param server the MRCP client to get from
+ * @param name the name to lookup
+ */
+MRCP_DECLARE(mrcp_profile_t*) mrcp_server_profile_get(mrcp_server_t *server, const char *name);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_SERVER_H__*/
diff --git a/libs/unimrcp/libs/mrcp-server/include/mrcp_server_session.h b/libs/unimrcp/libs/mrcp-server/include/mrcp_server_session.h
new file mode 100644 (file)
index 0000000..dcc0544
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_SERVER_SESSION_H__
+#define __MRCP_SERVER_SESSION_H__
+
+/**
+ * @file mrcp_server_session.h
+ * @brief MRCP Server Session
+ */ 
+
+#include <apr_hash.h>
+#include "mrcp_session.h"
+#include "mpf_message.h"
+#include "apt_task.h"
+#include "apt_obj_list.h"
+
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque MRCP channel declaration */
+typedef struct mrcp_channel_t mrcp_channel_t;
+/** MRCP server session declaration */
+typedef struct mrcp_server_session_t mrcp_server_session_t;
+/** MRCP signaling message declaration */
+typedef struct mrcp_signaling_message_t mrcp_signaling_message_t;
+
+/** Enumeration of signaling task messages */
+typedef enum {
+       SIGNALING_MESSAGE_OFFER,
+       SIGNALING_MESSAGE_CONTROL,
+       SIGNALING_MESSAGE_TERMINATE,
+} mrcp_signaling_message_type_e;
+
+/** MRCP signaling message */
+struct mrcp_signaling_message_t {
+       /** Signaling message type */
+       mrcp_signaling_message_type_e type;
+
+       /** Session */
+       mrcp_server_session_t        *session;
+       /** Descriptor */
+       mrcp_session_descriptor_t    *descriptor;
+
+       /** Channel */
+       mrcp_channel_t               *channel;
+       /** MRCP message */
+       mrcp_message_t               *message;
+};
+
+
+/** MRCP server session */
+struct mrcp_server_session_t {
+       /** Session base */
+       mrcp_session_t             base;
+       /** MRCP server */
+       mrcp_server_t             *server;
+       /** MRCP profile */
+       mrcp_profile_t            *profile;
+
+       /** Media context */
+       mpf_context_t             *context;
+
+       /** Media termination array */
+       apr_array_header_t        *terminations;
+       /** MRCP control channel array */
+       apr_array_header_t        *channels;
+
+       /** In-progress signaling request */
+       mrcp_signaling_message_t  *active_request;
+       /** Signaling request queue */
+       apt_obj_list_t            *request_queue;
+
+       /** In-progress offer */
+       mrcp_session_descriptor_t *offer;
+       /** In-progres answer */
+       mrcp_session_descriptor_t *answer;
+
+       /** Number of in-progress answer requests (flags) */
+       apr_size_t                 answer_flag_count;
+       /** Number of in-progress terminate requests (flags) */
+       apr_size_t                 terminate_flag_count;
+};
+
+/** MRCP profile */
+struct mrcp_profile_t {
+       /** Table of resource engines (mrcp_resource_engine_t*) */
+       apr_hash_t                *engine_table;
+       /** MRCP resource factory */
+       mrcp_resource_factory_t   *resource_factory;
+       /** Media processing engine */
+       mpf_engine_t              *media_engine;
+       /** RTP termination factory */
+       mpf_termination_factory_t *rtp_termination_factory;
+       /** Signaling agent */
+       mrcp_sig_agent_t          *signaling_agent;
+       /** Connection agent */
+       mrcp_connection_agent_t   *connection_agent;
+};
+
+/** Create server session */
+mrcp_server_session_t* mrcp_server_session_create();
+
+/** Process signaling message */
+apt_bool_t mrcp_server_signaling_message_process(mrcp_signaling_message_t *signaling_message);
+/** Process MPF message */
+apt_bool_t mrcp_server_mpf_message_process(mpf_message_t *mpf_message);
+
+/** Process channel modify event */
+apt_bool_t mrcp_server_on_channel_modify(mrcp_channel_t *channel, mrcp_control_descriptor_t *answer, apt_bool_t status);
+/** Process channel remove event */
+apt_bool_t mrcp_server_on_channel_remove(mrcp_channel_t *channel, apt_bool_t status);
+/** Process channel message receive */
+apt_bool_t mrcp_server_on_channel_message(mrcp_channel_t *channel, mrcp_message_t *message);
+
+/** Process channel open event */
+apt_bool_t mrcp_server_on_engine_channel_open(mrcp_channel_t *channel, apt_bool_t status);
+/** Process channel close event */
+apt_bool_t mrcp_server_on_engine_channel_close(mrcp_channel_t *channel);
+/** Process message receive event */
+apt_bool_t mrcp_server_on_engine_channel_message(mrcp_channel_t *channel, mrcp_message_t *message);
+
+/** Get session by channel */
+mrcp_session_t* mrcp_server_channel_session_get(mrcp_channel_t *channel);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_SERVER_SESSION_H__*/
diff --git a/libs/unimrcp/libs/mrcp-server/include/mrcp_server_types.h b/libs/unimrcp/libs/mrcp-server/include/mrcp_server_types.h
new file mode 100644 (file)
index 0000000..ac640fc
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_SERVER_TYPES_H__
+#define __MRCP_SERVER_TYPES_H__
+
+/**
+ * @file mrcp_server_types.h
+ * @brief MRCP Server Types
+ */ 
+
+#include "mrcp_sig_types.h"
+#include "mrcp_connection_types.h"
+#include "mpf_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque MRCP server declaration */
+typedef struct mrcp_server_t mrcp_server_t;
+
+/** Opaque MRCP profile declaration */
+typedef struct mrcp_profile_t mrcp_profile_t;
+
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_SERVER_TYPES_H__*/
diff --git a/libs/unimrcp/libs/mrcp-server/mrcpserver.vcproj b/libs/unimrcp/libs/mrcp-server/mrcpserver.vcproj
new file mode 100644 (file)
index 0000000..9cd5de4
--- /dev/null
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="mrcpserver"
+       ProjectGUID="{18B1F35A-10F8-4287-9B37-2D10501B0B38}"
+       RootNamespace="mrcpserver"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\mrcpserver.vsprops"
+                       CharacterSet="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\mrcpserver.vsprops"
+                       CharacterSet="1"
+                       WholeProgramOptimization="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+                       <File
+                               RelativePath=".\include\mrcp_server.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_server_session.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_server_types.h"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       >
+                       <File
+                               RelativePath=".\src\mrcp_server.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\mrcp_server_session.c"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/libs/mrcp-server/src/mrcp_server.c b/libs/unimrcp/libs/mrcp-server/src/mrcp_server.c
new file mode 100644 (file)
index 0000000..6ef74b2
--- /dev/null
@@ -0,0 +1,930 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_dso.h>
+#include "mrcp_server.h"
+#include "mrcp_server_session.h"
+#include "mrcp_message.h"
+#include "mrcp_resource_factory.h"
+#include "mrcp_sig_agent.h"
+#include "mrcp_server_connection.h"
+#include "mpf_engine.h"
+#include "apt_pool.h"
+#include "apt_consumer_task.h"
+#include "apt_obj_list.h"
+#include "apt_log.h"
+
+#define SERVER_TASK_NAME "MRCP Server"
+
+/** MRCP server */
+struct mrcp_server_t {
+       /** Main message processing task */
+       apt_consumer_task_t     *task;
+
+       /** MRCP resource factory */
+       mrcp_resource_factory_t *resource_factory;
+       /** Codec manager */
+       mpf_codec_manager_t     *codec_manager;
+       /** Table of resource engines (mrcp_resource_engine_t*) */
+       apr_hash_t              *resource_engine_table;
+       /** Table of media processing engines (mpf_engine_t*) */
+       apr_hash_t              *media_engine_table;
+       /** Table of RTP termination factories (mpf_termination_factory_t*) */
+       apr_hash_t              *rtp_factory_table;
+       /** Table of signaling agents (mrcp_sig_agent_t*) */
+       apr_hash_t              *sig_agent_table;
+       /** Table of connection agents (mrcp_connection_agent_t*) */
+       apr_hash_t              *cnt_agent_table;
+       /** Table of profiles (mrcp_profile_t*) */
+       apr_hash_t              *profile_table;
+       /** Table of plugins (apr_dso_handle_t*) */
+       apr_hash_t              *plugin_table;
+
+       /** Table of sessions */
+       apr_hash_t              *session_table;
+
+       /** Connection task message pool */
+       apt_task_msg_pool_t     *connection_msg_pool;
+       /** Resource engine task message pool */
+       apt_task_msg_pool_t     *resource_engine_msg_pool;
+
+       /** Dir layout structure */
+       apt_dir_layout_t        *dir_layout;
+       /** Time server started at */
+       apr_time_t               start_time;
+       /** Memory pool */
+       apr_pool_t              *pool;
+};
+
+
+typedef enum {
+       MRCP_SERVER_SIGNALING_TASK_MSG = TASK_MSG_USER,
+       MRCP_SERVER_CONNECTION_TASK_MSG,
+       MRCP_SERVER_RESOURCE_ENGINE_TASK_MSG,
+       MRCP_SERVER_MEDIA_TASK_MSG
+} mrcp_server_task_msg_type_e;
+
+
+static apt_bool_t mrcp_server_offer_signal(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor);
+static apt_bool_t mrcp_server_terminate_signal(mrcp_session_t *session);
+static apt_bool_t mrcp_server_control_signal(mrcp_session_t *session, mrcp_message_t *message);
+
+static const mrcp_session_request_vtable_t session_request_vtable = {
+       mrcp_server_offer_signal,
+       mrcp_server_terminate_signal,
+       mrcp_server_control_signal
+};
+
+
+/* Connection agent interface */
+typedef enum {
+       CONNECTION_AGENT_TASK_MSG_ADD_CHANNEL,
+       CONNECTION_AGENT_TASK_MSG_MODIFY_CHANNEL,
+       CONNECTION_AGENT_TASK_MSG_REMOVE_CHANNEL,
+       CONNECTION_AGENT_TASK_MSG_RECEIVE_MESSAGE,
+       CONNECTION_AGENT_TASK_MSG_TERMINATE
+} connection_agent_task_msg_type_e;
+
+typedef struct connection_agent_task_msg_data_t connection_agent_task_msg_data_t;
+struct connection_agent_task_msg_data_t {
+       mrcp_channel_t            *channel;
+       mrcp_control_descriptor_t *descriptor;
+       mrcp_message_t            *message;
+       apt_bool_t                 status;
+};
+
+static apt_bool_t mrcp_server_channel_add_signal(mrcp_control_channel_t *channel, mrcp_control_descriptor_t *descriptor, apt_bool_t status);
+static apt_bool_t mrcp_server_channel_modify_signal(mrcp_control_channel_t *channel, mrcp_control_descriptor_t *descriptor, apt_bool_t status);
+static apt_bool_t mrcp_server_channel_remove_signal(mrcp_control_channel_t *channel, apt_bool_t status);
+static apt_bool_t mrcp_server_message_signal(mrcp_control_channel_t *channel, mrcp_message_t *message);
+
+static const mrcp_connection_event_vtable_t connection_method_vtable = {
+       mrcp_server_channel_add_signal,
+       mrcp_server_channel_modify_signal,
+       mrcp_server_channel_remove_signal,
+       mrcp_server_message_signal
+};
+
+
+/* Resource engine interface */
+typedef enum {
+       RESOURCE_ENGINE_TASK_MSG_OPEN_CHANNEL,
+       RESOURCE_ENGINE_TASK_MSG_CLOSE_CHANNEL,
+       RESOURCE_ENGINE_TASK_MSG_MESSAGE
+} resource_engine_task_msg_type_e;
+
+typedef struct resource_engine_task_msg_data_t resource_engine_task_msg_data_t;
+struct resource_engine_task_msg_data_t {
+       mrcp_channel_t *channel;
+       apt_bool_t      status;
+       mrcp_message_t *mrcp_message;
+};
+
+static apt_bool_t mrcp_server_channel_open_signal(mrcp_engine_channel_t *channel, apt_bool_t status);
+static apt_bool_t mrcp_server_channel_close_signal(mrcp_engine_channel_t *channel);
+static apt_bool_t mrcp_server_channel_message_signal(mrcp_engine_channel_t *channel, mrcp_message_t *message);
+
+const mrcp_engine_channel_event_vtable_t engine_channel_vtable = {
+       mrcp_server_channel_open_signal,
+       mrcp_server_channel_close_signal,
+       mrcp_server_channel_message_signal
+};
+
+/* Task interface */
+static void mrcp_server_on_start_complete(apt_task_t *task);
+static void mrcp_server_on_terminate_complete(apt_task_t *task);
+static apt_bool_t mrcp_server_msg_process(apt_task_t *task, apt_task_msg_t *msg);
+
+static mrcp_session_t* mrcp_server_sig_agent_session_create(mrcp_sig_agent_t *signaling_agent);
+
+
+/** Create MRCP server instance */
+MRCP_DECLARE(mrcp_server_t*) mrcp_server_create(apt_dir_layout_t *dir_layout)
+{
+       mrcp_server_t *server;
+       apr_pool_t *pool;
+       apt_task_t *task;
+       apt_task_vtable_t *vtable;
+       apt_task_msg_pool_t *msg_pool;
+       
+       pool = apt_pool_create();
+       if(!pool) {
+               return NULL;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create "SERVER_TASK_NAME);
+       server = apr_palloc(pool,sizeof(mrcp_server_t));
+       server->pool = pool;
+       server->dir_layout = dir_layout;
+       server->resource_factory = NULL;
+       server->resource_engine_table = NULL;
+       server->media_engine_table = NULL;
+       server->rtp_factory_table = NULL;
+       server->sig_agent_table = NULL;
+       server->cnt_agent_table = NULL;
+       server->profile_table = NULL;
+       server->plugin_table = NULL;
+       server->session_table = NULL;
+       server->connection_msg_pool = NULL;
+       server->resource_engine_msg_pool = NULL;
+
+       msg_pool = apt_task_msg_pool_create_dynamic(0,pool);
+
+       server->task = apt_consumer_task_create(server,msg_pool,pool);
+       if(!server->task) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Server Task");
+               return NULL;
+       }
+       task = apt_consumer_task_base_get(server->task);
+       apt_task_name_set(task,SERVER_TASK_NAME);
+       vtable = apt_task_vtable_get(task);
+       if(vtable) {
+               vtable->process_msg = mrcp_server_msg_process;
+               vtable->on_start_complete = mrcp_server_on_start_complete;
+               vtable->on_terminate_complete = mrcp_server_on_terminate_complete;
+       }
+
+       server->resource_engine_table = apr_hash_make(server->pool);
+       server->media_engine_table = apr_hash_make(server->pool);
+       server->rtp_factory_table = apr_hash_make(server->pool);
+       server->sig_agent_table = apr_hash_make(server->pool);
+       server->cnt_agent_table = apr_hash_make(server->pool);
+
+       server->profile_table = apr_hash_make(server->pool);
+       server->plugin_table = apr_hash_make(server->pool);
+       
+       server->session_table = apr_hash_make(server->pool);
+       return server;
+}
+
+/** Start message processing loop */
+MRCP_DECLARE(apt_bool_t) mrcp_server_start(mrcp_server_t *server)
+{
+       apt_task_t *task;
+       if(!server || !server->task) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Invalid Server");
+               return FALSE;
+       }
+       server->start_time = apr_time_now();
+       task = apt_consumer_task_base_get(server->task);
+       if(apt_task_start(task) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Start Server Task");
+               return FALSE;
+       }
+       return TRUE;
+}
+
+/** Shutdown message processing loop */
+MRCP_DECLARE(apt_bool_t) mrcp_server_shutdown(mrcp_server_t *server)
+{
+       apt_task_t *task;
+       apr_time_t uptime;
+       if(!server || !server->task) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Invalid Server");
+               return FALSE;
+       }
+       task = apt_consumer_task_base_get(server->task);
+       if(apt_task_terminate(task,TRUE) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Shutdown Server Task");
+               return FALSE;
+       }
+       server->session_table = NULL;
+       uptime = apr_time_now() - server->start_time;
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Server Uptime [%d sec]", apr_time_sec(uptime));
+       return TRUE;
+}
+
+/** Destroy MRCP server */
+MRCP_DECLARE(apt_bool_t) mrcp_server_destroy(mrcp_server_t *server)
+{
+       apt_task_t *task;
+       if(!server || !server->task) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Invalid Server");
+               return FALSE;
+       }
+       task = apt_consumer_task_base_get(server->task);
+       apt_task_destroy(task);
+
+       apr_pool_destroy(server->pool);
+       return TRUE;
+}
+
+/** Register MRCP resource factory */
+MRCP_DECLARE(apt_bool_t) mrcp_server_resource_factory_register(mrcp_server_t *server, mrcp_resource_factory_t *resource_factory)
+{
+       if(!resource_factory) {
+               return FALSE;
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Resource Factory");
+       server->resource_factory = resource_factory;
+       return TRUE;
+}
+
+/** Register MRCP resource engine */
+MRCP_DECLARE(apt_bool_t) mrcp_server_resource_engine_register(mrcp_server_t *server, mrcp_resource_engine_t *engine, const char *name)
+{
+       if(!engine || !name) {
+               return FALSE;
+       }
+       if(!server->resource_engine_msg_pool) {
+               server->resource_engine_msg_pool = apt_task_msg_pool_create_dynamic(sizeof(resource_engine_task_msg_data_t),server->pool);
+       }
+       engine->codec_manager = server->codec_manager;
+       engine->dir_layout = server->dir_layout;
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Resource Engine [%s]",name);
+       apr_hash_set(server->resource_engine_table,name,APR_HASH_KEY_STRING,engine);
+       return TRUE;
+}
+
+/** Get resource engine by name */
+MRCP_DECLARE(mrcp_resource_engine_t*) mrcp_server_resource_engine_get(mrcp_server_t *server, const char *name)
+{
+       return apr_hash_get(server->resource_engine_table,name,APR_HASH_KEY_STRING);
+}
+
+/** Register codec manager */
+MRCP_DECLARE(apt_bool_t) mrcp_server_codec_manager_register(mrcp_server_t *server, mpf_codec_manager_t *codec_manager)
+{
+       if(!codec_manager) {
+               return FALSE;
+       }
+       server->codec_manager = codec_manager;
+       return TRUE;
+}
+
+/** Get registered codec manager */
+MRCP_DECLARE(const mpf_codec_manager_t*) mrcp_server_codec_manager_get(mrcp_server_t *server)
+{
+       return server->codec_manager;
+}
+
+/** Register media engine */
+MRCP_DECLARE(apt_bool_t) mrcp_server_media_engine_register(mrcp_server_t *server, mpf_engine_t *media_engine, const char *name)
+{
+       if(!media_engine || !name) {
+               return FALSE;
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Media Engine [%s]",name);
+       mpf_engine_codec_manager_register(media_engine,server->codec_manager);
+       apr_hash_set(server->media_engine_table,name,APR_HASH_KEY_STRING,media_engine);
+       mpf_engine_task_msg_type_set(media_engine,MRCP_SERVER_MEDIA_TASK_MSG);
+       if(server->task) {
+               apt_task_t *media_task = mpf_task_get(media_engine);
+               apt_task_t *task = apt_consumer_task_base_get(server->task);
+               apt_task_add(task,media_task);
+       }
+       return TRUE;
+}
+
+/** Get media engine by name */
+MRCP_DECLARE(mpf_engine_t*) mrcp_server_media_engine_get(mrcp_server_t *server, const char *name)
+{
+       return apr_hash_get(server->media_engine_table,name,APR_HASH_KEY_STRING);
+}
+
+/** Register RTP termination factory */
+MRCP_DECLARE(apt_bool_t) mrcp_server_rtp_factory_register(mrcp_server_t *server, mpf_termination_factory_t *rtp_termination_factory, const char *name)
+{
+       if(!rtp_termination_factory || !name) {
+               return FALSE;
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register RTP Termination Factory [%s]",name);
+       apr_hash_set(server->rtp_factory_table,name,APR_HASH_KEY_STRING,rtp_termination_factory);
+       return TRUE;
+}
+
+/** Get RTP termination factory by name */
+MRCP_DECLARE(mpf_termination_factory_t*) mrcp_server_rtp_factory_get(mrcp_server_t *server, const char *name)
+{
+       return apr_hash_get(server->rtp_factory_table,name,APR_HASH_KEY_STRING);
+}
+
+/** Register MRCP signaling agent */
+MRCP_DECLARE(apt_bool_t) mrcp_server_signaling_agent_register(mrcp_server_t *server, mrcp_sig_agent_t *signaling_agent, const char *name)
+{
+       if(!signaling_agent || !name) {
+               return FALSE;
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Signaling Agent [%s]",name);
+       signaling_agent->parent = server;
+       signaling_agent->resource_factory = server->resource_factory;
+       signaling_agent->create_server_session = mrcp_server_sig_agent_session_create;
+       signaling_agent->msg_pool = apt_task_msg_pool_create_dynamic(sizeof(mrcp_signaling_message_t*),server->pool);
+       apr_hash_set(server->sig_agent_table,name,APR_HASH_KEY_STRING,signaling_agent);
+       if(server->task) {
+               apt_task_t *task = apt_consumer_task_base_get(server->task);
+               apt_task_add(task,signaling_agent->task);
+       }
+       return TRUE;
+}
+
+/** Get signaling agent by name */
+MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_server_signaling_agent_get(mrcp_server_t *server, const char *name)
+{
+       return apr_hash_get(server->sig_agent_table,name,APR_HASH_KEY_STRING);
+}
+
+/** Register MRCP connection agent (MRCPv2 only) */
+MRCP_DECLARE(apt_bool_t) mrcp_server_connection_agent_register(mrcp_server_t *server, mrcp_connection_agent_t *connection_agent, const char *name)
+{
+       if(!connection_agent || !name) {
+               return FALSE;
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Connection Agent [%s]",name);
+       mrcp_server_connection_resource_factory_set(connection_agent,server->resource_factory);
+       mrcp_server_connection_agent_handler_set(connection_agent,server,&connection_method_vtable);
+       server->connection_msg_pool = apt_task_msg_pool_create_dynamic(sizeof(connection_agent_task_msg_data_t),server->pool);
+       apr_hash_set(server->cnt_agent_table,name,APR_HASH_KEY_STRING,connection_agent);
+       if(server->task) {
+               apt_task_t *task = apt_consumer_task_base_get(server->task);
+               apt_task_t *connection_task = mrcp_server_connection_agent_task_get(connection_agent);
+               apt_task_add(task,connection_task);
+       }
+       return TRUE;
+}
+
+/** Get connection agent by name */
+MRCP_DECLARE(mrcp_connection_agent_t*) mrcp_server_connection_agent_get(mrcp_server_t *server, const char *name)
+{
+       return apr_hash_get(server->cnt_agent_table,name,APR_HASH_KEY_STRING);
+}
+
+/** Create MRCP profile */
+MRCP_DECLARE(mrcp_profile_t*) mrcp_server_profile_create(
+                                                                       mrcp_resource_factory_t *resource_factory,
+                                                                       mrcp_sig_agent_t *signaling_agent,
+                                                                       mrcp_connection_agent_t *connection_agent,
+                                                                       mpf_engine_t *media_engine,
+                                                                       mpf_termination_factory_t *rtp_factory,
+                                                                       apr_pool_t *pool)
+{
+       mrcp_profile_t *profile = apr_palloc(pool,sizeof(mrcp_profile_t));
+       profile->resource_factory = resource_factory;
+       profile->engine_table = NULL;
+       profile->media_engine = media_engine;
+       profile->rtp_termination_factory = rtp_factory;
+       profile->signaling_agent = signaling_agent;
+       profile->connection_agent = connection_agent;
+       return profile;
+}
+
+static apt_bool_t mrcp_server_engine_table_make(mrcp_server_t *server, mrcp_profile_t *profile, apr_table_t *plugin_map)
+{
+       int i;
+       const apt_str_t *resource_name;
+       const char *plugin_name = NULL;
+       mrcp_resource_engine_t *resource_engine;
+
+       profile->engine_table = apr_hash_make(server->pool);
+       for(i=0; i<MRCP_RESOURCE_TYPE_COUNT; i++) {
+               resource_name = mrcp_resource_name_get(server->resource_factory,i);
+               if(!resource_name) continue;
+               
+               resource_engine = NULL;
+               /* first, try to find engine by name specified in plugin map (if available) */
+               if(plugin_map) {
+                       plugin_name = apr_table_get(plugin_map,resource_name->buf);
+                       if(plugin_name) {
+                               resource_engine = mrcp_server_resource_engine_get(server,plugin_name);
+                       }
+               }
+
+               /* next, if no engine found, try to find the first available engine */
+               if(!resource_engine) {
+                       mrcp_resource_engine_t *cur_engine;
+                       void *val;
+                       apr_hash_index_t *it = apr_hash_first(server->pool,server->resource_engine_table);
+                       /* walk through the list of engines */
+                       for(; it; it = apr_hash_next(it)) {
+                               apr_hash_this(it,(void*)&plugin_name,NULL,&val);
+                               cur_engine = val;
+                               if(cur_engine && cur_engine->resource_id == (mrcp_resource_id)i) {
+                                       resource_engine = cur_engine;
+                                       break;
+                               }
+                       }
+               }
+               
+               if(resource_engine) {
+                       if(plugin_name) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Assign Resource Engine [%s] [%s]",resource_name->buf,plugin_name);
+                       }
+                       apr_hash_set(profile->engine_table,resource_name->buf,resource_name->length,resource_engine);
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Resource Engine Available [%s]",resource_name->buf);
+               }
+       }
+
+       return TRUE;
+}
+
+/** Register MRCP profile */
+MRCP_DECLARE(apt_bool_t) mrcp_server_profile_register(
+                                                                       mrcp_server_t *server,
+                                                                       mrcp_profile_t *profile,
+                                                                       apr_table_t *plugin_map,
+                                                                       const char *name)
+{
+       if(!profile || !name) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Register Profile: no name");
+               return FALSE;
+       }
+       if(!profile->resource_factory) {
+               profile->resource_factory = server->resource_factory;
+       }
+       mrcp_server_engine_table_make(server,profile,plugin_map);
+       
+       if(!profile->signaling_agent) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Register Profile [%s]: missing signaling agent",name);
+               return FALSE;
+       }
+       if(profile->signaling_agent->mrcp_version == MRCP_VERSION_2 &&
+               !profile->connection_agent) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Register Profile [%s]: missing connection agent",name);
+               return FALSE;
+       }
+       if(!profile->media_engine) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Register Profile [%s]: missing media engine",name);
+               return FALSE;
+       }
+       if(!profile->rtp_termination_factory) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Register Profile [%s]: missing RTP factory",name);
+               return FALSE;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Profile [%s]",name);
+       apr_hash_set(server->profile_table,name,APR_HASH_KEY_STRING,profile);
+       return TRUE;
+}
+
+/** Get profile by name */
+MRCP_DECLARE(mrcp_profile_t*) mrcp_server_profile_get(mrcp_server_t *server, const char *name)
+{
+       return apr_hash_get(server->profile_table,name,APR_HASH_KEY_STRING);
+}
+
+/** Register resource engine plugin */
+MRCP_DECLARE(apt_bool_t) mrcp_server_plugin_register(mrcp_server_t *server, const char *path, const char *name)
+{
+       apt_bool_t status = FALSE;
+       apr_dso_handle_t *plugin = NULL;
+       apr_dso_handle_sym_t func_handle = NULL;
+       mrcp_plugin_creator_f plugin_creator = NULL;
+       if(!path || !name) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Register Plugin: no name");
+               return FALSE;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Plugin [%s] [%s]",path,name);
+       if(apr_dso_load(&plugin,path,server->pool) == APR_SUCCESS) {
+               if(apr_dso_sym(&func_handle,plugin,MRCP_PLUGIN_ENGINE_SYM_NAME) == APR_SUCCESS) {
+                       if(func_handle) {
+                               plugin_creator = (mrcp_plugin_creator_f)(intptr_t)func_handle;
+                       }
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Load DSO Symbol: "MRCP_PLUGIN_ENGINE_SYM_NAME);
+                       apr_dso_unload(plugin);
+                       return FALSE;
+               }
+               
+               if(apr_dso_sym(&func_handle,plugin,MRCP_PLUGIN_LOGGER_SYM_NAME) == APR_SUCCESS) {
+                       if(func_handle) {
+                               apt_logger_t *logger = apt_log_instance_get();
+                               mrcp_plugin_log_accessor_f log_accessor;
+                               log_accessor = (mrcp_plugin_log_accessor_f)(intptr_t)func_handle;
+                               log_accessor(logger);
+                       }
+               }
+       }
+       else {
+               char derr[512] = "";
+               apr_dso_error(plugin,derr,sizeof(derr));
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Load DSO: %s", derr);
+               return FALSE;
+       }
+
+       if(plugin_creator) {
+               mrcp_resource_engine_t *engine = plugin_creator(server->pool);
+               if(engine) {
+                       if(mrcp_plugin_version_check(&engine->plugin_version)) {
+                               status = TRUE;
+                               mrcp_server_resource_engine_register(server,engine,name);
+                               apr_hash_set(server->plugin_table,name,APR_HASH_KEY_STRING,plugin);
+                       }
+                       else {
+                               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Incompatible Plugin Version [%d.%d.%d] < ["PLUGIN_VERSION_STRING"]",
+                                       engine->plugin_version.major,
+                                       engine->plugin_version.minor,
+                                       engine->plugin_version.patch);
+                       }
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Resource Engine");
+               }
+       }
+       else {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Entry Point Found for Plugin");
+       }
+
+       if(status == FALSE) {
+               apr_dso_unload(plugin);
+       }
+       return status;
+}
+
+MRCP_DECLARE(apr_pool_t*) mrcp_server_memory_pool_get(mrcp_server_t *server)
+{
+       return server->pool;
+}
+
+void mrcp_server_session_add(mrcp_server_session_t *session)
+{
+       if(session->base.id.buf) {
+               apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Add Session "APT_SID_FMT,session->base.id.buf);
+               apr_hash_set(session->server->session_table,session->base.id.buf,session->base.id.length,session);
+       }
+}
+
+void mrcp_server_session_remove(mrcp_server_session_t *session)
+{
+       if(session->base.id.buf) {
+               apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Remove Session "APT_SID_FMT,session->base.id.buf);
+               apr_hash_set(session->server->session_table,session->base.id.buf,session->base.id.length,NULL);
+       }
+}
+
+static APR_INLINE mrcp_server_session_t* mrcp_server_session_find(mrcp_server_t *server, const apt_str_t *session_id)
+{
+       return apr_hash_get(server->session_table,session_id->buf,session_id->length);
+}
+
+static void mrcp_server_on_start_complete(apt_task_t *task)
+{
+       apt_consumer_task_t *consumer_task = apt_task_object_get(task);
+       mrcp_server_t *server = apt_consumer_task_object_get(consumer_task);
+       mrcp_resource_engine_t *resource_engine;
+       apr_hash_index_t *it;
+       void *val;
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open Resource Engines");
+       it = apr_hash_first(server->pool,server->resource_engine_table);
+       for(; it; it = apr_hash_next(it)) {
+               apr_hash_this(it,NULL,NULL,&val);
+               resource_engine = val;
+               if(resource_engine) {
+                       mrcp_resource_engine_open(resource_engine);
+               }
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,SERVER_TASK_NAME" Started");
+}
+
+static void mrcp_server_on_terminate_complete(apt_task_t *task)
+{
+       apt_consumer_task_t *consumer_task = apt_task_object_get(task);
+       mrcp_server_t *server = apt_consumer_task_object_get(consumer_task);
+       mrcp_resource_engine_t *resource_engine;
+       apr_dso_handle_t *plugin;
+       apr_hash_index_t *it;
+       void *val;
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close Resource Engines");
+       it=apr_hash_first(server->pool,server->resource_engine_table);
+       for(; it; it = apr_hash_next(it)) {
+               apr_hash_this(it,NULL,NULL,&val);
+               resource_engine = val;
+               if(resource_engine) {
+                       mrcp_resource_engine_close(resource_engine);
+               }
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unload Plugins");
+       it=apr_hash_first(server->pool,server->plugin_table);
+       for(; it; it = apr_hash_next(it)) {
+               apr_hash_this(it,NULL,NULL,&val);
+               plugin = val;
+               if(plugin) {
+                       apr_dso_unload(plugin);
+               }
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,SERVER_TASK_NAME" Terminated");
+}
+
+static apt_bool_t mrcp_server_msg_process(apt_task_t *task, apt_task_msg_t *msg)
+{
+       switch(msg->type) {
+               case MRCP_SERVER_SIGNALING_TASK_MSG:
+               {
+                       mrcp_signaling_message_t **signaling_message = (mrcp_signaling_message_t**) msg->data;
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Receive Signaling Task Message [%d]", (*signaling_message)->type);
+                       mrcp_server_signaling_message_process(*signaling_message);
+                       break;
+               }
+               case MRCP_SERVER_CONNECTION_TASK_MSG:
+               {
+                       const connection_agent_task_msg_data_t *connection_message = (const connection_agent_task_msg_data_t*)msg->data;
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Receive Connection Task Message [%d]", msg->sub_type);
+                       switch(msg->sub_type) {
+                               case CONNECTION_AGENT_TASK_MSG_ADD_CHANNEL:
+                               {
+                                       mrcp_server_on_channel_modify(connection_message->channel,connection_message->descriptor,connection_message->status);
+                                       break;
+                               }
+                               case CONNECTION_AGENT_TASK_MSG_MODIFY_CHANNEL:
+                               {
+                                       mrcp_server_on_channel_modify(connection_message->channel,connection_message->descriptor,connection_message->status);
+                                       break;
+                               }
+                               case CONNECTION_AGENT_TASK_MSG_REMOVE_CHANNEL:
+                               {
+                                       mrcp_server_on_channel_remove(connection_message->channel,connection_message->status);
+                                       break;
+                               }
+                               case CONNECTION_AGENT_TASK_MSG_RECEIVE_MESSAGE:
+                               {
+                                       mrcp_server_on_channel_message(connection_message->channel, connection_message->message);
+                                       break;
+                               }
+                               default:
+                                       break;
+                       }
+                       break;
+               }
+               case MRCP_SERVER_RESOURCE_ENGINE_TASK_MSG:
+               {
+                       resource_engine_task_msg_data_t *data = (resource_engine_task_msg_data_t*)msg->data;
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Receive Resource Engine Task Message [%d]", msg->sub_type);
+                       switch(msg->sub_type) {
+                               case RESOURCE_ENGINE_TASK_MSG_OPEN_CHANNEL:
+                                       mrcp_server_on_engine_channel_open(data->channel,data->status);
+                                       break;
+                               case RESOURCE_ENGINE_TASK_MSG_CLOSE_CHANNEL:
+                                       mrcp_server_on_engine_channel_close(data->channel);
+                                       break;
+                               case RESOURCE_ENGINE_TASK_MSG_MESSAGE:
+                                       mrcp_server_on_engine_channel_message(data->channel,data->mrcp_message);
+                                       break;
+                               default:
+                                       break;
+                       }
+                       break;
+               }
+               case MRCP_SERVER_MEDIA_TASK_MSG:
+               {
+                       mpf_message_t *mpf_message = (mpf_message_t*) msg->data;
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Receive Media Task Message [%d]", mpf_message->command_id);
+                       mrcp_server_mpf_message_process(mpf_message);
+                       break;
+               }
+               default:
+               {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Receive Unknown Task Message [%d]", msg->type);
+                       break;
+               }
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_server_signaling_task_msg_signal(mrcp_signaling_message_type_e type, mrcp_session_t *session, mrcp_session_descriptor_t *descriptor, mrcp_message_t *message)
+{
+       mrcp_signaling_message_t *signaling_message;
+       apt_task_msg_t *task_msg = apt_task_msg_acquire(session->signaling_agent->msg_pool);
+       mrcp_signaling_message_t **slot = ((mrcp_signaling_message_t**)task_msg->data);
+       task_msg->type = MRCP_SERVER_SIGNALING_TASK_MSG;
+       task_msg->sub_type = type;
+       
+       signaling_message = apr_palloc(session->pool,sizeof(mrcp_signaling_message_t));
+       signaling_message->type = type;
+       signaling_message->session = (mrcp_server_session_t*)session;
+       signaling_message->descriptor = descriptor;
+       signaling_message->channel = NULL;
+       signaling_message->message = message;
+       *slot = signaling_message;
+       
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Signal Signaling Task Message");
+       return apt_task_msg_parent_signal(session->signaling_agent->task,task_msg);
+}
+
+static apt_bool_t mrcp_server_connection_task_msg_signal(
+                                                       connection_agent_task_msg_type_e type,
+                                                       mrcp_connection_agent_t         *agent,
+                                                       mrcp_control_channel_t          *channel,
+                                                       mrcp_control_descriptor_t       *descriptor,
+                                                       mrcp_message_t                  *message,
+                                                       apt_bool_t                       status)
+{
+       mrcp_server_t *server = mrcp_server_connection_agent_object_get(agent);
+       apt_task_t *task = apt_consumer_task_base_get(server->task);
+       connection_agent_task_msg_data_t *data;
+       apt_task_msg_t *task_msg = apt_task_msg_acquire(server->connection_msg_pool);
+       task_msg->type = MRCP_SERVER_CONNECTION_TASK_MSG;
+       task_msg->sub_type = type;
+       data = (connection_agent_task_msg_data_t*) task_msg->data;
+       data->channel = channel ? channel->obj : NULL;
+       data->descriptor = descriptor;
+       data->message = message;
+       data->status = status;
+
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Signal Connection Task Message");
+       return apt_task_msg_signal(task,task_msg);
+}
+
+static apt_bool_t mrcp_server_engine_task_msg_signal(
+                                                       resource_engine_task_msg_type_e  type,
+                                                       mrcp_engine_channel_t           *engine_channel,
+                                                       apt_bool_t                       status,
+                                                       mrcp_message_t                  *message)
+{
+       mrcp_channel_t *channel = engine_channel->event_obj;
+       mrcp_session_t *session = mrcp_server_channel_session_get(channel);
+       mrcp_server_t *server = session->signaling_agent->parent;
+       apt_task_t *task = apt_consumer_task_base_get(server->task);
+       resource_engine_task_msg_data_t *data;
+       apt_task_msg_t *task_msg = apt_task_msg_acquire(server->resource_engine_msg_pool);
+       task_msg->type = MRCP_SERVER_RESOURCE_ENGINE_TASK_MSG;
+       task_msg->sub_type = type;
+       data = (resource_engine_task_msg_data_t*) task_msg->data;
+       data->channel = channel;
+       data->status = status;
+       data->mrcp_message = message;
+
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Signal Resource Engine Task Message");
+       return apt_task_msg_signal(task,task_msg);
+}
+
+static mrcp_profile_t* mrcp_server_profile_get_by_agent(mrcp_server_t *server, mrcp_server_session_t *session, mrcp_sig_agent_t *signaling_agent)
+{
+       mrcp_profile_t *profile;
+       apr_hash_index_t *it;
+       void *val;
+       const void *key;
+       const char *name;
+       it = apr_hash_first(session->base.pool,server->profile_table);
+       for(; it; it = apr_hash_next(it)) {
+               apr_hash_this(it,&key,NULL,&val);
+               profile = val;
+               name = key;
+               if(profile && name && profile->signaling_agent == signaling_agent) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Found Profile [%s]",name);
+                       return profile;
+               }
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot Find Profile by Agent "APT_SID_FMT,session->base.id.buf);
+       return NULL;
+}
+
+static mrcp_session_t* mrcp_server_sig_agent_session_create(mrcp_sig_agent_t *signaling_agent)
+{
+       mrcp_server_t *server = signaling_agent->parent;
+       mrcp_server_session_t *session = mrcp_server_session_create();
+       session->server = server;
+       session->profile = mrcp_server_profile_get_by_agent(server,session,signaling_agent);
+       if(!session->profile) {
+               mrcp_session_destroy(&session->base);
+               return NULL;
+       }
+       session->base.signaling_agent = signaling_agent;
+       session->base.request_vtable = &session_request_vtable;
+       return &session->base;
+}
+
+static apt_bool_t mrcp_server_offer_signal(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor)
+{
+       return mrcp_server_signaling_task_msg_signal(SIGNALING_MESSAGE_OFFER,session,descriptor,NULL);
+}
+
+static apt_bool_t mrcp_server_terminate_signal(mrcp_session_t *session)
+{
+       return mrcp_server_signaling_task_msg_signal(SIGNALING_MESSAGE_TERMINATE,session,NULL,NULL);
+}
+
+static apt_bool_t mrcp_server_control_signal(mrcp_session_t *session, mrcp_message_t *message)
+{
+       return mrcp_server_signaling_task_msg_signal(SIGNALING_MESSAGE_CONTROL,session,NULL,message);
+}
+
+static apt_bool_t mrcp_server_channel_add_signal(mrcp_control_channel_t *channel, mrcp_control_descriptor_t *descriptor, apt_bool_t status)
+{
+       mrcp_connection_agent_t *agent = channel->agent;
+       return mrcp_server_connection_task_msg_signal(
+                                                               CONNECTION_AGENT_TASK_MSG_ADD_CHANNEL,
+                                                               agent,
+                                                               channel,
+                                                               descriptor,
+                                                               NULL,
+                                                               status);
+}
+
+static apt_bool_t mrcp_server_channel_modify_signal(mrcp_control_channel_t *channel, mrcp_control_descriptor_t *descriptor, apt_bool_t status)
+{
+       mrcp_connection_agent_t *agent = channel->agent;
+       return mrcp_server_connection_task_msg_signal(
+                                                               CONNECTION_AGENT_TASK_MSG_MODIFY_CHANNEL,
+                                                               agent,
+                                                               channel,
+                                                               descriptor,
+                                                               NULL,
+                                                               status);
+}
+
+static apt_bool_t mrcp_server_channel_remove_signal(mrcp_control_channel_t *channel, apt_bool_t status)
+{
+       mrcp_connection_agent_t *agent = channel->agent;
+       return mrcp_server_connection_task_msg_signal(
+                                                               CONNECTION_AGENT_TASK_MSG_REMOVE_CHANNEL,
+                                                               agent,
+                                                               channel,
+                                                               NULL,
+                                                               NULL,
+                                                               status);
+}
+
+static apt_bool_t mrcp_server_message_signal(mrcp_control_channel_t *channel, mrcp_message_t *message)
+{
+       mrcp_connection_agent_t *agent = channel->agent;
+       return mrcp_server_connection_task_msg_signal(
+                                                               CONNECTION_AGENT_TASK_MSG_RECEIVE_MESSAGE,
+                                                               agent,
+                                                               channel,
+                                                               NULL,
+                                                               message,
+                                                               TRUE);
+}
+
+static apt_bool_t mrcp_server_channel_open_signal(mrcp_engine_channel_t *channel, apt_bool_t status)
+{
+       return mrcp_server_engine_task_msg_signal(
+                                                               RESOURCE_ENGINE_TASK_MSG_OPEN_CHANNEL,
+                                                               channel,
+                                                               status,
+                                                               NULL);
+}
+
+static apt_bool_t mrcp_server_channel_close_signal(mrcp_engine_channel_t *channel)
+{
+       return mrcp_server_engine_task_msg_signal(
+                                                               RESOURCE_ENGINE_TASK_MSG_CLOSE_CHANNEL,
+                                                               channel,
+                                                               TRUE,
+                                                               NULL);
+}
+
+static apt_bool_t mrcp_server_channel_message_signal(mrcp_engine_channel_t *channel, mrcp_message_t *message)
+{
+       return mrcp_server_engine_task_msg_signal(
+                                                               RESOURCE_ENGINE_TASK_MSG_MESSAGE,
+                                                               channel,
+                                                               TRUE,
+                                                               message);
+}
diff --git a/libs/unimrcp/libs/mrcp-server/src/mrcp_server_session.c b/libs/unimrcp/libs/mrcp-server/src/mrcp_server_session.c
new file mode 100644 (file)
index 0000000..26fbe95
--- /dev/null
@@ -0,0 +1,934 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mrcp_server.h"
+#include "mrcp_server_session.h"
+#include "mrcp_resource.h"
+#include "mrcp_resource_factory.h"
+#include "mrcp_resource_engine.h"
+#include "mrcp_sig_agent.h"
+#include "mrcp_server_connection.h"
+#include "mrcp_session_descriptor.h"
+#include "mrcp_control_descriptor.h"
+#include "mrcp_state_machine.h"
+#include "mrcp_message.h"
+#include "mpf_user.h"
+#include "mpf_termination.h"
+#include "mpf_engine.h"
+#include "apt_consumer_task.h"
+#include "apt_log.h"
+
+#define MRCP_SESSION_ID_HEX_STRING_LENGTH 16
+
+struct mrcp_channel_t {
+       /** Memory pool */
+       apr_pool_t             *pool;
+       /** MRCP resource */
+       apt_str_t               resource_name;
+       /** MRCP resource */
+       mrcp_resource_t        *resource;
+       /** MRCP session entire channel belongs to */
+       mrcp_session_t         *session;
+       /** MRCP control channel */
+       mrcp_control_channel_t *control_channel;
+       /** MRCP resource engine channel */
+       mrcp_engine_channel_t  *engine_channel;
+       /** MRCP resource state machine  */
+       mrcp_state_machine_t   *state_machine;
+       /** media descriptor id */
+       apr_size_t              id;
+       /** waiting state of control media */
+       apt_bool_t              waiting_for_channel;
+       /** waiting state of media termination */
+       apt_bool_t              waiting_for_termination;
+};
+
+typedef struct mrcp_termination_slot_t mrcp_termination_slot_t;
+
+struct mrcp_termination_slot_t {
+       /** RTP termination */
+       mpf_termination_t *termination;
+       /** media descriptor id */
+       apr_size_t              id;
+       /** waiting state */
+       apt_bool_t         waiting;
+};
+
+extern const mrcp_engine_channel_event_vtable_t engine_channel_vtable;
+
+void mrcp_server_session_add(mrcp_server_session_t *session);
+void mrcp_server_session_remove(mrcp_server_session_t *session);
+
+static apt_bool_t mrcp_server_signaling_message_dispatch(mrcp_server_session_t *session, mrcp_signaling_message_t *signaling_message);
+
+static apt_bool_t mrcp_server_resource_offer_process(mrcp_server_session_t *session, mrcp_session_descriptor_t *descriptor);
+static apt_bool_t mrcp_server_control_media_offer_process(mrcp_server_session_t *session, mrcp_session_descriptor_t *descriptor);
+static apt_bool_t mrcp_server_av_media_offer_process(mrcp_server_session_t *session, mrcp_session_descriptor_t *descriptor);
+
+static apt_bool_t mrcp_server_on_termination_modify(mrcp_server_session_t *session, const mpf_message_t *mpf_message);
+static apt_bool_t mrcp_server_on_termination_subtract(mrcp_server_session_t *session, const mpf_message_t *mpf_message);
+
+static apt_bool_t mrcp_server_session_answer_send(mrcp_server_session_t *session);
+static apt_bool_t mrcp_server_session_terminate_send(mrcp_server_session_t *session);
+
+static mrcp_channel_t* mrcp_server_channel_find(mrcp_server_session_t *session, const apt_str_t *resource_name);
+
+static apt_bool_t mrcp_server_mpf_request_send(
+                                               mrcp_server_session_t *session, 
+                                               mpf_command_type_e command_id, 
+                                               mpf_context_t *context, 
+                                               mpf_termination_t *termination, 
+                                               void *descriptor);
+
+
+mrcp_server_session_t* mrcp_server_session_create()
+{
+       mrcp_server_session_t *session = (mrcp_server_session_t*) mrcp_session_create(sizeof(mrcp_server_session_t)-sizeof(mrcp_session_t));
+       session->context = NULL;
+       session->terminations = apr_array_make(session->base.pool,2,sizeof(mrcp_termination_slot_t));
+       session->channels = apr_array_make(session->base.pool,2,sizeof(mrcp_channel_t*));
+       session->active_request = NULL;
+       session->request_queue = apt_list_create(session->base.pool);
+       session->offer = NULL;
+       session->answer = NULL;
+       session->answer_flag_count = 0;
+       session->terminate_flag_count = 0;
+       return session;
+}
+
+static mrcp_engine_channel_t* mrcp_server_engine_channel_create(mrcp_server_session_t *session, const apt_str_t *resource_name)
+{
+       mrcp_resource_engine_t *resource_engine = apr_hash_get(
+                                                                                               session->profile->engine_table,
+                                                                                               resource_name->buf,
+                                                                                               resource_name->length);
+       if(!resource_engine) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Find Resource Engine [%s]",resource_name->buf);
+               return NULL;
+       }
+
+       return resource_engine->method_vtable->create_channel(resource_engine,session->base.pool);
+}
+
+static apt_bool_t mrcp_server_message_dispatch(mrcp_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       mrcp_channel_t *channel = state_machine->obj;
+
+       if(message->start_line.message_type == MRCP_MESSAGE_TYPE_REQUEST) {
+               /* send request message to resource engine for actual processing */
+               if(channel->engine_channel) {
+                       mrcp_engine_channel_request_process(channel->engine_channel,message);
+               }
+       }
+       else if(message->start_line.message_type == MRCP_MESSAGE_TYPE_RESPONSE) {
+               mrcp_server_session_t *session = (mrcp_server_session_t*)channel->session;
+               /* send response message to client */
+               if(channel->control_channel) {
+                       /* MRCPv2 */
+                       mrcp_server_control_message_send(channel->control_channel,message);
+               }
+               else {
+                       /* MRCPv1 */
+                       mrcp_session_control_response(channel->session,message);
+               }
+
+               session->active_request = apt_list_pop_front(session->request_queue);
+               if(session->active_request) {
+                       mrcp_server_signaling_message_dispatch(session,session->active_request);
+               }
+       }
+       else { 
+               /* send event message to client */
+               if(channel->control_channel) {
+                       /* MRCPv2 */
+                       mrcp_server_control_message_send(channel->control_channel,message);
+               }
+               else {
+                       /* MRCPv1 */
+                       mrcp_session_control_response(channel->session,message);
+               }
+       }
+       return TRUE;
+}
+
+static mrcp_channel_t* mrcp_server_channel_create(mrcp_server_session_t *session, const apt_str_t *resource_name, apr_size_t id)
+{
+       mrcp_channel_t *channel;
+       apr_pool_t *pool = session->base.pool;
+
+       channel = apr_palloc(pool,sizeof(mrcp_channel_t));
+       channel->pool = pool;
+       channel->session = &session->base;
+       channel->resource = NULL;
+       channel->control_channel = NULL;
+       channel->state_machine = NULL;
+       channel->engine_channel = NULL;
+       channel->id = id;
+       channel->waiting_for_channel = FALSE;
+       channel->waiting_for_termination = FALSE;
+       apt_string_reset(&channel->resource_name);
+
+       if(resource_name && resource_name->buf) {
+               mrcp_resource_id resource_id;
+               mrcp_resource_t *resource;
+               mrcp_engine_channel_t *engine_channel;
+               channel->resource_name = *resource_name;
+               resource_id = mrcp_resource_id_find(
+                                                               session->profile->resource_factory,
+                                                               resource_name);
+               resource = mrcp_resource_get(session->profile->resource_factory,resource_id);
+               if(resource) {
+                       channel->resource = resource;
+                       if(session->base.signaling_agent->mrcp_version == MRCP_VERSION_2) {
+                               channel->control_channel = mrcp_server_control_channel_create(
+                                                                       session->profile->connection_agent,
+                                                                       channel,
+                                                                       pool);
+                       }
+                       channel->state_machine = resource->create_server_state_machine(
+                                                               channel,
+                                                               mrcp_server_message_dispatch,
+                                                               session->base.signaling_agent->mrcp_version,
+                                                               pool);
+
+                       engine_channel = mrcp_server_engine_channel_create(session,resource_name);
+                       if(engine_channel) {
+                               engine_channel->event_obj = channel;
+                               engine_channel->event_vtable = &engine_channel_vtable;
+                               channel->engine_channel = engine_channel;
+                       }
+                       else {
+                               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Resource Engine Channel [%s]",resource_name->buf);
+                               session->answer->status = MRCP_SESSION_STATUS_UNACCEPTABLE_RESOURCE;
+                       }
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Such Resource [%s]",resource_name->buf);
+                       session->answer->status = MRCP_SESSION_STATUS_NO_SUCH_RESOURCE;
+               }
+       }
+       else {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Invalid Resource Identifier");
+               session->answer->status = MRCP_SESSION_STATUS_NO_SUCH_RESOURCE;
+       }
+
+       return channel;
+}
+
+mrcp_session_t* mrcp_server_channel_session_get(mrcp_channel_t *channel)
+{
+       return channel->session;
+}
+
+apt_bool_t mrcp_server_signaling_message_process(mrcp_signaling_message_t *signaling_message)
+{
+       mrcp_server_session_t *session = signaling_message->session;
+       if(session->active_request) {
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Push Request to Queue");
+               apt_list_push_back(session->request_queue,signaling_message,session->base.pool);
+       }
+       else {
+               session->active_request = signaling_message;
+               mrcp_server_signaling_message_dispatch(session,signaling_message);
+       }
+       return TRUE;
+}
+
+apt_bool_t mrcp_server_on_channel_modify(mrcp_channel_t *channel, mrcp_control_descriptor_t *answer, apt_bool_t status)
+{
+       mrcp_server_session_t *session = (mrcp_server_session_t*)channel->session;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Control Channel Modify");
+       if(!answer) {
+               return FALSE;
+       }
+       if(!channel->waiting_for_channel) {
+               return FALSE;
+       }
+       channel->waiting_for_channel = FALSE;
+       answer->session_id = session->base.id;
+       mrcp_session_control_media_set(session->answer,channel->id,answer);
+       if(session->answer_flag_count) {
+               session->answer_flag_count--;
+               if(!session->answer_flag_count) {
+                       /* send answer to client */
+                       mrcp_server_session_answer_send(session);
+               }
+       }
+       return TRUE;
+}
+
+apt_bool_t mrcp_server_on_channel_remove(mrcp_channel_t *channel, apt_bool_t status)
+{
+       mrcp_server_session_t *session = (mrcp_server_session_t*)channel->session;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Control Channel Remove");
+       if(!channel->waiting_for_channel) {
+               return FALSE;
+       }
+       channel->waiting_for_channel = FALSE;
+       if(session->terminate_flag_count) {
+               session->terminate_flag_count--;
+               if(!session->terminate_flag_count) {
+                       mrcp_server_session_terminate_send(session);
+               }
+       }
+       return TRUE;
+}
+
+apt_bool_t mrcp_server_on_channel_message(mrcp_channel_t *channel, mrcp_message_t *message)
+{
+       mrcp_server_session_t *session = (mrcp_server_session_t*)channel->session;
+       mrcp_signaling_message_t *signaling_message;
+       signaling_message = apr_palloc(session->base.pool,sizeof(mrcp_signaling_message_t));
+       signaling_message->type = SIGNALING_MESSAGE_CONTROL;
+       signaling_message->session = session;
+       signaling_message->descriptor = NULL;
+       signaling_message->channel = channel;
+       signaling_message->message = message;
+       return mrcp_server_signaling_message_process(signaling_message);
+}
+
+apt_bool_t mrcp_server_on_engine_channel_open(mrcp_channel_t *channel, apt_bool_t status)
+{
+       mrcp_server_session_t *session = (mrcp_server_session_t*)channel->session;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Engine Channel Open [%s]", status == TRUE ? "OK" : "Failed");
+       if(status == FALSE) {
+               session->answer->status = MRCP_SESSION_STATUS_UNAVAILABLE_RESOURCE;
+       }
+       if(session->answer_flag_count) {
+               session->answer_flag_count--;
+               if(!session->answer_flag_count) {
+                       /* send answer to client */
+                       mrcp_server_session_answer_send(session);
+               }
+       }
+       return TRUE;
+}
+
+apt_bool_t mrcp_server_on_engine_channel_close(mrcp_channel_t *channel)
+{
+       mrcp_server_session_t *session = (mrcp_server_session_t*)channel->session;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Engine Channel Close");
+       if(session->terminate_flag_count) {
+               session->terminate_flag_count--;
+               if(!session->terminate_flag_count) {
+                       mrcp_server_session_terminate_send(session);
+               }
+       }
+       return TRUE;
+}
+
+apt_bool_t mrcp_server_on_engine_channel_message(mrcp_channel_t *channel, mrcp_message_t *message)
+{
+       if(!channel->state_machine) {
+               return FALSE;
+       }
+       /* update state machine */
+       return mrcp_state_machine_update(channel->state_machine,message);
+}
+
+
+apt_bool_t mrcp_server_mpf_message_process(mpf_message_t *mpf_message)
+{
+       mrcp_server_session_t *session = NULL;
+       if(mpf_message->context) {
+               session = mpf_context_object_get(mpf_message->context);
+       }
+       if(mpf_message->message_type == MPF_MESSAGE_TYPE_RESPONSE) {
+               switch(mpf_message->command_id) {
+                       case MPF_COMMAND_ADD:
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Termination Add");
+                               mrcp_server_on_termination_modify(session,mpf_message);
+                               break;
+                       case MPF_COMMAND_MODIFY:
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Termination Modify");
+                               mrcp_server_on_termination_modify(session,mpf_message);
+                               break;
+                       case MPF_COMMAND_SUBTRACT:
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Termination Subtract");
+                               mrcp_server_on_termination_subtract(session,mpf_message);
+                               break;
+                       default:
+                               break;
+               }
+       }
+       else if(mpf_message->message_type == MPF_MESSAGE_TYPE_EVENT) {
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process MPF Event");
+       }
+       return TRUE;
+}
+
+static mrcp_session_descriptor_t* mrcp_session_answer_create(mrcp_session_descriptor_t *offer, apr_pool_t *pool)
+{
+       int i;
+       void **control_slot;
+       mpf_rtp_media_descriptor_t **av_slot;
+       mrcp_session_descriptor_t *answer = apr_palloc(pool,sizeof(mrcp_session_descriptor_t));
+       apt_string_reset(&answer->origin);
+       apt_string_reset(&answer->ip);
+       apt_string_reset(&answer->ext_ip);
+       answer->resource_name = offer->resource_name;
+       answer->resource_state = offer->resource_state;
+       answer->status = offer->status;
+       answer->control_media_arr = apr_array_make(pool,offer->control_media_arr->nelts,sizeof(void*));
+       for(i=0; i<offer->control_media_arr->nelts; i++) {
+               control_slot = apr_array_push(answer->control_media_arr);
+               *control_slot = NULL;
+       }
+       answer->audio_media_arr = apr_array_make(pool,offer->audio_media_arr->nelts,sizeof(mpf_rtp_media_descriptor_t*));
+       for(i=0; i<offer->audio_media_arr->nelts; i++) {
+               av_slot = apr_array_push(answer->audio_media_arr);
+               *av_slot = NULL;
+       }
+       answer->video_media_arr = apr_array_make(pool,offer->video_media_arr->nelts,sizeof(mpf_rtp_media_descriptor_t*));
+       for(i=0; i<offer->video_media_arr->nelts; i++) {
+               av_slot = apr_array_push(answer->video_media_arr);
+               *av_slot = NULL;
+       }
+       return answer;
+}
+
+static apt_bool_t mrcp_server_session_offer_process(mrcp_server_session_t *session, mrcp_session_descriptor_t *descriptor)
+{
+       if(!session->context) {
+               /* initial offer received, generate session id and add to session's table */
+               if(!session->base.id.length) {
+                       apt_unique_id_generate(&session->base.id,MRCP_SESSION_ID_HEX_STRING_LENGTH,session->base.pool);
+               }
+               mrcp_server_session_add(session);
+
+               session->context = mpf_context_create(session,5,session->base.pool);
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive Offer "APT_SID_FMT" [c:%d a:%d v:%d]",
+               session->base.id.buf,
+               descriptor->control_media_arr->nelts,
+               descriptor->audio_media_arr->nelts,
+               descriptor->video_media_arr->nelts);
+
+       /* store received offer */
+       session->offer = descriptor;
+       session->answer = mrcp_session_answer_create(descriptor,session->base.pool);
+
+       if(session->base.signaling_agent->mrcp_version == MRCP_VERSION_1) {
+               if(mrcp_server_resource_offer_process(session,descriptor) == TRUE) {
+                       mrcp_server_av_media_offer_process(session,descriptor);
+               }
+               else {
+                       session->answer->resource_state = FALSE;
+               }
+       }
+       else {
+               mrcp_server_control_media_offer_process(session,descriptor);
+               mrcp_server_av_media_offer_process(session,descriptor);
+       }
+       
+       if(!session->answer_flag_count) {
+               /* send answer to client */
+               mrcp_server_session_answer_send(session);
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_server_session_terminate_process(mrcp_server_session_t *session)
+{
+       mrcp_channel_t *channel;
+       mrcp_termination_slot_t *slot;
+       int i;
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive Terminate Request "APT_SID_FMT,session->base.id.buf);
+       for(i=0; i<session->channels->nelts; i++) {
+               channel = ((mrcp_channel_t**)session->channels->elts)[i];
+               if(!channel) continue;
+
+               /* send remove channel request */
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Remove Control Channel [%d]",i);
+               if(channel->control_channel) {
+                       if(mrcp_server_control_channel_remove(channel->control_channel) == TRUE) {
+                               channel->waiting_for_channel = TRUE;
+                               session->terminate_flag_count++;
+                       }
+               }
+
+               if(channel->engine_channel) {
+                       mpf_termination_t *termination = channel->engine_channel->termination;
+                       /* send subtract termination request */
+                       if(termination) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Subtract Channel Termination");
+                               if(mrcp_server_mpf_request_send(session,MPF_COMMAND_SUBTRACT,session->context,termination,NULL) == TRUE) {
+                                       channel->waiting_for_termination = TRUE;
+                                       session->terminate_flag_count++;
+                               }
+                       }
+
+                       /* close resource engine channel */
+                       if(mrcp_engine_channel_close(channel->engine_channel) == TRUE) {
+                               session->terminate_flag_count++;
+                       }
+               }
+       }
+       for(i=0; i<session->terminations->nelts; i++) {
+               /* get existing termination */
+               slot = &((mrcp_termination_slot_t*)session->terminations->elts)[i];
+               if(!slot || !slot->termination) continue;
+
+               /* send subtract termination request */
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Subtract RTP Termination [%d]",i);
+               if(mrcp_server_mpf_request_send(session,MPF_COMMAND_SUBTRACT,session->context,slot->termination,NULL) == TRUE) {
+                       slot->waiting = TRUE;
+                       session->terminate_flag_count++;
+               }
+       }
+       mrcp_server_session_remove(session);
+
+       if(!session->terminate_flag_count) {
+               mrcp_server_session_terminate_send(session);
+       }
+
+       return TRUE;
+}
+
+static apt_bool_t mrcp_server_on_message_receive(mrcp_server_session_t *session, mrcp_channel_t *channel, mrcp_message_t *message)
+{
+       if(!channel) {
+               channel = mrcp_server_channel_find(session,&message->channel_id.resource_name);
+               if(!channel) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Such Channel");
+                       return FALSE;
+               }
+       }
+       if(!channel->resource || !channel->state_machine) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Resource");
+               return FALSE;
+       }
+
+       /* update state machine */
+       return mrcp_state_machine_update(channel->state_machine,message);
+}
+
+static apt_bool_t mrcp_server_signaling_message_dispatch(mrcp_server_session_t *session, mrcp_signaling_message_t *signaling_message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Dispatch Signaling Message [%d]",signaling_message->type);
+       switch(signaling_message->type) {
+               case SIGNALING_MESSAGE_OFFER:
+                       mrcp_server_session_offer_process(signaling_message->session,signaling_message->descriptor);
+                       break;
+               case SIGNALING_MESSAGE_CONTROL:
+                       mrcp_server_on_message_receive(signaling_message->session,signaling_message->channel,signaling_message->message);
+                       break;
+               case SIGNALING_MESSAGE_TERMINATE:
+                       mrcp_server_session_terminate_process(signaling_message->session);
+                       break;
+               default:
+                       break;
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_server_resource_offer_process(mrcp_server_session_t *session, mrcp_session_descriptor_t *descriptor)
+{
+       if(descriptor->resource_state == TRUE) {
+               /* setup */
+               mrcp_channel_t *channel;
+               mrcp_channel_t **slot;
+               int count = session->channels->nelts;
+               channel = mrcp_server_channel_find(session,&descriptor->resource_name);
+               if(channel) {
+                       /* channel already exists */
+                       return TRUE;
+               }
+               /* create new MRCP channel instance */
+               channel = mrcp_server_channel_create(session,&descriptor->resource_name,count);
+               if(!channel || !channel->resource) {
+                       return FALSE;
+               }
+               /* add to channel array */
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add Control Channel [%d]",count);
+               slot = apr_array_push(session->channels);
+               *slot = channel;
+
+               if(channel->engine_channel) {
+                       /* open resource engine channel */
+                       if(mrcp_engine_channel_open(channel->engine_channel) == TRUE) {
+                               mpf_termination_t *termination = channel->engine_channel->termination;
+                               session->answer_flag_count++;
+
+                               if(termination) {
+                                       /* send add termination request (add to media context) */
+                                       if(mrcp_server_mpf_request_send(session,MPF_COMMAND_ADD,session->context,termination,NULL) == TRUE) {
+                                               channel->waiting_for_termination = TRUE;
+                                               session->answer_flag_count++;
+                                       }
+
+                                       if(termination->audio_stream) {
+                                               mpf_rtp_media_descriptor_t *rtp_media_descriptor = mrcp_session_audio_media_get(descriptor,0);
+                                               if(rtp_media_descriptor) {
+                                                       mpf_stream_mode_e mode = termination->audio_stream->mode;
+                                                       rtp_media_descriptor->mode |= mode;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+       else {
+               /* teardown */
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_server_control_media_offer_process(mrcp_server_session_t *session, mrcp_session_descriptor_t *descriptor)
+{
+       mrcp_channel_t *channel;
+       mrcp_control_descriptor_t *control_descriptor;
+       int i;
+       int count = session->channels->nelts;
+       if(count > descriptor->control_media_arr->nelts) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Number of Control Channels [%d] > Number of Control Media in Offer [%d]",
+                       count,descriptor->control_media_arr->nelts);
+               count = descriptor->control_media_arr->nelts;
+       }
+       
+       /* update existing control channels */
+       for(i=0; i<count; i++) {
+               /* get existing termination */
+               channel = *((mrcp_channel_t**)session->channels->elts + i);
+               if(!channel) continue;
+
+               channel->waiting_for_channel = FALSE;
+               /* get control descriptor */
+               control_descriptor = mrcp_session_control_media_get(descriptor,i);
+               if(!control_descriptor) continue;
+
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Modify Control Channel [%d]",i);
+               if(channel->control_channel) {
+                       /* send offer */
+                       if(mrcp_server_control_channel_modify(channel->control_channel,control_descriptor) == TRUE) {
+                               channel->waiting_for_channel = TRUE;
+                               session->answer_flag_count++;
+                       }
+               }
+
+               if(channel->waiting_for_channel == FALSE) {
+                       mrcp_control_descriptor_t *answer = mrcp_control_answer_create(control_descriptor,channel->pool);
+                       answer->port = 0;
+                       answer->session_id = session->base.id;
+                       mrcp_session_control_media_set(session->answer,channel->id,answer);
+               }
+       }
+       
+       /* add new control channels */
+       for(; i<descriptor->control_media_arr->nelts; i++) {
+               mrcp_channel_t **slot;
+               /* get control descriptor */
+               control_descriptor = mrcp_session_control_media_get(descriptor,i);
+               if(!control_descriptor) continue;
+
+               /* create new MRCP channel instance */
+               channel = mrcp_server_channel_create(session,&control_descriptor->resource_name,i);
+               if(!channel) continue;
+               /* add to channel array */
+
+               control_descriptor->session_id = session->base.id;
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add Control Channel [%d]",i);
+               slot = apr_array_push(session->channels);
+               *slot = channel;
+
+               if(channel->control_channel) {
+                       /* send modify connection request */
+                       if(mrcp_server_control_channel_add(channel->control_channel,control_descriptor) == TRUE) {
+                               channel->waiting_for_channel = TRUE;
+                               session->answer_flag_count++;
+                       }
+               }
+
+               if(channel->waiting_for_channel == FALSE) {
+                       mrcp_control_descriptor_t *answer = mrcp_control_answer_create(control_descriptor,channel->pool);
+                       answer->port = 0;
+                       answer->session_id = session->base.id;
+                       mrcp_session_control_media_set(session->answer,channel->id,answer);
+               }
+               
+               if(channel->engine_channel) {
+                       /* open resource engine channel */
+                       if(mrcp_engine_channel_open(channel->engine_channel) == TRUE) {
+                               mpf_termination_t *termination = channel->engine_channel->termination;
+                               session->answer_flag_count++;
+
+                               if(termination) {
+                                       /* send add termination request (add to media context) */
+                                       if(mrcp_server_mpf_request_send(session,MPF_COMMAND_ADD,session->context,termination,NULL) == TRUE) {
+                                               channel->waiting_for_termination = TRUE;
+                                               session->answer_flag_count++;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return TRUE;
+}
+
+static apt_bool_t mrcp_server_av_media_offer_process(mrcp_server_session_t *session, mrcp_session_descriptor_t *descriptor)
+{
+       mrcp_termination_slot_t *slot;
+       int i;
+       int count = session->terminations->nelts;
+       if(!descriptor->audio_media_arr->nelts) {
+               /* no media to process */
+               return TRUE;
+       }
+       if(count > descriptor->audio_media_arr->nelts) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Number of Terminations [%d] > Number of Audio Media in Offer [%d]",
+                       count,descriptor->audio_media_arr->nelts);
+               count = descriptor->audio_media_arr->nelts;
+       }
+       
+       /* update existing terminations */
+       for(i=0; i<count; i++) {
+               mpf_rtp_termination_descriptor_t *rtp_descriptor;
+               /* get existing termination */
+               slot = &((mrcp_termination_slot_t*)session->terminations->elts)[i];
+               if(!slot || !slot->termination) continue;
+
+               /* construct termination descriptor */
+               rtp_descriptor = apr_palloc(session->base.pool,sizeof(mpf_rtp_termination_descriptor_t));
+               mpf_rtp_termination_descriptor_init(rtp_descriptor);
+               rtp_descriptor->audio.local = NULL;
+               rtp_descriptor->audio.remote = mrcp_session_audio_media_get(descriptor,i);
+
+               /* send modify termination request */
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Modify RTP Termination [%d]",i);
+               if(mrcp_server_mpf_request_send(session,MPF_COMMAND_MODIFY,session->context,slot->termination,rtp_descriptor) == TRUE) {
+                       slot->waiting = TRUE;
+                       session->answer_flag_count++;
+               }
+       }
+       
+       /* add new terminations */
+       for(; i<descriptor->audio_media_arr->nelts; i++) {
+               mpf_rtp_termination_descriptor_t *rtp_descriptor;
+               mpf_termination_t *termination;
+               /* create new RTP termination instance */
+               termination = mpf_termination_create(session->profile->rtp_termination_factory,session,session->base.pool);
+               /* add to termination array */
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add RTP Termination [%d]",i);
+               slot = apr_array_push(session->terminations);
+               slot->id = i;
+               slot->waiting = FALSE;
+               slot->termination = termination;
+
+               /* construct termination descriptor */
+               rtp_descriptor = apr_palloc(session->base.pool,sizeof(mpf_rtp_termination_descriptor_t));
+               mpf_rtp_termination_descriptor_init(rtp_descriptor);
+               rtp_descriptor->audio.local = NULL;
+               rtp_descriptor->audio.remote = mrcp_session_audio_media_get(descriptor,i);
+
+               /* send add termination request (add to media context) */
+               if(mrcp_server_mpf_request_send(session,MPF_COMMAND_ADD,session->context,termination,rtp_descriptor) == TRUE) {
+                       slot->waiting = TRUE;
+                       session->answer_flag_count++;
+               }
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_server_session_answer_send(mrcp_server_session_t *session)
+{
+       apt_bool_t status;
+       mrcp_session_descriptor_t *descriptor = session->answer;
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Send Answer "APT_SID_FMT" [c:%d a:%d v:%d] Status %s",
+               session->base.id.buf,
+               descriptor->control_media_arr->nelts,
+               descriptor->audio_media_arr->nelts,
+               descriptor->video_media_arr->nelts,
+               mrcp_session_status_phrase_get(descriptor->status));
+       status = mrcp_session_answer(&session->base,descriptor);
+       session->offer = NULL;
+       session->answer = NULL;
+
+       session->active_request = apt_list_pop_front(session->request_queue);
+       if(session->active_request) {
+               mrcp_server_signaling_message_dispatch(session,session->active_request);
+       }
+       return status;
+}
+
+static apt_bool_t mrcp_server_session_terminate_send(mrcp_server_session_t *session)
+{
+       int i;
+       mrcp_channel_t *channel;
+       for(i=0; i<session->channels->nelts; i++) {
+               channel = ((mrcp_channel_t**)session->channels->elts)[i];
+               if(!channel) continue;
+
+               if(channel->control_channel) {
+                       mrcp_server_control_channel_destroy(channel->control_channel);
+                       channel->control_channel = NULL;
+               }
+               if(channel->engine_channel) {
+                       mrcp_engine_channel_destroy(channel->engine_channel);
+                       channel->engine_channel = NULL;
+               }
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Send Terminate Response "APT_SID_FMT,session->base.id.buf);
+       mrcp_session_terminate_response(&session->base);
+       return TRUE;
+}
+
+
+static mrcp_termination_slot_t* mrcp_server_rtp_termination_find(mrcp_server_session_t *session, mpf_termination_t *termination)
+{
+       int i;
+       mrcp_termination_slot_t *slot;
+       for(i=0; i<session->terminations->nelts; i++) {
+               slot = &((mrcp_termination_slot_t*)session->terminations->elts)[i];
+               if(slot && slot->termination == termination) {
+                       return slot;
+               }
+       }
+       return NULL;
+}
+
+static mrcp_channel_t* mrcp_server_channel_termination_find(mrcp_server_session_t *session, mpf_termination_t *termination)
+{
+       int i;
+       mrcp_channel_t *channel;
+       for(i=0; i<session->channels->nelts; i++) {
+               channel = ((mrcp_channel_t**)session->channels->elts)[i];
+               if(!channel) continue;
+
+               if(channel->engine_channel && channel->engine_channel->termination == termination) {
+                       return channel;
+               }
+       }
+       return NULL;
+}
+
+static mrcp_channel_t* mrcp_server_channel_find(mrcp_server_session_t *session, const apt_str_t *resource_name)
+{
+       int i;
+       mrcp_channel_t *channel;
+       for(i=0; i<session->channels->nelts; i++) {
+               channel = ((mrcp_channel_t**)session->channels->elts)[i];
+               if(!channel) continue;
+
+               if(apt_string_compare(&channel->resource_name,resource_name) == TRUE) {
+                       return channel;
+               }
+       }
+       return NULL;
+}
+
+static apt_bool_t mrcp_server_on_termination_modify(mrcp_server_session_t *session, const mpf_message_t *mpf_message)
+{
+       mrcp_termination_slot_t *termination_slot;
+       if(!session) {
+               return FALSE;
+       }
+       termination_slot = mrcp_server_rtp_termination_find(session,mpf_message->termination);
+       if(termination_slot) {
+               /* rtp termination */
+               mpf_rtp_termination_descriptor_t *rtp_descriptor;
+               if(termination_slot->waiting == FALSE) {
+                       return FALSE;
+               }
+               termination_slot->waiting = FALSE;
+               rtp_descriptor = mpf_message->descriptor;
+               if(rtp_descriptor->audio.local) {
+                       session->answer->ip = rtp_descriptor->audio.local->base.ip;
+                       session->answer->ext_ip = rtp_descriptor->audio.local->base.ext_ip;
+                       mrcp_session_audio_media_set(session->answer,termination_slot->id,rtp_descriptor->audio.local);
+               }
+               if(session->answer_flag_count) {
+                       session->answer_flag_count--;
+                       if(!session->answer_flag_count) {
+                               /* send answer to client */
+                               mrcp_server_session_answer_send(session);
+                       }
+               }
+       }
+       else {
+               /* engine channel termination */
+               mrcp_channel_t *channel = mrcp_server_channel_termination_find(session,mpf_message->termination);
+               if(channel && channel->waiting_for_termination == TRUE) {
+                       channel->waiting_for_termination = FALSE;
+                       if(session->answer_flag_count) {
+                               session->answer_flag_count--;
+                               if(!session->answer_flag_count) {
+                                       /* send answer to client */
+                                       mrcp_server_session_answer_send(session);
+                               }
+                       }
+               }
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_server_on_termination_subtract(mrcp_server_session_t *session, const mpf_message_t *mpf_message)
+{
+       mrcp_termination_slot_t *termination_slot;
+       if(!session) {
+               return FALSE;
+       }
+       termination_slot = mrcp_server_rtp_termination_find(session,mpf_message->termination);
+       if(termination_slot) {
+               /* rtp termination */
+               if(termination_slot->waiting == FALSE) {
+                       return FALSE;
+               }
+               termination_slot->waiting = FALSE;
+               if(session->terminate_flag_count) {
+                       session->terminate_flag_count--;
+                       if(!session->terminate_flag_count) {
+                               mrcp_server_session_terminate_send(session);
+                       }
+               }
+       }
+       else {
+               /* engine channel termination */
+               mrcp_channel_t *channel = mrcp_server_channel_termination_find(session,mpf_message->termination);
+               if(channel && channel->waiting_for_termination == TRUE) {
+                       channel->waiting_for_termination = FALSE;
+                       if(session->terminate_flag_count) {
+                               session->terminate_flag_count--;
+                               if(!session->terminate_flag_count) {
+                                       mrcp_server_session_terminate_send(session);
+                               }
+                       }
+               }
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_server_mpf_request_send(
+                                               mrcp_server_session_t *session, 
+                                               mpf_command_type_e command_id, 
+                                               mpf_context_t *context, 
+                                               mpf_termination_t *termination, 
+                                               void *descriptor)
+{
+       apt_task_t *media_task = mpf_task_get(session->profile->media_engine);
+       apt_task_msg_t *msg;
+       mpf_message_t *mpf_message;
+       msg = apt_task_msg_get(media_task);
+       msg->type = TASK_MSG_USER;
+       mpf_message = (mpf_message_t*) msg->data;
+
+       mpf_message->message_type = MPF_MESSAGE_TYPE_REQUEST;
+       mpf_message->command_id = command_id;
+       mpf_message->context = context;
+       mpf_message->termination = termination;
+       mpf_message->descriptor = descriptor;
+       return apt_task_msg_signal(media_task,msg);
+}
diff --git a/libs/unimrcp/libs/mrcp-signaling/Makefile.am b/libs/unimrcp/libs/mrcp-signaling/Makefile.am
new file mode 100644 (file)
index 0000000..4a7458d
--- /dev/null
@@ -0,0 +1,17 @@
+MAINTAINERCLEANFILES       = Makefile.in
+
+INCLUDES                    = -I$(top_srcdir)/libs/mrcp-signaling/include \
+                              -I$(top_srcdir)/libs/mrcp/include \
+                              -I$(top_srcdir)/libs/mpf/include \
+                              -I$(top_srcdir)/libs/apr-toolkit/include \
+                              $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+noinst_LTLIBRARIES          = libmrcpsignaling.la
+
+include_HEADERS             = include/mrcp_sig_types.h \
+                              include/mrcp_sig_agent.h \
+                              include/mrcp_session.h \
+                              include/mrcp_session_descriptor.h
+
+libmrcpsignaling_la_SOURCES = src/mrcp_sig_agent.c \
+                              src/mrcp_session_descriptor.c
\ No newline at end of file
diff --git a/libs/unimrcp/libs/mrcp-signaling/include/mrcp_session.h b/libs/unimrcp/libs/mrcp-signaling/include/mrcp_session.h
new file mode 100644 (file)
index 0000000..192da1c
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_SESSION_H__
+#define __MRCP_SESSION_H__
+
+/**
+ * @file mrcp_session.h
+ * @brief Abstract MRCP Session
+ */ 
+
+#include "mrcp_sig_types.h"
+#include "apt_string.h"
+
+APT_BEGIN_EXTERN_C
+
+#define MRCP_SESSION_PTR(session) (session)
+#define MRCP_SESSION_SID(session) \
+       (session)->id.buf ? (session)->id.buf : "new"
+
+#define MRCP_SESSION_PTRSID(session) \
+       MRCP_SESSION_PTR(session), MRCP_SESSION_SID(session)
+
+/** MRCP session request vtable declaration */
+typedef struct mrcp_session_request_vtable_t mrcp_session_request_vtable_t;
+/** MRCP session response vtable declaration */
+typedef struct mrcp_session_response_vtable_t mrcp_session_response_vtable_t;
+/** MRCP session event vtable declaration */
+typedef struct mrcp_session_event_vtable_t mrcp_session_event_vtable_t;
+
+
+/** MRCP session */
+struct mrcp_session_t {
+       /** Memory pool to allocate memory from */
+       apr_pool_t       *pool;
+       /** External object associated with session */
+       void             *obj;
+       /** Back pointer to signaling agent */
+       mrcp_sig_agent_t *signaling_agent;
+
+       /** Session identifier */
+       apt_str_t         id;
+       /** Last request identifier sent for client, received for server */
+       mrcp_request_id   last_request_id;
+
+       /** Virtual request methods */
+       const mrcp_session_request_vtable_t  *request_vtable;
+       /** Virtual response methods */
+       const mrcp_session_response_vtable_t *response_vtable;
+       /** Virtual event methods */
+       const mrcp_session_event_vtable_t    *event_vtable;
+};
+
+
+/** MRCP session request vtable */
+struct mrcp_session_request_vtable_t {
+       /** Offer session descriptor */
+       apt_bool_t (*offer)(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor);
+       /** Terminate session */
+       apt_bool_t (*terminate)(mrcp_session_t *session);
+       /** Control session (MRCPv1 only) */
+       apt_bool_t (*control)(mrcp_session_t *session, mrcp_message_t *message);
+       /** Discover resources */
+       apt_bool_t (*discover)(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor);
+};
+
+/** MRCP session response vtable */
+struct mrcp_session_response_vtable_t {
+       /** Answer with remote session descriptor */
+       apt_bool_t (*on_answer)(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor);
+       /** Session terminated */
+       apt_bool_t (*on_terminate)(mrcp_session_t *session);
+       /** Control session (MRCPv1 only) */
+       apt_bool_t (*on_control)(mrcp_session_t *session, mrcp_message_t *message);
+       /** Response to resource discovery request */
+       apt_bool_t (*on_discover)(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor);
+};
+
+/** MRCP session event vtable */
+struct mrcp_session_event_vtable_t {
+       /** Received session termination event without appropriate request */
+       apt_bool_t (*on_terminate)(mrcp_session_t *session);
+};
+
+
+/** Create new memory pool and allocate session object from the pool. */
+MRCP_DECLARE(mrcp_session_t*) mrcp_session_create(apr_size_t padding);
+
+/** Destroy session and assosiated memory pool. */
+MRCP_DECLARE(void) mrcp_session_destroy(mrcp_session_t *session);
+
+
+/** Offer */
+static APR_INLINE apt_bool_t mrcp_session_offer(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor)
+{
+       if(session->request_vtable->offer) {
+               return session->request_vtable->offer(session,descriptor);
+       }
+       return FALSE;
+}
+
+/** Terminate */
+static APR_INLINE apt_bool_t mrcp_session_terminate_request(mrcp_session_t *session)
+{
+       if(session->request_vtable->terminate) {
+               return session->request_vtable->terminate(session);
+       }
+       return FALSE;
+}
+
+/** Answer */
+static APR_INLINE apt_bool_t mrcp_session_answer(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor)
+{
+       if(session->response_vtable->on_answer) {
+               return session->response_vtable->on_answer(session,descriptor);
+       }
+       return FALSE;
+}
+
+/** On terminate response */
+static APR_INLINE apt_bool_t mrcp_session_terminate_response(mrcp_session_t *session)
+{
+       if(session->response_vtable->on_terminate) {
+               return session->response_vtable->on_terminate(session);
+       }
+       return FALSE;
+}
+
+/** On terminate event */
+static APR_INLINE apt_bool_t mrcp_session_terminate_event(mrcp_session_t *session)
+{
+       if(session->event_vtable->on_terminate) {
+               return session->event_vtable->on_terminate(session);
+       }
+       return FALSE;
+}
+
+/** Control request */
+static APR_INLINE apt_bool_t mrcp_session_control_request(mrcp_session_t *session, mrcp_message_t *message)
+{
+       if(session->request_vtable->control) {
+               return session->request_vtable->control(session,message);
+       }
+       return FALSE;
+}
+
+/** On control response/event */
+static APR_INLINE apt_bool_t mrcp_session_control_response(mrcp_session_t *session, mrcp_message_t *message)
+{
+       if(session->response_vtable->on_control) {
+               return session->response_vtable->on_control(session,message);
+       }
+       return FALSE;
+}
+
+/** Resource discovery request */
+static APR_INLINE apt_bool_t mrcp_session_discover_request(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor)
+{
+       if(session->request_vtable->discover) {
+               return session->request_vtable->discover(session,descriptor);
+       }
+       return FALSE;
+}
+
+/** On resource discovery response */
+static APR_INLINE apt_bool_t mrcp_session_discover_response(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor)
+{
+       if(session->response_vtable->on_discover) {
+               return session->response_vtable->on_discover(session,descriptor);
+       }
+       return FALSE;
+}
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_SESSION_H__*/
diff --git a/libs/unimrcp/libs/mrcp-signaling/include/mrcp_session_descriptor.h b/libs/unimrcp/libs/mrcp-signaling/include/mrcp_session_descriptor.h
new file mode 100644 (file)
index 0000000..4a2fa19
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_SESSION_DESCRIPTOR_H__
+#define __MRCP_SESSION_DESCRIPTOR_H__
+
+/**
+ * @file mrcp_session_descriptor.h
+ * @brief MRCP Session Descriptor
+ */ 
+
+#include "mpf_rtp_descriptor.h"
+#include "mrcp_sig_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/** MRCP session status */
+typedef enum {
+       MRCP_SESSION_STATUS_OK,                           /**< OK */
+       MRCP_SESSION_STATUS_NO_SUCH_RESOURCE,     /**< no such resource found */
+       MRCP_SESSION_STATUS_UNACCEPTABLE_RESOURCE,/**< resource exists, but no implementation (plugin) found */
+       MRCP_SESSION_STATUS_UNAVAILABLE_RESOURCE, /**< resource exists, but is temporary unavailable */
+       MRCP_SESSION_STATUS_ERROR                 /**< internal error occuried */
+} mrcp_session_status_e;
+
+/** MRCP session descriptor */
+struct mrcp_session_descriptor_t {
+       /** SDP origin */
+       apt_str_t             origin;
+       /** Session level IP address */
+       apt_str_t             ip;
+       /** Session level external (NAT) IP address */
+       apt_str_t             ext_ip;
+       /** Session level resource name (MRCPv1 only) */
+       apt_str_t             resource_name;
+       /** Resource state (MRCPv1 only) */
+       apt_bool_t            resource_state;
+       /** Session status */
+       mrcp_session_status_e status;
+
+       /** MRCP control media array (mrcp_control_descriptor_t) */
+       apr_array_header_t   *control_media_arr;
+       /** Audio media array (mpf_rtp_media_descriptor_t) */
+       apr_array_header_t   *audio_media_arr;
+       /** Video media array (mpf_rtp_media_descriptor_t) */
+       apr_array_header_t   *video_media_arr;
+};
+
+/** Create session descriptor  */
+MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_session_descriptor_create(apr_pool_t *pool);
+
+static APR_INLINE apr_size_t mrcp_session_media_count_get(const mrcp_session_descriptor_t *descriptor)
+{
+       return descriptor->control_media_arr->nelts + descriptor->audio_media_arr->nelts + descriptor->video_media_arr->nelts;
+}
+
+static APR_INLINE apr_size_t mrcp_session_control_media_add(mrcp_session_descriptor_t *descriptor, void *media)
+{
+       void **slot = apr_array_push(descriptor->control_media_arr);
+       *slot = media;
+       return mrcp_session_media_count_get(descriptor) - 1;
+}
+
+static APR_INLINE void* mrcp_session_control_media_get(const mrcp_session_descriptor_t *descriptor, apr_size_t id)
+{
+       if((int)id >= descriptor->control_media_arr->nelts) {
+               return NULL;
+       }
+       return ((void**)descriptor->control_media_arr->elts)[id];
+}
+
+static APR_INLINE apt_bool_t mrcp_session_control_media_set(mrcp_session_descriptor_t *descriptor, apr_size_t id, void *media)
+{
+       if((int)id >= descriptor->control_media_arr->nelts) {
+               return FALSE;
+       }
+       ((void**)descriptor->control_media_arr->elts)[id] = media;
+       return TRUE;
+}
+
+
+static APR_INLINE apr_size_t mrcp_session_audio_media_add(mrcp_session_descriptor_t *descriptor, mpf_rtp_media_descriptor_t *media)
+{
+       mpf_rtp_media_descriptor_t **slot = apr_array_push(descriptor->audio_media_arr);
+       *slot = media;
+       return mrcp_session_media_count_get(descriptor) - 1;
+}
+
+static APR_INLINE mpf_rtp_media_descriptor_t* mrcp_session_audio_media_get(const mrcp_session_descriptor_t *descriptor, apr_size_t id)
+{
+       if((int)id >= descriptor->audio_media_arr->nelts) {
+               return NULL;
+       }
+       return ((mpf_rtp_media_descriptor_t**)descriptor->audio_media_arr->elts)[id];
+}
+
+static APR_INLINE apt_bool_t mrcp_session_audio_media_set(const mrcp_session_descriptor_t *descriptor, apr_size_t id, mpf_rtp_media_descriptor_t* media)
+{
+       if((int)id >= descriptor->audio_media_arr->nelts) {
+               return FALSE;
+       }
+       ((mpf_rtp_media_descriptor_t**)descriptor->audio_media_arr->elts)[id] = media;
+       return TRUE;
+}
+
+
+static APR_INLINE apr_size_t mrcp_session_video_media_add(mrcp_session_descriptor_t *descriptor, mpf_rtp_media_descriptor_t *media)
+{
+       mpf_rtp_media_descriptor_t **slot = apr_array_push(descriptor->video_media_arr);
+       *slot = media;
+       return mrcp_session_media_count_get(descriptor) - 1;
+}
+
+static APR_INLINE mpf_rtp_media_descriptor_t* mrcp_session_video_media_get(const mrcp_session_descriptor_t *descriptor, apr_size_t id)
+{
+       if((int)id >= descriptor->video_media_arr->nelts) {
+               return NULL;
+       }
+       return ((mpf_rtp_media_descriptor_t**)descriptor->video_media_arr->elts)[id];
+}
+
+static APR_INLINE apt_bool_t mrcp_session_video_media_set(mrcp_session_descriptor_t *descriptor, apr_size_t id, mpf_rtp_media_descriptor_t* media)
+{
+       if((int)id >= descriptor->video_media_arr->nelts) {
+               return FALSE;
+       }
+       ((mpf_rtp_media_descriptor_t**)descriptor->video_media_arr->elts)[id] = media;
+       return TRUE;
+}
+
+/** Get session status phrase  */
+MRCP_DECLARE(const char*) mrcp_session_status_phrase_get(mrcp_session_status_e status);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_SESSION_DESCRIPTOR_H__*/
diff --git a/libs/unimrcp/libs/mrcp-signaling/include/mrcp_sig_agent.h b/libs/unimrcp/libs/mrcp-signaling/include/mrcp_sig_agent.h
new file mode 100644 (file)
index 0000000..d17986c
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_SIG_AGENT_H__
+#define __MRCP_SIG_AGENT_H__
+
+/**
+ * @file mrcp_sig_agent.h
+ * @brief Abstract MRCP Signaling Agent
+ */ 
+
+#include "mrcp_sig_types.h"
+#include "apt_task.h"
+
+APT_BEGIN_EXTERN_C
+
+
+/** MRCP signaling agent  */
+struct mrcp_sig_agent_t {
+       /** Memory pool to allocate memory from */
+       apr_pool_t          *pool;
+       /** External object associated with agent */
+       void                *obj;
+       /** Parent object (client/server) */
+       void                *parent;
+       /** MRCP version */
+       mrcp_version_e       mrcp_version;
+       /** MRCP resource factory */
+       mrcp_resource_factory_t *resource_factory;
+       /** Task interface */
+       apt_task_t          *task;
+       /** Task message pool used to allocate signaling agent messages */
+       apt_task_msg_pool_t *msg_pool;
+
+       /** Virtual create_server_session */
+       mrcp_session_t* (*create_server_session)(mrcp_sig_agent_t *signaling_agent);
+       /** Virtual create_client_session */
+       apt_bool_t (*create_client_session)(mrcp_session_t *session);
+};
+
+/** Create signaling agent. */
+MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_signaling_agent_create(void *obj, mrcp_version_e mrcp_version, apr_pool_t *pool);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_SIG_AGENT_H__*/
diff --git a/libs/unimrcp/libs/mrcp-signaling/include/mrcp_sig_types.h b/libs/unimrcp/libs/mrcp-signaling/include/mrcp_sig_types.h
new file mode 100644 (file)
index 0000000..41de32b
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_SIG_TYPES_H__
+#define __MRCP_SIG_TYPES_H__
+
+/**
+ * @file mrcp_sig_types.h
+ * @brief MRCP Signaling Types Declaration
+ */ 
+
+#include "mrcp_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque MRCP signaling agent declaration */
+typedef struct mrcp_sig_agent_t mrcp_sig_agent_t;
+
+/** Opaque MRCP session declaration */
+typedef struct mrcp_session_t mrcp_session_t;
+
+/** Opaque MRCP session descriptor declaration */
+typedef struct mrcp_session_descriptor_t mrcp_session_descriptor_t;
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_SIG_TYPES_H__*/
diff --git a/libs/unimrcp/libs/mrcp-signaling/mrcpsignaling.vcproj b/libs/unimrcp/libs/mrcp-signaling/mrcpsignaling.vcproj
new file mode 100644 (file)
index 0000000..19353d7
--- /dev/null
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="mrcpsignaling"
+       ProjectGUID="{12A49562-BAB9-43A3-A21D-15B60BBB4C31}"
+       RootNamespace="mrcpsignaling"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\mrcpsignaling.vsprops"
+                       CharacterSet="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\mrcpsignaling.vsprops"
+                       CharacterSet="1"
+                       WholeProgramOptimization="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+                       <File
+                               RelativePath=".\include\mrcp_session.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_session_descriptor.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_sig_agent.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_sig_types.h"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       >
+                       <File
+                               RelativePath=".\src\mrcp_session_descriptor.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\mrcp_sig_agent.c"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/libs/mrcp-signaling/src/mrcp_session_descriptor.c b/libs/unimrcp/libs/mrcp-signaling/src/mrcp_session_descriptor.c
new file mode 100644 (file)
index 0000000..5b01627
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mrcp_session_descriptor.h"
+
+MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_session_descriptor_create(apr_pool_t *pool)
+{
+       mrcp_session_descriptor_t *descriptor = apr_palloc(pool,sizeof(mrcp_session_descriptor_t));
+       apt_string_reset(&descriptor->origin);
+       apt_string_reset(&descriptor->ip);
+       apt_string_reset(&descriptor->ext_ip);
+       apt_string_reset(&descriptor->resource_name);
+       descriptor->resource_state = FALSE;
+       descriptor->status = MRCP_SESSION_STATUS_OK;
+       descriptor->control_media_arr = apr_array_make(pool,1,sizeof(void*));
+       descriptor->audio_media_arr = apr_array_make(pool,1,sizeof(mpf_rtp_media_descriptor_t*));
+       descriptor->video_media_arr = apr_array_make(pool,0,sizeof(mpf_rtp_media_descriptor_t*));
+       return descriptor;
+}
+
+MRCP_DECLARE(const char*) mrcp_session_status_phrase_get(mrcp_session_status_e status)
+{
+       switch(status) {
+               case MRCP_SESSION_STATUS_OK:
+                       return "OK";
+               case MRCP_SESSION_STATUS_NO_SUCH_RESOURCE:
+                       return "Not Found";
+               case MRCP_SESSION_STATUS_UNACCEPTABLE_RESOURCE:
+                       return "Not Acceptable";
+               case MRCP_SESSION_STATUS_UNAVAILABLE_RESOURCE:
+                       return "Unavailable";
+               case MRCP_SESSION_STATUS_ERROR:
+                       return "Error";
+       }
+       return "Unknown";
+}
diff --git a/libs/unimrcp/libs/mrcp-signaling/src/mrcp_sig_agent.c b/libs/unimrcp/libs/mrcp-signaling/src/mrcp_sig_agent.c
new file mode 100644 (file)
index 0000000..90773c3
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mrcp_sig_agent.h"
+#include "mrcp_session.h"
+#include "apt_pool.h"
+
+MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_signaling_agent_create(void *obj, mrcp_version_e mrcp_version, apr_pool_t *pool)
+{
+       mrcp_sig_agent_t *sig_agent = apr_palloc(pool,sizeof(mrcp_sig_agent_t));
+       sig_agent->pool = pool;
+       sig_agent->obj = obj;
+       sig_agent->mrcp_version = mrcp_version;
+       sig_agent->resource_factory = NULL;
+       sig_agent->parent = NULL;
+       sig_agent->task = NULL;
+       sig_agent->msg_pool = NULL;
+       sig_agent->create_server_session = NULL;
+       sig_agent->create_client_session = NULL;
+       return sig_agent;
+}
+
+MRCP_DECLARE(mrcp_session_t*) mrcp_session_create(apr_size_t padding)
+{
+       mrcp_session_t *session;
+       apr_pool_t *pool = apt_pool_create();
+       if(!pool) {
+               return NULL;
+       }
+       session = apr_palloc(pool,sizeof(mrcp_session_t)+padding);
+       session->pool = pool;
+       session->obj = NULL;
+       session->signaling_agent = NULL;
+       session->request_vtable = NULL;
+       session->response_vtable = NULL;
+       session->event_vtable = NULL;
+       apt_string_reset(&session->id);
+       session->last_request_id = 0;
+       return session;
+}
+
+MRCP_DECLARE(void) mrcp_session_destroy(mrcp_session_t *session)
+{
+       if(session->pool) {
+               apr_pool_destroy(session->pool);
+       }
+}
diff --git a/libs/unimrcp/libs/mrcp/Makefile.am b/libs/unimrcp/libs/mrcp/Makefile.am
new file mode 100644 (file)
index 0000000..2d82333
--- /dev/null
@@ -0,0 +1,42 @@
+MAINTAINERCLEANFILES    = Makefile.in
+
+INCLUDES                 = -I$(top_srcdir)/libs/mrcp/include \
+                           -I$(top_srcdir)/libs/mrcp/message/include \
+                           -I$(top_srcdir)/libs/mrcp/control/include \
+                           -I$(top_srcdir)/libs/mrcp/resources/include \
+                           -I$(top_srcdir)/libs/apr-toolkit/include \
+                           $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+noinst_LTLIBRARIES       = libmrcp.la
+
+include_HEADERS          = include/mrcp.h \
+                           include/mrcp_types.h \
+                           message/include/mrcp_header_accessor.h \
+                           message/include/mrcp_generic_header.h \
+                           message/include/mrcp_message.h \
+                           control/include/mrcp_state_machine.h \
+                           control/include/mrcp_resource.h \
+                           control/include/mrcp_resource_factory.h \
+                           control/include/mrcp_stream.h \
+                           resources/include/mrcp_synth_header.h \
+                           resources/include/mrcp_synth_resource.h \
+                           resources/include/mrcp_synth_state_machine.h \
+                           resources/include/mrcp_recog_header.h \
+                           resources/include/mrcp_recog_resource.h \
+                           resources/include/mrcp_recog_state_machine.h \
+                           resources/include/mrcp_default_factory.h
+
+libmrcp_la_SOURCES       = message/src/mrcp_header_accessor.c \
+                           message/src/mrcp_generic_header.c \
+                           message/src/mrcp_message.c \
+                           control/src/mrcp_resource_factory.c \
+                           control/src/mrcp_stream.c \
+                           resources/src/mrcp_synth_header.c \
+                           resources/src/mrcp_synth_resource.c \
+                           resources/src/mrcp_synth_server_state_machine.c \
+                           resources/src/mrcp_synth_client_state_machine.c \
+                           resources/src/mrcp_recog_header.c \
+                           resources/src/mrcp_recog_resource.c \
+                           resources/src/mrcp_recog_server_state_machine.c \
+                           resources/src/mrcp_recog_client_state_machine.c \
+                           resources/src/mrcp_default_factory.c
diff --git a/libs/unimrcp/libs/mrcp/control/include/mrcp_resource.h b/libs/unimrcp/libs/mrcp/control/include/mrcp_resource.h
new file mode 100644 (file)
index 0000000..c85af89
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_RESOURCE_H__
+#define __MRCP_RESOURCE_H__
+
+/**
+ * @file mrcp_resource.h
+ * @brief Abstract MRCP Resource
+ */ 
+
+#include "mrcp_types.h"
+#include "mrcp_header_accessor.h"
+#include "mrcp_state_machine.h"
+
+APT_BEGIN_EXTERN_C
+
+
+/** MRCP resource definition */
+struct mrcp_resource_t {
+       /** MRCP resource identifier */
+       mrcp_resource_id            id;
+
+       /** Set resource specific data in a message by resource id */
+       apt_bool_t (*resourcify_message_by_id)(mrcp_resource_t *resource, mrcp_message_t *message);
+       /** Set resource specific data in a message by resource name */
+       apt_bool_t (*resourcify_message_by_name)(mrcp_resource_t *resource, mrcp_message_t *message);
+
+       /** Create client side state machine */
+       mrcp_state_machine_t* (*create_client_state_machine)(void *obj, mrcp_message_dispatcher_f dispatcher, mrcp_version_e version, apr_pool_t *pool);
+       /** Create server side state machine */
+       mrcp_state_machine_t* (*create_server_state_machine)(void *obj, mrcp_message_dispatcher_f dispatcher, mrcp_version_e version, apr_pool_t *pool);
+};
+
+/** Initialize MRCP resource */
+static APR_INLINE void mrcp_resource_init(mrcp_resource_t *resource)
+{
+       resource->resourcify_message_by_id = NULL;
+       resource->resourcify_message_by_name = NULL;
+       resource->create_client_state_machine = NULL;
+       resource->create_server_state_machine = NULL;
+}
+
+/** Validate MRCP resource */
+static APR_INLINE apt_bool_t mrcp_resource_validate(mrcp_resource_t *resource)
+{
+       return (resource->resourcify_message_by_id && 
+               resource->resourcify_message_by_name) ? TRUE : FALSE;
+}
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_RESOURCE_H__*/
diff --git a/libs/unimrcp/libs/mrcp/control/include/mrcp_resource_factory.h b/libs/unimrcp/libs/mrcp/control/include/mrcp_resource_factory.h
new file mode 100644 (file)
index 0000000..59af8e8
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_RESOURCE_FACTORY_H__
+#define __MRCP_RESOURCE_FACTORY_H__
+
+/**
+ * @file mrcp_resource_factory.h
+ * @brief Aggregation of MRCP Resources
+ */ 
+
+#include "apt_string_table.h"
+#include "apt_text_stream.h"
+#include "mrcp_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Create MRCP resource factory */
+MRCP_DECLARE(mrcp_resource_factory_t*) mrcp_resource_factory_create(apr_size_t resource_count, apr_pool_t *pool);
+
+/** Destroy MRCP resource factory */
+MRCP_DECLARE(apt_bool_t) mrcp_resource_factory_destroy(mrcp_resource_factory_t *resource_factory);
+
+/** Set MRCP resource string table */
+MRCP_DECLARE(apt_bool_t) mrcp_resource_string_table_set(mrcp_resource_factory_t *resource_factory, const apt_str_table_item_t *string_table);
+
+/** Register MRCP resource */
+MRCP_DECLARE(apt_bool_t) mrcp_resource_register(mrcp_resource_factory_t *resource_factory, mrcp_resource_t *resource, mrcp_resource_id resource_id);
+
+/** Get MRCP resource by resource id */
+MRCP_DECLARE(mrcp_resource_t*) mrcp_resource_get(mrcp_resource_factory_t *resource_factory, mrcp_resource_id resource_id);
+
+/** Get resource name associated with specified resource id */
+MRCP_DECLARE(const apt_str_t*) mrcp_resource_name_get(mrcp_resource_factory_t *resource_factory, mrcp_resource_id resource_id);
+
+/** Find resource id associated with specified resource name */
+MRCP_DECLARE(mrcp_resource_id) mrcp_resource_id_find(mrcp_resource_factory_t *resource_factory, const apt_str_t *resource_name);
+
+
+/** Associate MRCP resource specific data by resource identifier */
+MRCP_DECLARE(apt_bool_t) mrcp_message_resourcify_by_id(mrcp_resource_factory_t *resource_factory, mrcp_message_t *message);
+
+/** Associate MRCP resource specific data by resource name */
+MRCP_DECLARE(apt_bool_t) mrcp_message_resourcify_by_name(mrcp_resource_factory_t *resource_factory, mrcp_message_t *message);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_RESOURCE_FACTORY_H__*/
diff --git a/libs/unimrcp/libs/mrcp/control/include/mrcp_state_machine.h b/libs/unimrcp/libs/mrcp/control/include/mrcp_state_machine.h
new file mode 100644 (file)
index 0000000..52ec2dd
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_STATE_MACHINE_H__
+#define __MRCP_STATE_MACHINE_H__
+
+/**
+ * @file mrcp_state_machine.h
+ * @brief MRCP State Machine
+ */ 
+
+#include "mrcp_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/** MRCP state machine declaration */
+typedef struct mrcp_state_machine_t mrcp_state_machine_t;
+
+/** MRCP message dispatcher */
+typedef apt_bool_t (*mrcp_message_dispatcher_f)(mrcp_state_machine_t *state_machine, mrcp_message_t *message);
+
+
+/** MRCP state machine */
+struct mrcp_state_machine_t {
+       /** External object associated with state machine */
+       void *obj;
+       /** Message dispatcher */
+       mrcp_message_dispatcher_f dispatcher;
+
+       /** Virtual update */
+       apt_bool_t (*update)(mrcp_state_machine_t *state_machine, mrcp_message_t *message);
+};
+
+/** Initialize MRCP state machine */
+static APR_INLINE void mrcp_state_machine_init(mrcp_state_machine_t *state_machine, void *obj, mrcp_message_dispatcher_f dispatcher)
+{
+       state_machine->obj = obj;
+       state_machine->dispatcher = dispatcher;
+}
+
+/** Update MRCP state machine */
+static APR_INLINE apt_bool_t mrcp_state_machine_update(mrcp_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       return state_machine->update(state_machine,message);
+}
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_STATE_MACHINE_H__*/
diff --git a/libs/unimrcp/libs/mrcp/control/include/mrcp_stream.h b/libs/unimrcp/libs/mrcp/control/include/mrcp_stream.h
new file mode 100644 (file)
index 0000000..69643f4
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_STREAM_H__
+#define __MRCP_STREAM_H__
+
+/**
+ * @file mrcp_stream.h
+ * @brief MRCP Stream Parser and Generator
+ */ 
+
+#include "apt_text_stream.h"
+#include "mrcp_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Result of MRCP stream processing (parse/generate) */
+typedef enum {
+       MRCP_STREAM_MESSAGE_COMPLETE,
+       MRCP_STREAM_MESSAGE_TRUNCATED,
+       MRCP_STREAM_MESSAGE_INVALID
+} mrcp_stream_result_e;
+
+/** Opaque MRCP parser declaration */
+typedef struct mrcp_parser_t mrcp_parser_t;
+/** Opaque MRCP generator declaration */
+typedef struct mrcp_generator_t mrcp_generator_t;
+
+/** MRCP message handler */
+typedef apt_bool_t (*mrcp_message_handler_f)(void *obj, mrcp_message_t *message, mrcp_stream_result_e result);
+
+/** Parse MRCP message (excluding message body) */
+MRCP_DECLARE(apt_bool_t) mrcp_message_parse(mrcp_resource_factory_t *resource_factory, mrcp_message_t *message, apt_text_stream_t *stream);
+
+/** Generate MRCP message (excluding message body) */
+MRCP_DECLARE(apt_bool_t) mrcp_message_generate(mrcp_resource_factory_t *resource_factory, mrcp_message_t *message, apt_text_stream_t *stream);
+
+
+/** Create MRCP stream parser */
+MRCP_DECLARE(mrcp_parser_t*) mrcp_parser_create(mrcp_resource_factory_t *resource_factory, apr_pool_t *pool);
+
+/** Set resource name to be used while parsing (MRCPv1 only) */
+MRCP_DECLARE(void) mrcp_parser_resource_name_set(mrcp_parser_t *parser, const apt_str_t *resource_name);
+
+/** Parse MRCP stream */
+MRCP_DECLARE(mrcp_stream_result_e) mrcp_parser_run(mrcp_parser_t *parser, apt_text_stream_t *stream);
+
+/** Get parsed MRCP message */
+MRCP_DECLARE(mrcp_message_t*) mrcp_parser_message_get(const mrcp_parser_t *parser);
+
+
+/** Create MRCP stream generator */
+MRCP_DECLARE(mrcp_generator_t*) mrcp_generator_create(mrcp_resource_factory_t *resource_factory, apr_pool_t *pool);
+
+/** Set MRCP message to generate */
+MRCP_DECLARE(apt_bool_t) mrcp_generator_message_set(mrcp_generator_t *generator, mrcp_message_t *message);
+
+/** Generate MRCP stream */
+MRCP_DECLARE(mrcp_stream_result_e) mrcp_generator_run(mrcp_generator_t *generator, apt_text_stream_t *stream);
+
+/** Walk through MRCP stream and call message handler for each parsed message */
+MRCP_DECLARE(apt_bool_t) mrcp_stream_walk(mrcp_parser_t *parser, apt_text_stream_t *stream, mrcp_message_handler_f handler, void *obj);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_STREAM_H__*/
diff --git a/libs/unimrcp/libs/mrcp/control/src/mrcp_resource_factory.c b/libs/unimrcp/libs/mrcp/control/src/mrcp_resource_factory.c
new file mode 100644 (file)
index 0000000..7280d3d
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mrcp_resource_factory.h"
+#include "mrcp_message.h"
+#include "mrcp_resource.h"
+#include "mrcp_generic_header.h"
+
+/** Resource factory definition (aggregation of resources) */
+struct mrcp_resource_factory_t {
+       /** Array of MRCP resources */
+       mrcp_resource_t           **resource_array;
+       /** Number of MRCP resources */
+       apr_size_t                  resource_count;
+       /** String table of MRCP resource names */
+       const apt_str_table_item_t *string_table;
+};
+
+/** Create MRCP resource factory */
+MRCP_DECLARE(mrcp_resource_factory_t*) mrcp_resource_factory_create(apr_size_t resource_count, apr_pool_t *pool)
+{
+       apr_size_t i;
+       mrcp_resource_factory_t *resource_factory;
+       if(resource_count == 0) {
+               return NULL;
+       }
+
+       resource_factory = apr_palloc(pool,sizeof(mrcp_resource_factory_t));
+       resource_factory->resource_count = resource_count;
+       resource_factory->resource_array = apr_palloc(pool,sizeof(mrcp_resource_t*)*resource_count);
+       for(i=0; i<resource_count; i++) {
+               resource_factory->resource_array[i] = NULL;
+       }
+       resource_factory->string_table = NULL;
+       
+       return resource_factory;
+}
+
+/** Destroy MRCP resource container */
+MRCP_DECLARE(apt_bool_t) mrcp_resource_factory_destroy(mrcp_resource_factory_t *resource_factory)
+{
+       if(resource_factory->resource_array) {
+               resource_factory->resource_array = NULL;
+       }
+       resource_factory->resource_count = 0;
+       return TRUE;
+}
+
+/** Set MRCP resource string table */
+MRCP_DECLARE(apt_bool_t) mrcp_resource_string_table_set(mrcp_resource_factory_t *resource_factory, const apt_str_table_item_t *string_table)
+{
+       resource_factory->string_table = string_table;
+       return TRUE;
+}
+
+/** Register MRCP resource */
+MRCP_DECLARE(apt_bool_t) mrcp_resource_register(mrcp_resource_factory_t *resource_factory, mrcp_resource_t *resource, mrcp_resource_id resource_id)
+{      
+       if(!resource || resource_id >= resource_factory->resource_count) {
+               /* invalid params */
+               return FALSE;
+       }
+       if(resource_factory->resource_array[resource_id]) {
+               /* resource with specified id already exists */
+               return FALSE;
+       }
+       resource->id = resource_id;
+       if(mrcp_resource_validate(resource) != TRUE) {
+               /* invalid resource */
+               return FALSE;
+       }
+       resource_factory->resource_array[resource->id] = resource;
+       return TRUE;
+}
+
+/** Get MRCP resource by resource id */
+MRCP_DECLARE(mrcp_resource_t*) mrcp_resource_get(mrcp_resource_factory_t *resource_factory, mrcp_resource_id resource_id)
+{
+       if(resource_id >= resource_factory->resource_count) {
+               return NULL;
+       }
+       return resource_factory->resource_array[resource_id];
+}
+
+
+/** Set header accessor interface */
+static APR_INLINE void mrcp_generic_header_accessor_set(mrcp_message_t *message)
+{
+       message->header.generic_header_accessor.vtable = mrcp_generic_header_vtable_get(message->start_line.version);
+}
+
+/** Associate MRCP resource specific data by resource identifier */
+MRCP_DECLARE(apt_bool_t) mrcp_message_resourcify_by_id(mrcp_resource_factory_t *resource_factory, mrcp_message_t *message)
+{
+       mrcp_resource_t *resource;
+       const apt_str_t *name;
+       resource = mrcp_resource_get(resource_factory,message->channel_id.resource_id);
+       if(!resource) {
+               return FALSE;
+       }
+       name = mrcp_resource_name_get(resource_factory,resource->id);
+       if(!name) {
+               return FALSE;
+       }
+       /* associate resource_name and resource_id */
+       message->channel_id.resource_name = *name;
+
+       mrcp_generic_header_accessor_set(message);
+       return resource->resourcify_message_by_id(resource,message);
+}
+
+/** Associate MRCP resource specific data by resource name */
+MRCP_DECLARE(apt_bool_t) mrcp_message_resourcify_by_name(mrcp_resource_factory_t *resource_factory, mrcp_message_t *message)
+{
+       mrcp_resource_t *resource;
+       /* associate resource_name and resource_id */
+       const apt_str_t *name = &message->channel_id.resource_name;
+       message->channel_id.resource_id = mrcp_resource_id_find(resource_factory,name);
+       resource = mrcp_resource_get(resource_factory,message->channel_id.resource_id);
+       if(!resource) {
+               return FALSE;
+       }
+
+       mrcp_generic_header_accessor_set(message);
+       return resource->resourcify_message_by_name(resource,message);
+}
+
+/** Get resource name associated with specified resource id */
+MRCP_DECLARE(const apt_str_t*) mrcp_resource_name_get(mrcp_resource_factory_t *resource_factory, mrcp_resource_id resource_id)
+{
+       return apt_string_table_str_get(resource_factory->string_table,resource_factory->resource_count,resource_id);
+}
+
+/** Find resource id associated with specified resource name */
+MRCP_DECLARE(mrcp_resource_id) mrcp_resource_id_find(mrcp_resource_factory_t *resource_factory, const apt_str_t *resource_name)
+{
+       return apt_string_table_id_find(resource_factory->string_table,resource_factory->resource_count,resource_name);
+}
diff --git a/libs/unimrcp/libs/mrcp/control/src/mrcp_stream.c b/libs/unimrcp/libs/mrcp/control/src/mrcp_stream.c
new file mode 100644 (file)
index 0000000..f90d068
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mrcp_stream.h"
+#include "mrcp_message.h"
+#include "mrcp_generic_header.h"
+#include "mrcp_resource_factory.h"
+#include "apt_log.h"
+
+/** MRCP parser */
+struct mrcp_parser_t {
+       mrcp_resource_factory_t *resource_factory;
+       apt_str_t                resource_name;
+       mrcp_stream_result_e     result;
+       char                    *pos;
+       apt_bool_t               skip_lf;
+       mrcp_message_t          *message;
+       apr_pool_t              *pool;
+};
+
+/** MRCP generator */
+struct mrcp_generator_t {
+       mrcp_resource_factory_t *resource_factory;
+       mrcp_stream_result_e     result;
+       char                    *pos;
+       mrcp_message_t          *message;
+       apr_pool_t              *pool;
+};
+
+
+/** Read MRCP message-body */
+static mrcp_stream_result_e mrcp_message_body_read(mrcp_message_t *message, apt_text_stream_t *stream)
+{
+       mrcp_stream_result_e result = MRCP_STREAM_MESSAGE_COMPLETE;
+       if(message->body.buf) {
+               mrcp_generic_header_t *generic_header = mrcp_generic_header_get(message);
+               /* stream length available to read */
+               apr_size_t stream_length = stream->text.length - (stream->pos - stream->text.buf);
+               /* required/remaining length to read */
+               apr_size_t required_length = generic_header->content_length - message->body.length;
+               if(required_length > stream_length) {
+                       required_length = stream_length;
+                       /* not complete */
+                       result = MRCP_STREAM_MESSAGE_TRUNCATED;
+               }
+               memcpy(message->body.buf+message->body.length,stream->pos,required_length);
+               message->body.length += required_length;
+               stream->pos += required_length;
+               message->body.buf[message->body.length] = '\0';
+       }
+
+       return result;
+}
+
+/** Parse MRCP message-body */
+static mrcp_stream_result_e mrcp_message_body_parse(mrcp_message_t *message, apt_text_stream_t *stream, apr_pool_t *pool)
+{
+       if(mrcp_generic_header_property_check(message,GENERIC_HEADER_CONTENT_LENGTH) == TRUE) {
+               mrcp_generic_header_t *generic_header = mrcp_generic_header_get(message);
+               if(generic_header && generic_header->content_length) {
+                       apt_str_t *body = &message->body;
+                       body->buf = apr_palloc(pool,generic_header->content_length+1);
+                       body->length = 0;
+                       return mrcp_message_body_read(message,stream);
+               }
+       }
+       return MRCP_STREAM_MESSAGE_COMPLETE;
+}
+
+/** Write MRCP message-body */
+static mrcp_stream_result_e mrcp_message_body_write(mrcp_message_t *message, apt_text_stream_t *stream)
+{
+       mrcp_stream_result_e result = MRCP_STREAM_MESSAGE_COMPLETE;
+       mrcp_generic_header_t *generic_header = mrcp_generic_header_get(message);
+       if(generic_header && message->body.length < generic_header->content_length) {
+               /* stream length available to write */
+               apr_size_t stream_length = stream->text.length - (stream->pos - stream->text.buf);
+               /* required/remaining length to write */
+               apr_size_t required_length = generic_header->content_length - message->body.length;
+               if(required_length > stream_length) {
+                       required_length = stream_length;
+                       /* not complete */
+                       result = MRCP_STREAM_MESSAGE_TRUNCATED;
+               }
+
+               memcpy(stream->pos,message->body.buf+message->body.length,required_length);
+               message->body.length += required_length;
+               stream->pos += required_length;
+       }
+
+       return result;
+}
+
+/** Generate MRCP message-body */
+static mrcp_stream_result_e mrcp_message_body_generate(mrcp_message_t *message, apt_text_stream_t *stream)
+{
+       if(mrcp_generic_header_property_check(message,GENERIC_HEADER_CONTENT_LENGTH) == TRUE) {
+               mrcp_generic_header_t *generic_header = mrcp_generic_header_get(message);
+               if(generic_header && generic_header->content_length) {
+                       apt_str_t *body = &message->body;
+                       body->length = 0;
+                       return mrcp_message_body_write(message,stream);
+               }
+       }
+       return MRCP_STREAM_MESSAGE_COMPLETE;
+}
+
+/** Parse MRCP message (excluding message body) */
+MRCP_DECLARE(apt_bool_t) mrcp_message_parse(mrcp_resource_factory_t *resource_factory, mrcp_message_t *message, apt_text_stream_t *stream)
+{
+       /* parse start-line */
+       if(mrcp_start_line_parse(&message->start_line,stream,message->pool) == FALSE) {
+               return FALSE;
+       }
+
+       if(message->start_line.version == MRCP_VERSION_2) {
+               mrcp_channel_id_parse(&message->channel_id,stream,message->pool);
+       }
+
+       if(mrcp_message_resourcify_by_name(resource_factory,message) == FALSE) {
+               return FALSE;
+       }
+
+       /* parse header */
+       if(mrcp_message_header_parse(&message->header,stream,message->pool) == FALSE) {
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+/** Generate MRCP message (excluding message body) */
+MRCP_DECLARE(apt_bool_t) mrcp_message_generate(mrcp_resource_factory_t *resource_factory, mrcp_message_t *message, apt_text_stream_t *stream)
+{
+       /* initialize resource specific data */
+       if(mrcp_message_resourcify_by_id(resource_factory,message) == FALSE) {
+               return FALSE;
+       }
+
+       /* validate message */
+       if(mrcp_message_validate(message) == FALSE) {
+               return FALSE;
+       }
+       
+       /* generate start-line */
+       if(mrcp_start_line_generate(&message->start_line,stream) == FALSE) {
+               return FALSE;
+       }
+
+       if(message->start_line.version == MRCP_VERSION_2) {
+               mrcp_channel_id_generate(&message->channel_id,stream);
+       }
+
+       /* generate header */
+       if(mrcp_message_header_generate(&message->header,stream) == FALSE) {
+               return FALSE;
+       }
+
+       /* finalize start-line generation */
+       mrcp_start_line_finalize(&message->start_line,message->body.length,stream);
+       return TRUE;
+}
+
+
+/** Create MRCP stream parser */
+MRCP_DECLARE(mrcp_parser_t*) mrcp_parser_create(mrcp_resource_factory_t *resource_factory, apr_pool_t *pool)
+{
+       mrcp_parser_t *parser = apr_palloc(pool,sizeof(mrcp_parser_t));
+       parser->resource_factory = resource_factory;
+       apt_string_reset(&parser->resource_name);
+       parser->result = MRCP_STREAM_MESSAGE_INVALID;
+       parser->pos = NULL;
+       parser->skip_lf = FALSE;
+       parser->message = NULL;
+       parser->pool = pool;
+       return parser;
+}
+
+/** Set resource name to be used while parsing (MRCPv1 only) */
+MRCP_DECLARE(void) mrcp_parser_resource_name_set(mrcp_parser_t *parser, const apt_str_t *resource_name)
+{
+       if(resource_name) {
+               apt_string_copy(&parser->resource_name,resource_name,parser->pool);
+       }
+}
+
+static mrcp_stream_result_e mrcp_parser_break(mrcp_parser_t *parser, apt_text_stream_t *stream)
+{
+       /* failed to parse either start-line or header */
+       if(apt_text_is_eos(stream) == TRUE) {
+               /* end of stream reached, rewind/restore stream */
+               stream->pos = parser->pos;
+               parser->result = MRCP_STREAM_MESSAGE_TRUNCATED;
+               parser->message = NULL;
+       }
+       else {
+               /* error case */
+               parser->result = MRCP_STREAM_MESSAGE_INVALID;
+       }
+       return parser->result;
+}
+
+/** Parse MRCP stream */
+MRCP_DECLARE(mrcp_stream_result_e) mrcp_parser_run(mrcp_parser_t *parser, apt_text_stream_t *stream)
+{
+       mrcp_message_t *message = parser->message;
+       if(message && parser->result == MRCP_STREAM_MESSAGE_TRUNCATED) {
+               /* process continuation data */
+               parser->result = mrcp_message_body_read(message,stream);
+               return parser->result;
+       }
+       
+       /* create new MRCP message */
+       message = mrcp_message_create(parser->pool);
+       message->channel_id.resource_name = parser->resource_name;
+       parser->message = message;
+       /* store current position to be able to rewind/restore stream if needed */
+       parser->pos = stream->pos;
+
+       /* parse start-line and header */
+       if(mrcp_message_parse(parser->resource_factory,message,stream) == FALSE) {
+               return mrcp_parser_break(parser,stream);
+       }
+
+       /* parse body */
+       parser->result = mrcp_message_body_parse(message,stream,message->pool);
+
+       /* in the worst case message segmentation may occur between <CR> and <LF> 
+          of the final empty header */
+       if(!message->body.length && *(stream->pos-1)== APT_TOKEN_CR) {
+               /* if this is the case be prepared to skip <LF> */
+               parser->skip_lf = TRUE;
+       }
+       return parser->result;
+}
+
+/** Get parsed MRCP message */
+MRCP_DECLARE(mrcp_message_t*) mrcp_parser_message_get(const mrcp_parser_t *parser)
+{
+       return parser->message;
+}
+
+
+/** Create MRCP stream generator */
+MRCP_DECLARE(mrcp_generator_t*) mrcp_generator_create(mrcp_resource_factory_t *resource_factory, apr_pool_t *pool)
+{
+       mrcp_generator_t *generator = apr_palloc(pool,sizeof(mrcp_generator_t));
+       generator->resource_factory = resource_factory;
+       generator->result = MRCP_STREAM_MESSAGE_INVALID;
+       generator->pos = NULL;
+       generator->message = NULL;
+       generator->pool = pool;
+       return generator;
+}
+
+/** Set MRCP message to generate */
+MRCP_DECLARE(apt_bool_t) mrcp_generator_message_set(mrcp_generator_t *generator, mrcp_message_t *message)
+{
+       if(!message) {
+               return FALSE;
+       }
+       generator->message = message;
+       return TRUE;
+}
+
+static mrcp_stream_result_e mrcp_generator_break(mrcp_generator_t *generator, apt_text_stream_t *stream)
+{
+       /* failed to generate either start-line or header */
+       if(apt_text_is_eos(stream) == TRUE) {
+               /* end of stream reached, rewind/restore stream */
+               stream->pos = generator->pos;
+               generator->result = MRCP_STREAM_MESSAGE_TRUNCATED;
+       }
+       else {
+               /* error case */
+               generator->result = MRCP_STREAM_MESSAGE_INVALID;
+       }
+       return generator->result;
+}
+
+/** Generate MRCP stream */
+MRCP_DECLARE(mrcp_stream_result_e) mrcp_generator_run(mrcp_generator_t *generator, apt_text_stream_t *stream)
+{
+       mrcp_message_t *message = generator->message;
+       if(!message) {
+               return MRCP_STREAM_MESSAGE_INVALID;
+       }
+
+       if(message && generator->result == MRCP_STREAM_MESSAGE_TRUNCATED) {
+               /* process continuation data */
+               generator->result = mrcp_message_body_write(message,stream);
+               return generator->result;
+       }
+
+       /* generate start-line and header */
+       if(mrcp_message_generate(generator->resource_factory,message,stream) == FALSE) {
+               return mrcp_generator_break(generator,stream);
+       }
+
+       /* generate body */
+       generator->result = mrcp_message_body_generate(message,stream);
+       return generator->result;
+}
+
+
+/** Walk through MRCP stream and invoke message handler for each parsed message */
+MRCP_DECLARE(apt_bool_t) mrcp_stream_walk(mrcp_parser_t *parser, apt_text_stream_t *stream, mrcp_message_handler_f handler, void *obj)
+{
+       mrcp_stream_result_e result;
+       if(parser->skip_lf == TRUE) {
+               /* skip <LF> occurred as a result of message segmentation between <CR> and <LF> */
+               apt_text_char_skip(stream,APT_TOKEN_LF);
+               parser->skip_lf = FALSE;
+       }
+       do {
+               result = mrcp_parser_run(parser,stream);
+               if(result == MRCP_STREAM_MESSAGE_COMPLETE) {
+                       /* message is completely parsed */
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Parsed MRCP Message [%lu]", stream->pos - stream->text.buf);
+                       /* invoke message handler */
+                       handler(obj,parser->message,result);
+               }
+               else if(result == MRCP_STREAM_MESSAGE_TRUNCATED) {
+                       /* message is partially parsed, to be continued */
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Truncated MRCP Message [%lu]", stream->pos - stream->text.buf);
+                       /* prepare stream for further processing */
+                       if(apt_text_stream_scroll(stream) == TRUE) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Scroll MRCP Stream", stream->text.buf);
+                       }
+                       return TRUE;
+               }
+               else if(result == MRCP_STREAM_MESSAGE_INVALID){
+                       /* error case */
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse MRCP Message");
+                       /* invoke message handler */
+                       handler(obj,parser->message,result);
+                       /* reset stream pos */
+                       stream->pos = stream->text.buf;
+                       return FALSE;
+               }
+       }
+       while(apt_text_is_eos(stream) == FALSE);
+
+       /* reset stream pos */
+       stream->pos = stream->text.buf;
+       return TRUE;
+}
diff --git a/libs/unimrcp/libs/mrcp/include/mrcp.h b/libs/unimrcp/libs/mrcp/include/mrcp.h
new file mode 100644 (file)
index 0000000..0140a1b
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_H__
+#define __MRCP_H__
+
+/**
+ * @file mrcp.h
+ * @brief MRCP Core Definitions
+ */ 
+
+#include <apt.h>
+#include <apt_dir_layout.h>
+
+/** Library export/import defines */
+#ifdef WIN32
+#ifdef MRCP_STATIC_LIB
+#define MRCP_DECLARE(type)   type __stdcall
+#else
+#ifdef MRCP_LIB_EXPORT
+#define MRCP_DECLARE(type)   __declspec(dllexport) type __stdcall
+#else
+#define MRCP_DECLARE(type)   __declspec(dllimport) type __stdcall
+#endif
+#endif
+#else
+#define MRCP_DECLARE(type) type
+#endif
+
+#endif /*__MRCP_H__*/
diff --git a/libs/unimrcp/libs/mrcp/include/mrcp_types.h b/libs/unimrcp/libs/mrcp/include/mrcp_types.h
new file mode 100644 (file)
index 0000000..9b381ab
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_TYPES_H__
+#define __MRCP_TYPES_H__
+
+/**
+ * @file mrcp_types.h
+ * @brief Basic MRCP Types
+ */ 
+
+#include "mrcp.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Protocol version */
+typedef enum {
+       
+       MRCP_VERSION_UNKNOWN = 0,  /**< Unknown version */
+       MRCP_VERSION_1 = 1,        /**< MRCPv1 (RFC4463) */
+       MRCP_VERSION_2 = 2         /**< MRCPv2 (draft-ietf-speechsc-mrcpv2-15) */
+} mrcp_version_e;
+
+/** Enumeration of MRCP resource types */
+typedef enum {
+       MRCP_SYNTHESIZER_RESOURCE, /**< Synthesizer resource */
+       MRCP_RECOGNIZER_RESOURCE,  /**< Recognizer resource */
+
+       MRCP_RESOURCE_TYPE_COUNT   /**< Number of resources */
+} mrcp_resource_type_e;
+
+/** Message identifier used in request/response/event messages. */
+typedef apr_size_t  mrcp_request_id;
+/** Method identifier associated with method name. */
+typedef apr_size_t mrcp_method_id;
+/** Resource identifier associated with resource name. */
+typedef apr_size_t mrcp_resource_id;
+
+
+/** Opaque MRCP message declaration */
+typedef struct mrcp_message_t mrcp_message_t;
+/** Opaque MRCP resource declaration */
+typedef struct mrcp_resource_t mrcp_resource_t;
+/** Opaque MRCP resource factory declaration */
+typedef struct mrcp_resource_factory_t mrcp_resource_factory_t;
+
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_TYPES_H__*/
diff --git a/libs/unimrcp/libs/mrcp/message/include/mrcp_generic_header.h b/libs/unimrcp/libs/mrcp/message/include/mrcp_generic_header.h
new file mode 100644 (file)
index 0000000..fb8ebf8
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_GENERIC_HEADER_H__
+#define __MRCP_GENERIC_HEADER_H__
+
+/**
+ * @file mrcp_generic_header.h
+ * @brief MRCP Generic Header
+ */ 
+
+#include "mrcp_types.h"
+#include "mrcp_header_accessor.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Enumeration of MRCP generic headers */
+typedef enum {
+       GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST,
+       GENERIC_HEADER_PROXY_SYNC_ID,
+       GENERIC_HEADER_ACCEPT_CHARSET,
+       GENERIC_HEADER_CONTENT_TYPE,
+       GENERIC_HEADER_CONTENT_ID,
+       GENERIC_HEADER_CONTENT_BASE,
+       GENERIC_HEADER_CONTENT_ENCODING,
+       GENERIC_HEADER_CONTENT_LOCATION,
+       GENERIC_HEADER_CONTENT_LENGTH,
+       GENERIC_HEADER_CACHE_CONTROL,
+       GENERIC_HEADER_LOGGING_TAG,
+       GENERIC_HEADER_VENDOR_SPECIFIC_PARAMS,
+       
+       /** Additional headers for MRCP v2 */
+       GENERIC_HEADER_ACCEPT,
+       GENERIC_HEADER_FETCH_TIMEOUT,
+       GENERIC_HEADER_SET_COOKIE,
+       GENERIC_HEADER_SET_COOKIE2,
+
+       GENERIC_HEADER_COUNT
+} mrcp_generic_header_id;
+
+/** MRCP request identifiers list declaration */
+typedef struct mrcp_request_id_list_t mrcp_request_id_list_t;
+/** MRCP vendor specific parameter list of pairs */
+typedef struct mrcp_vendor_specific_params_list_t mrcp_vendor_specific_params_list_t;
+/** MRCP generic header declaration */
+typedef struct mrcp_generic_header_t mrcp_generic_header_t;
+
+/** Max number of request ids in active request id list */
+#define MAX_ACTIVE_REQUEST_ID_COUNT 5
+/** List (array) of MRCP request identifiers */
+struct mrcp_request_id_list_t {
+       /** Array of request identifiers */
+       mrcp_request_id ids[MAX_ACTIVE_REQUEST_ID_COUNT];
+       /** Number of request identifiers */
+       size_t          count;
+};
+
+
+/** MRCP generic header */
+struct mrcp_generic_header_t {
+       /** Indicates the list of request-ids to which it should apply */
+       mrcp_request_id_list_t active_request_id_list;
+       /** Helps the resource receiving the event, proxied by the client, 
+       to decide if this event has been processed through a direct interaction of the resources */
+       apt_str_t              proxy_sync_id;
+       /** Specifies the acceptable character set for entities returned in the response or events associated with this request */
+       apt_str_t              accept_charset;
+       /** Restricted to speech markup, grammar, recognition results, etc. */
+       apt_str_t              content_type;
+       /** Contains an ID or name for the content, by which it can be referred to */
+       apt_str_t              content_id;
+       /** May be used to specify the base URI for resolving relative URLs within the entity */
+       apt_str_t              content_base;
+       /** Indicates what additional content coding has been applied to the entity-body */
+       apt_str_t              content_encoding;
+       /** Statement of the location of the resource corresponding to this particular entity at the time of the request */
+       apt_str_t              content_location;
+       /** Contains the length of the content of the message body */
+       size_t                 content_length;
+       /** Defines the default caching algorithms on the media server for the session or request */
+       apt_str_t              cache_control;
+       /** Sets the logging tag for logs generated by the media server */
+       apt_str_t              logging_tag;
+       /** Specifies the vendor specific parameters used by the media server */
+       apt_pair_arr_t        *vendor_specific_params;
+
+       /** Additional headers for MRCP v2 */
+       /** Specifies the acceptable media types set for entities returned in the response or events associated with this request */
+       apt_str_t              accept;
+       /** Defines the timeout for content that the server may need to fetch over the network */
+       apr_size_t             fetch_timeout;
+       /** Enables to synchronize the cookie store of MRCP v2 client and server */
+       apt_str_t              set_cookie;
+       /** Enables to synchronize the cookie store of MRCP v2 client and server */
+       apt_str_t              set_cookie2;
+};
+
+/** Get generic header vtable */
+MRCP_DECLARE(const mrcp_header_vtable_t*) mrcp_generic_header_vtable_get(mrcp_version_e version);
+
+
+/** Append active request id list */
+MRCP_DECLARE(apt_bool_t) active_request_id_list_append(mrcp_generic_header_t *generic_header, mrcp_request_id request_id);
+/** Find request id in active request id list */
+MRCP_DECLARE(apt_bool_t) active_request_id_list_find(mrcp_generic_header_t *generic_header, mrcp_request_id request_id);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_GENERIC_HEADER_H__*/
diff --git a/libs/unimrcp/libs/mrcp/message/include/mrcp_header_accessor.h b/libs/unimrcp/libs/mrcp/message/include/mrcp_header_accessor.h
new file mode 100644 (file)
index 0000000..2091833
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_HEADER_ACCESSOR_H__
+#define __MRCP_HEADER_ACCESSOR_H__
+
+/**
+ * @file mrcp_header_accessor.h
+ * @brief Abstract MRCP Header Accessor
+ */ 
+
+#include "apt_string_table.h"
+#include "apt_text_stream.h"
+#include "mrcp.h"
+
+APT_BEGIN_EXTERN_C
+
+/** MRCP header accessor declaration */
+typedef struct mrcp_header_accessor_t mrcp_header_accessor_t;
+/** MRCP header vtable declaration */
+typedef struct mrcp_header_vtable_t mrcp_header_vtable_t;
+
+/** MRCP header accessor interface */
+struct mrcp_header_vtable_t {
+       /** Allocate actual header data */
+       void* (*allocate)(mrcp_header_accessor_t *accessor, apr_pool_t *pool);
+       /** Destroy header data */
+       void (*destroy)(mrcp_header_accessor_t *accessor);
+
+       /** Parse header field */
+       apt_bool_t (*parse_field)(mrcp_header_accessor_t *accessor, apr_size_t id, const apt_str_t *value, apr_pool_t *pool);
+       /** Generate header field */
+       apt_bool_t (*generate_field)(mrcp_header_accessor_t *accessor, apr_size_t id, apt_text_stream_t *value);
+       /** Duplicate header field */
+       apt_bool_t (*duplicate_field)(mrcp_header_accessor_t *accessor, const mrcp_header_accessor_t *src, apr_size_t id, apr_pool_t *pool);
+
+       /** Table of fields  */
+       const apt_str_table_item_t *field_table;
+       /** Number of fields  */
+       apr_size_t                  field_count;
+};
+
+
+/** Initialize header vtable */
+static APR_INLINE void mrcp_header_vtable_init(mrcp_header_vtable_t *vtable)
+{
+       vtable->allocate = NULL;
+       vtable->destroy = NULL;
+       vtable->parse_field = NULL;
+       vtable->generate_field = NULL;
+       vtable->duplicate_field = NULL;
+       vtable->field_table = NULL;
+       vtable->field_count = 0;
+}
+
+/** Validate header vtable */
+static APR_INLINE apt_bool_t mrcp_header_vtable_validate(const mrcp_header_vtable_t *vtable)
+{
+       return (vtable->allocate && vtable->destroy && 
+               vtable->parse_field && vtable->generate_field &&
+               vtable->duplicate_field && vtable->field_table && 
+               vtable->field_count) ?  TRUE : FALSE;
+}
+
+
+/** MRCP header accessor */
+struct mrcp_header_accessor_t {
+       /** Actual header data allocated by accessor */
+       void                       *data;
+
+       /** Array properties (mrcp_header_property_e) */
+       char                       *properties;
+       /** Number of filled properties (header fields) */
+       apr_size_t                  counter;
+       
+       /** Header accessor interface */
+       const mrcp_header_vtable_t *vtable;
+};
+
+/** Initialize header accessor */
+static APR_INLINE void mrcp_header_accessor_init(mrcp_header_accessor_t *accessor)
+{
+       accessor->data = NULL;
+       accessor->properties = NULL;
+       accessor->counter = 0;
+       accessor->vtable = NULL;
+}
+
+
+/** Allocate header data */
+static APR_INLINE void* mrcp_header_allocate(mrcp_header_accessor_t *accessor, apr_pool_t *pool)
+{
+       if(accessor->data) {
+               return accessor->data;
+       }
+       if(!accessor->vtable || !accessor->vtable->allocate) {
+               return NULL;
+       }
+       accessor->properties = (char*)apr_pcalloc(pool,sizeof(char)*accessor->vtable->field_count);
+       accessor->counter = 0;
+       return accessor->vtable->allocate(accessor,pool);
+}
+
+/** Destroy header data */
+static APR_INLINE void mrcp_header_destroy(mrcp_header_accessor_t *accessor)
+{
+       if(!accessor->vtable || !accessor->vtable->destroy) {
+               return;
+       }
+       accessor->vtable->destroy(accessor);
+}
+
+
+/** Parse header */
+MRCP_DECLARE(apt_bool_t) mrcp_header_parse(mrcp_header_accessor_t *accessor, const apt_pair_t *pair, apr_pool_t *pool);
+
+/** Generate header */
+MRCP_DECLARE(apt_bool_t) mrcp_header_generate(mrcp_header_accessor_t *accessor, apt_text_stream_t *text_stream);
+
+/** Set header */
+MRCP_DECLARE(apt_bool_t) mrcp_header_set(mrcp_header_accessor_t *accessor, const mrcp_header_accessor_t *src, const mrcp_header_accessor_t *mask, apr_pool_t *pool);
+
+/** Inherit header */
+MRCP_DECLARE(apt_bool_t) mrcp_header_inherit(mrcp_header_accessor_t *accessor, const mrcp_header_accessor_t *parent, apr_pool_t *pool);
+
+
+/** Add name:value property */
+MRCP_DECLARE(void) mrcp_header_property_add(mrcp_header_accessor_t *accessor, apr_size_t id);
+
+/** Remove property */
+MRCP_DECLARE(void) mrcp_header_property_remove(mrcp_header_accessor_t *accessor, apr_size_t id);
+
+/** Check the property */
+MRCP_DECLARE(apt_bool_t) mrcp_header_property_check(mrcp_header_accessor_t *accessor, apr_size_t id);
+
+/** Add name only property */
+MRCP_DECLARE(void) mrcp_header_name_property_add(mrcp_header_accessor_t *accessor, apr_size_t id);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_HEADER_ACCESSOR_H__*/
diff --git a/libs/unimrcp/libs/mrcp/message/include/mrcp_message.h b/libs/unimrcp/libs/mrcp/message/include/mrcp_message.h
new file mode 100644 (file)
index 0000000..769ab08
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_MESSAGE_H__
+#define __MRCP_MESSAGE_H__
+
+/**
+ * @file mrcp_message.h
+ * @brief MRCP Message Definition
+ */ 
+
+#include "mrcp_types.h"
+#include "mrcp_header_accessor.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Request-states used in MRCP response message */
+typedef enum {
+       /** The request was processed to completion and there will be no        
+           more events from that resource to the client with that request-id */
+       MRCP_REQUEST_STATE_COMPLETE,
+       /** The job has been placed on a queue and will be processed in first-in-first-out order */
+       MRCP_REQUEST_STATE_INPROGRESS,
+       /** Indicate that further event messages will be delivered with that request-id */
+       MRCP_REQUEST_STATE_PENDING,
+       
+       /** Number of request states */
+       MRCP_REQUEST_STATE_COUNT,
+       /** Unknown request state */
+       MRCP_REQUEST_STATE_UNKNOWN = MRCP_REQUEST_STATE_COUNT
+} mrcp_request_state_e;
+
+/** Status codes */
+typedef enum {
+       MRCP_STATUS_CODE_UNKNOWN                   = 0,
+       /* success codes (2xx) */
+       MRCP_STATUS_CODE_SUCCESS                   = 200,
+       MRCP_STATUS_CODE_SUCCESS_WITH_IGNORE       = 201,
+       /* failure codes (4xx) */
+       MRCP_STATUS_CODE_METHOD_NOT_ALLOWED        = 401,
+       MRCP_STATUS_CODE_METHOD_NOT_VALID          = 402,
+       MRCP_STATUS_CODE_UNSUPPORTED_PARAM         = 403,
+       MRCP_STATUS_CODE_ILLEGAL_PARAM_VALUE       = 404,
+       MRCP_STATUS_CODE_NOT_FOUND                 = 405,
+       MRCP_STATUS_CODE_MISSING_PARAM             = 406,
+       MRCP_STATUS_CODE_METHOD_FAILED             = 407,
+       MRCP_STATUS_CODE_UNRECOGNIZED_MESSAGE      = 408,
+       MRCP_STATUS_CODE_UNSUPPORTED_PARAM_VALUE   = 409,
+       MRCP_STATUS_CODE_RESOURCE_SPECIFIC_FAILURE = 421
+} mrcp_status_code_e;
+
+/** MRCP message types */
+typedef enum {
+       MRCP_MESSAGE_TYPE_UNKNOWN,
+       MRCP_MESSAGE_TYPE_REQUEST,
+       MRCP_MESSAGE_TYPE_RESPONSE,
+       MRCP_MESSAGE_TYPE_EVENT
+} mrcp_message_type_e;
+
+
+/** MRCP start-line declaration */
+typedef struct mrcp_start_line_t mrcp_start_line_t;
+/** MRCP channel-id declaration */
+typedef struct mrcp_channel_id mrcp_channel_id;
+/** MRCP message header declaration */
+typedef struct mrcp_message_header_t mrcp_message_header_t;
+
+
+/** Start-line of MRCP message */
+struct mrcp_start_line_t {
+       /** MRCP message type */
+       mrcp_message_type_e  message_type;
+       /** Version of protocol in use */
+       mrcp_version_e       version;
+       /** Specify the length of the message, including the start-line (v2) */
+       size_t               length;
+       /** Unique identifier among client and server */
+       mrcp_request_id      request_id;
+       /** MRCP method name */
+       apt_str_t            method_name;
+       /** MRCP method id (associated with method name) */
+       mrcp_method_id       method_id;
+       /** Success or failure or other status of the request */
+       mrcp_status_code_e   status_code;
+       /** The state of the job initiated by the request */
+       mrcp_request_state_e request_state;
+};
+
+/** Initialize MRCP start-line */
+MRCP_DECLARE(void) mrcp_start_line_init(mrcp_start_line_t *start_line);
+/** Parse MRCP start-line */
+MRCP_DECLARE(apt_bool_t) mrcp_start_line_parse(mrcp_start_line_t *start_line, apt_text_stream_t *text_stream, apr_pool_t *pool);
+/** Generate MRCP start-line */
+MRCP_DECLARE(apt_bool_t) mrcp_start_line_generate(mrcp_start_line_t *start_line, apt_text_stream_t *text_stream);
+/** Finalize MRCP start-line generation */
+MRCP_DECLARE(apt_bool_t) mrcp_start_line_finalize(mrcp_start_line_t *start_line, apr_size_t content_length, apt_text_stream_t *text_stream);
+
+
+/** MRCP channel-identifier */
+struct mrcp_channel_id {
+       /** Unambiguous string identifying the MRCP session */
+       apt_str_t        session_id;
+       /** MRCP resource name */
+       apt_str_t        resource_name;
+       /** MRCP resource id (associated with resource name) */
+       mrcp_resource_id resource_id;
+};
+
+/** Initialize MRCP channel-identifier */
+MRCP_DECLARE(void) mrcp_channel_id_init(mrcp_channel_id *channel_id);
+
+/** Parse MRCP channel-identifier */
+MRCP_DECLARE(apt_bool_t) mrcp_channel_id_parse(mrcp_channel_id *channel_id, apt_text_stream_t *text_stream, apr_pool_t *pool);
+
+/** Generate MRCP channel-identifier */
+MRCP_DECLARE(apt_bool_t) mrcp_channel_id_generate(mrcp_channel_id *channel_id, apt_text_stream_t *text_stream);
+
+
+/** MRCP message-header */
+struct mrcp_message_header_t {
+       /** MRCP generic-header */
+       mrcp_header_accessor_t generic_header_accessor;
+       /** MRCP resource specific header */
+       mrcp_header_accessor_t resource_header_accessor;
+};
+
+/** Initialize MRCP message-header */
+static APR_INLINE void mrcp_message_header_init(mrcp_message_header_t *message_header)
+{
+       mrcp_header_accessor_init(&message_header->generic_header_accessor);
+       mrcp_header_accessor_init(&message_header->resource_header_accessor);
+}
+
+/** Destroy MRCP message-header */
+static APR_INLINE void mrcp_message_header_destroy(mrcp_message_header_t *message_header)
+{
+       mrcp_header_destroy(&message_header->generic_header_accessor);
+       mrcp_header_destroy(&message_header->resource_header_accessor);
+}
+
+
+/** Parse MRCP message-header */
+MRCP_DECLARE(apt_bool_t) mrcp_message_header_parse(mrcp_message_header_t *message_header, apt_text_stream_t *text_stream, apr_pool_t *pool);
+
+/** Generate MRCP message-header */
+MRCP_DECLARE(apt_bool_t) mrcp_message_header_generate(mrcp_message_header_t *message_header, apt_text_stream_t *text_stream);
+
+/** Set MRCP message-header */
+MRCP_DECLARE(apt_bool_t) mrcp_message_header_set(mrcp_message_header_t *message_header, const mrcp_message_header_t *src, apr_pool_t *pool);
+
+/** Get MRCP message-header */
+MRCP_DECLARE(apt_bool_t) mrcp_message_header_get(mrcp_message_header_t *message_header, const mrcp_message_header_t *src, apr_pool_t *pool);
+
+/** Inherit MRCP message-header */
+MRCP_DECLARE(apt_bool_t) mrcp_message_header_inherit(mrcp_message_header_t *message_header, const mrcp_message_header_t *parent, apr_pool_t *pool);
+
+
+
+/** MRCP message */
+struct mrcp_message_t {
+       /** Start-line of MRCP message */
+       mrcp_start_line_t      start_line;
+       /** Channel-identifier of MRCP message */
+       mrcp_channel_id        channel_id;
+       /** Header of MRCP message */
+       mrcp_message_header_t  header;
+       /** Body of MRCP message */
+       apt_str_t              body;
+
+       /** Memory pool MRCP message is allocated from */
+       apr_pool_t            *pool;
+};
+
+/** Create MRCP message */
+MRCP_DECLARE(mrcp_message_t*) mrcp_message_create(apr_pool_t *pool);
+
+/** Initialize MRCP message */
+MRCP_DECLARE(void) mrcp_message_init(mrcp_message_t *message, apr_pool_t *pool);
+
+/** Initialize MRCP response/event message by request message */
+MRCP_DECLARE(void) mrcp_message_init_by_request(mrcp_message_t *message, const mrcp_message_t *request_message);
+
+/** Create MRCP request message */
+MRCP_DECLARE(mrcp_message_t*) mrcp_request_create(mrcp_resource_id resource_id, mrcp_method_id method_id, apr_pool_t *pool);
+/** Create MRCP response message */
+MRCP_DECLARE(mrcp_message_t*) mrcp_response_create(const mrcp_message_t *request_message, apr_pool_t *pool);
+/** Create MRCP event message */
+MRCP_DECLARE(mrcp_message_t*) mrcp_event_create(const mrcp_message_t *request_message, mrcp_method_id event_id, apr_pool_t *pool);
+
+/** Validate MRCP message */
+MRCP_DECLARE(apt_bool_t) mrcp_message_validate(mrcp_message_t *message);
+
+/** Destroy MRCP message */
+MRCP_DECLARE(void) mrcp_message_destroy(mrcp_message_t *message);
+
+
+/** Parse MRCP message-body */
+MRCP_DECLARE(apt_bool_t) mrcp_body_parse(mrcp_message_t *message, apt_text_stream_t *text_stream, apr_pool_t *pool);
+/** Generate MRCP message-body */
+MRCP_DECLARE(apt_bool_t) mrcp_body_generate(mrcp_message_t *message, apt_text_stream_t *text_stream);
+
+/** Get MRCP generic-header */
+static APR_INLINE void* mrcp_generic_header_get(mrcp_message_t *mrcp_message)
+{
+       return mrcp_message->header.generic_header_accessor.data;
+}
+
+/** Prepare MRCP generic-header */
+static APR_INLINE void* mrcp_generic_header_prepare(mrcp_message_t *mrcp_message)
+{
+       return mrcp_header_allocate(&mrcp_message->header.generic_header_accessor,mrcp_message->pool);
+}
+
+/** Add MRCP generic-header proprerty */
+static APR_INLINE void mrcp_generic_header_property_add(mrcp_message_t *mrcp_message, size_t id)
+{
+       mrcp_header_property_add(&mrcp_message->header.generic_header_accessor,id);
+}
+
+/** Add MRCP generic-header name only proprerty (should be used to construct empty headers in case of GET-PARAMS request) */
+static APR_INLINE void mrcp_generic_header_name_property_add(mrcp_message_t *mrcp_message, size_t id)
+{
+       mrcp_header_name_property_add(&mrcp_message->header.generic_header_accessor,id);
+}
+
+/** Check MRCP generic-header proprerty */
+static APR_INLINE apt_bool_t mrcp_generic_header_property_check(mrcp_message_t *mrcp_message, size_t id)
+{
+       return mrcp_header_property_check(&mrcp_message->header.generic_header_accessor,id);
+}
+
+
+/** Get MRCP resource-header */
+static APR_INLINE void* mrcp_resource_header_get(const mrcp_message_t *mrcp_message)
+{
+       return mrcp_message->header.resource_header_accessor.data;
+}
+
+/** Prepare MRCP resource-header */
+static APR_INLINE void* mrcp_resource_header_prepare(mrcp_message_t *mrcp_message)
+{
+       return mrcp_header_allocate(&mrcp_message->header.resource_header_accessor,mrcp_message->pool);
+}
+
+/** Add MRCP resource-header proprerty */
+static APR_INLINE void mrcp_resource_header_property_add(mrcp_message_t *mrcp_message, size_t id)
+{
+       mrcp_header_property_add(&mrcp_message->header.resource_header_accessor,id);
+}
+
+/** Add MRCP resource-header name only proprerty (should be used to construct empty headers in case of GET-PARAMS request) */
+static APR_INLINE void mrcp_resource_header_name_property_add(mrcp_message_t *mrcp_message, size_t id)
+{
+       mrcp_header_name_property_add(&mrcp_message->header.resource_header_accessor,id);
+}
+
+/** Check MRCP resource-header proprerty */
+static APR_INLINE apt_bool_t mrcp_resource_header_property_check(mrcp_message_t *mrcp_message, size_t id)
+{
+       return mrcp_header_property_check(&mrcp_message->header.resource_header_accessor,id);
+}
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_MESSAGE_H__*/
diff --git a/libs/unimrcp/libs/mrcp/message/src/mrcp_generic_header.c b/libs/unimrcp/libs/mrcp/message/src/mrcp_generic_header.c
new file mode 100644 (file)
index 0000000..fe1b796
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mrcp_generic_header.h"
+
+/** String table of mrcp generic-header fields (mrcp_generic_header_id) */
+static const apt_str_table_item_t generic_header_string_table[] = {
+       {{"Active-Request-Id-List",    22},3},
+       {{"Proxy-Sync-Id",             13},0},
+       {{"Accept-Charset",            14},7},
+       {{"Content-Type",              12},9},
+       {{"Content-Id",                10},9},
+       {{"Content-Base",              12},8},
+       {{"Content-Encoding",          16},9},
+       {{"Content-Location",          16},9},
+       {{"Content-Length",            14},10},
+       {{"Cache-Control",             13},1},
+       {{"Logging-Tag",               11},0},
+       {{"Vendor-Specific-Parameters",26},0},
+       {{"Accept",                     6},6},
+       {{"Fetch-Timeout",             13},0},
+       {{"Set-Cookie",                10},10},
+       {{"Set-Cookie2",               11},10}
+};
+
+
+/** Parse mrcp request-id list */
+static apt_bool_t mrcp_request_id_list_parse(mrcp_request_id_list_t *request_id_list, const apt_str_t *value)
+{
+       apt_str_t field;
+       apt_text_stream_t stream;
+       stream.text = *value;
+       stream.pos = stream.text.buf;
+       request_id_list->count = 0;
+       while(request_id_list->count < MAX_ACTIVE_REQUEST_ID_COUNT) {
+               if(apt_text_field_read(&stream,',',TRUE,&field) == FALSE) {
+                       break;
+               }
+               request_id_list->ids[request_id_list->count] = apt_size_value_parse(&field);
+               request_id_list->count++;
+       }
+       return TRUE;
+}
+
+/** Generate mrcp request-id list */
+static apt_bool_t mrcp_request_id_list_generate(mrcp_request_id_list_t *request_id_list, apt_text_stream_t *stream)
+{
+       size_t i;
+       for(i=0; i<request_id_list->count; i++) {
+               apt_size_value_generate(request_id_list->ids[i],stream);
+               if(i < request_id_list->count-1) {
+                       *stream->pos++ = ',';
+               }
+       }
+       return TRUE;
+}
+
+
+/** Initialize generic-header */
+static void mrcp_generic_header_init(mrcp_generic_header_t *generic_header)
+{
+       generic_header->active_request_id_list.count = 0;
+       apt_string_reset(&generic_header->proxy_sync_id);
+       apt_string_reset(&generic_header->accept_charset);
+       apt_string_reset(&generic_header->content_type);
+       apt_string_reset(&generic_header->content_id);
+       apt_string_reset(&generic_header->content_base);
+       apt_string_reset(&generic_header->content_encoding);
+       apt_string_reset(&generic_header->content_location);
+       generic_header->content_length = 0;
+       apt_string_reset(&generic_header->cache_control);
+       apt_string_reset(&generic_header->logging_tag);
+       generic_header->vendor_specific_params = NULL;
+       /* initializes additionnal MRCP V2 generic headers */
+       apt_string_reset(&generic_header->accept);
+       generic_header->fetch_timeout = 0;
+       apt_string_reset(&generic_header->set_cookie);
+       apt_string_reset(&generic_header->set_cookie2);
+}
+
+
+/** Allocate generic-header */
+static void* mrcp_generic_header_allocate(mrcp_header_accessor_t *accessor, apr_pool_t *pool)
+{
+       mrcp_generic_header_t *generic_header = apr_palloc(pool,sizeof(mrcp_generic_header_t));
+       mrcp_generic_header_init(generic_header);
+       accessor->data = generic_header;
+       return accessor->data;
+}
+
+/** Parse generic-header */
+static apt_bool_t mrcp_generic_header_parse(mrcp_header_accessor_t *accessor, size_t id, const apt_str_t *value, apr_pool_t *pool)
+{
+       apt_bool_t status = TRUE;
+       mrcp_generic_header_t *generic_header = accessor->data;
+       switch(id) {
+               case GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST:
+                       mrcp_request_id_list_parse(&generic_header->active_request_id_list,value);
+                       break;
+               case GENERIC_HEADER_PROXY_SYNC_ID:
+                       apt_string_copy(&generic_header->proxy_sync_id,value,pool);
+                       break;
+               case GENERIC_HEADER_ACCEPT_CHARSET:
+                       apt_string_copy(&generic_header->accept_charset,value,pool);
+                       break;
+               case GENERIC_HEADER_CONTENT_TYPE:
+                       apt_string_copy(&generic_header->content_type,value,pool);
+                       break;
+               case GENERIC_HEADER_CONTENT_ID:
+                       apt_string_copy(&generic_header->content_id,value,pool);
+                       break;
+               case GENERIC_HEADER_CONTENT_BASE:
+                       apt_string_copy(&generic_header->content_base,value,pool);
+                       break;
+               case GENERIC_HEADER_CONTENT_ENCODING:
+                       apt_string_copy(&generic_header->content_encoding,value,pool);
+                       break;
+               case GENERIC_HEADER_CONTENT_LOCATION:
+                       apt_string_copy(&generic_header->content_location,value,pool);
+                       break;
+               case GENERIC_HEADER_CONTENT_LENGTH:
+                       generic_header->content_length = apt_size_value_parse(value);
+                       break;
+               case GENERIC_HEADER_CACHE_CONTROL:
+                       apt_string_copy(&generic_header->cache_control,value,pool);
+                       break;
+               case GENERIC_HEADER_LOGGING_TAG:
+                       apt_string_copy(&generic_header->logging_tag,value,pool);
+                       break;
+               case GENERIC_HEADER_VENDOR_SPECIFIC_PARAMS:
+                       if(!generic_header->vendor_specific_params) {
+                               generic_header->vendor_specific_params = apt_pair_array_create(1,pool);
+                       }
+                       apt_pair_array_parse(generic_header->vendor_specific_params,value,pool);
+                       break;
+               case GENERIC_HEADER_ACCEPT:
+                       apt_string_copy(&generic_header->accept,value,pool);
+                       break;
+               case GENERIC_HEADER_FETCH_TIMEOUT:
+                       generic_header->fetch_timeout = apt_size_value_parse(value);
+                       break;
+               case GENERIC_HEADER_SET_COOKIE:
+                       apt_string_copy(&generic_header->set_cookie,value,pool);
+                       break;
+               case GENERIC_HEADER_SET_COOKIE2:
+                       apt_string_copy(&generic_header->set_cookie2,value,pool);
+                       break;
+               default:
+                       status = FALSE;
+       }
+       return status;
+}
+
+/** Generate generic-header */
+static apt_bool_t mrcp_generic_header_generate(mrcp_header_accessor_t *accessor, size_t id, apt_text_stream_t *value)
+{
+       mrcp_generic_header_t *generic_header = accessor->data;
+       switch(id) {
+               case GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST:
+                       mrcp_request_id_list_generate(&generic_header->active_request_id_list,value);
+                       break;
+               case GENERIC_HEADER_PROXY_SYNC_ID:
+                       apt_string_value_generate(&generic_header->proxy_sync_id,value);
+                       break;
+               case GENERIC_HEADER_ACCEPT_CHARSET:
+                       apt_string_value_generate(&generic_header->accept_charset,value);
+                       break;
+               case GENERIC_HEADER_CONTENT_TYPE:
+                       apt_string_value_generate(&generic_header->content_type,value);
+                       break;
+               case GENERIC_HEADER_CONTENT_ID:
+                       apt_string_value_generate(&generic_header->content_id,value);
+                       break;
+               case GENERIC_HEADER_CONTENT_BASE:
+                       apt_string_value_generate(&generic_header->content_base,value);
+                       break;
+               case GENERIC_HEADER_CONTENT_ENCODING:
+                       apt_string_value_generate(&generic_header->content_encoding,value);
+                       break;
+               case GENERIC_HEADER_CONTENT_LOCATION:
+                       apt_string_value_generate(&generic_header->content_location,value);
+                       break;
+               case GENERIC_HEADER_CONTENT_LENGTH:
+                       apt_size_value_generate(generic_header->content_length,value);
+                       break;
+               case GENERIC_HEADER_CACHE_CONTROL:
+                       apt_string_value_generate(&generic_header->cache_control,value);
+                       break;
+               case GENERIC_HEADER_LOGGING_TAG:
+                       apt_string_value_generate(&generic_header->logging_tag,value);
+                       break;
+               case GENERIC_HEADER_VENDOR_SPECIFIC_PARAMS:
+                       apt_pair_array_generate(generic_header->vendor_specific_params,value);
+                       break;
+               case GENERIC_HEADER_ACCEPT:
+                       apt_string_value_generate(&generic_header->accept,value);
+                       break;
+               case GENERIC_HEADER_FETCH_TIMEOUT:
+                       apt_size_value_generate(generic_header->fetch_timeout,value);
+                       break;
+               case GENERIC_HEADER_SET_COOKIE:
+                       apt_string_value_generate(&generic_header->set_cookie,value);
+                       break;
+               case GENERIC_HEADER_SET_COOKIE2:
+                       apt_string_value_generate(&generic_header->set_cookie2,value);
+                       break;
+               default:
+                       break;
+       }
+       return TRUE;
+}
+
+/** Duplicate generic-header */
+static apt_bool_t mrcp_generic_header_duplicate(mrcp_header_accessor_t *accessor, const mrcp_header_accessor_t *src, size_t id, apr_pool_t *pool)
+{
+       mrcp_generic_header_t *generic_header = accessor->data;
+       const mrcp_generic_header_t *src_generic_header = src->data;
+       apt_bool_t status = TRUE;
+
+       if(!generic_header || !src_generic_header) {
+               return FALSE;
+       }
+
+       switch(id) {
+               case GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST:
+                       break;
+               case GENERIC_HEADER_PROXY_SYNC_ID:
+                       apt_string_copy(&generic_header->proxy_sync_id,&src_generic_header->proxy_sync_id,pool);
+                       break;
+               case GENERIC_HEADER_ACCEPT_CHARSET:
+                       apt_string_copy(&generic_header->accept_charset,&src_generic_header->accept_charset,pool);
+                       break;
+               case GENERIC_HEADER_CONTENT_TYPE:
+                       apt_string_copy(&generic_header->content_type,&src_generic_header->content_type,pool);
+                       break;
+               case GENERIC_HEADER_CONTENT_ID:
+                       apt_string_copy(&generic_header->content_id,&src_generic_header->content_id,pool);
+                       break;
+               case GENERIC_HEADER_CONTENT_BASE:
+                       apt_string_copy(&generic_header->content_base,&src_generic_header->content_base,pool);
+                       break;
+               case GENERIC_HEADER_CONTENT_ENCODING:
+                       apt_string_copy(&generic_header->content_encoding,&src_generic_header->content_encoding,pool);
+                       break;
+               case GENERIC_HEADER_CONTENT_LOCATION:
+                       apt_string_copy(&generic_header->content_location,&src_generic_header->content_location,pool);
+                       break;
+               case GENERIC_HEADER_CONTENT_LENGTH:
+                       generic_header->content_length = src_generic_header->content_length;
+                       break;
+               case GENERIC_HEADER_CACHE_CONTROL:
+                       apt_string_copy(&generic_header->cache_control,&src_generic_header->cache_control,pool);
+                       break;
+               case GENERIC_HEADER_LOGGING_TAG:
+                       apt_string_copy(&generic_header->logging_tag,&src_generic_header->logging_tag,pool);
+                       break;
+               case GENERIC_HEADER_VENDOR_SPECIFIC_PARAMS:
+                       generic_header->vendor_specific_params = apt_pair_array_copy(src_generic_header->vendor_specific_params,pool);
+                       break;
+               case GENERIC_HEADER_ACCEPT:
+                       apt_string_copy(&generic_header->accept,&src_generic_header->accept,pool);
+                       break;
+               case GENERIC_HEADER_FETCH_TIMEOUT:
+                       generic_header->fetch_timeout = src_generic_header->fetch_timeout;
+                       break;
+               case GENERIC_HEADER_SET_COOKIE:
+                       apt_string_copy(&generic_header->set_cookie,&src_generic_header->set_cookie,pool);
+                       break;
+               case GENERIC_HEADER_SET_COOKIE2:
+                       apt_string_copy(&generic_header->set_cookie2,&src_generic_header->set_cookie2,pool);
+                       break;
+               default:
+                       status = FALSE;
+       }
+       return status;
+}
+
+static const mrcp_header_vtable_t vtable = {
+       mrcp_generic_header_allocate,
+       NULL, /* nothing to destroy */
+       mrcp_generic_header_parse,
+       mrcp_generic_header_generate,
+       mrcp_generic_header_duplicate,
+       generic_header_string_table,
+       GENERIC_HEADER_COUNT
+};
+
+
+MRCP_DECLARE(const mrcp_header_vtable_t*) mrcp_generic_header_vtable_get(mrcp_version_e version)
+{
+       return &vtable;
+}
+
+
+/** Append active request id list */
+MRCP_DECLARE(apt_bool_t) active_request_id_list_append(mrcp_generic_header_t *generic_header, mrcp_request_id request_id)
+{
+       mrcp_request_id_list_t *request_id_list = &generic_header->active_request_id_list;
+       if(request_id_list->count >= MAX_ACTIVE_REQUEST_ID_COUNT) {
+               return FALSE;
+       }
+       request_id_list->ids[request_id_list->count++] = request_id;
+       return TRUE;
+}
+
+/** Find request id in active request id list */
+MRCP_DECLARE(apt_bool_t) active_request_id_list_find(mrcp_generic_header_t *generic_header, mrcp_request_id request_id)
+{
+       size_t i;
+       mrcp_request_id_list_t *request_id_list = &generic_header->active_request_id_list;
+       for(i=0; i<request_id_list->count; i++) {
+               if(request_id_list->ids[i] == request_id) {
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
diff --git a/libs/unimrcp/libs/mrcp/message/src/mrcp_header_accessor.c b/libs/unimrcp/libs/mrcp/message/src/mrcp_header_accessor.c
new file mode 100644 (file)
index 0000000..e721900
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mrcp_header_accessor.h"
+
+typedef enum {
+       MRCP_HEADER_FIELD_NONE       = 0x0,
+       MRCP_HEADER_FIELD_NAME       = 0x1,
+       MRCP_HEADER_FIELD_VALUE      = 0x2,
+       MRCP_HEADER_FIELD_NAME_VALUE = MRCP_HEADER_FIELD_NAME | MRCP_HEADER_FIELD_VALUE
+} mrcp_header_property_e;
+
+
+MRCP_DECLARE(apt_bool_t) mrcp_header_parse(mrcp_header_accessor_t *accessor, const apt_pair_t *pair, apr_pool_t *pool)
+{
+       size_t id;
+       if(!accessor->vtable) {
+               return FALSE;
+       }
+
+       id = apt_string_table_id_find(accessor->vtable->field_table,accessor->vtable->field_count,&pair->name);
+       if(id >= accessor->vtable->field_count) {
+               return FALSE;
+       }
+
+       if(!pair->value.length) {
+               mrcp_header_name_property_add(accessor,id);
+               return TRUE;
+       }
+
+       if(accessor->vtable->parse_field(accessor,id,&pair->value,pool) == FALSE) {
+               return FALSE;
+       }
+       
+       mrcp_header_property_add(accessor,id);
+       return TRUE;
+}
+
+MRCP_DECLARE(apt_bool_t) mrcp_header_generate(mrcp_header_accessor_t *accessor, apt_text_stream_t *text_stream)
+{
+       const apt_str_t *name;
+       apr_size_t i,j;
+       char prop;
+
+       if(!accessor->vtable) {
+               return FALSE;
+       }
+
+       for(i=0, j=0; i<accessor->vtable->field_count && j<accessor->counter; i++) {
+               prop = accessor->properties[i];
+               if((prop & MRCP_HEADER_FIELD_NAME) == MRCP_HEADER_FIELD_NAME) {
+                       j++;
+                       name = apt_string_table_str_get(accessor->vtable->field_table,accessor->vtable->field_count,i);
+                       if(!name) continue;
+                       
+                       apt_text_header_name_generate(name,text_stream);
+                       if((prop & MRCP_HEADER_FIELD_VALUE) == MRCP_HEADER_FIELD_VALUE) {
+                               accessor->vtable->generate_field(accessor,i,text_stream);
+                       }
+                       apt_text_eol_insert(text_stream);
+               }
+       }
+
+       return TRUE;
+}
+
+MRCP_DECLARE(void) mrcp_header_property_add(mrcp_header_accessor_t *accessor, apr_size_t id)
+{
+       if(id < accessor->vtable->field_count) {
+               char *prop = &accessor->properties[id];
+               if((*prop & MRCP_HEADER_FIELD_NAME) != MRCP_HEADER_FIELD_NAME) {
+                       accessor->counter++;
+               }
+               *prop = MRCP_HEADER_FIELD_NAME_VALUE;
+       }
+}
+
+MRCP_DECLARE(void) mrcp_header_name_property_add(mrcp_header_accessor_t *accessor, apr_size_t id)
+{
+       if(id < accessor->vtable->field_count) {
+               char *prop = &accessor->properties[id];
+               if((*prop & MRCP_HEADER_FIELD_NAME) != MRCP_HEADER_FIELD_NAME) {
+                       *prop = MRCP_HEADER_FIELD_NAME;
+                       accessor->counter++;
+               }
+       }
+}
+
+
+MRCP_DECLARE(void) mrcp_header_property_remove(mrcp_header_accessor_t *accessor, apr_size_t id)
+{
+       if(id < accessor->vtable->field_count) {
+               char *prop = &accessor->properties[id];
+               if((*prop & MRCP_HEADER_FIELD_NAME) == MRCP_HEADER_FIELD_NAME) {
+                       accessor->counter--;
+               }
+               *prop = MRCP_HEADER_FIELD_NONE;
+       }
+}
+
+MRCP_DECLARE(apt_bool_t) mrcp_header_property_check(mrcp_header_accessor_t *accessor, apr_size_t id)
+{
+       if((id < accessor->vtable->field_count) && accessor->properties) {
+               if((accessor->properties[id] & MRCP_HEADER_FIELD_NAME) == MRCP_HEADER_FIELD_NAME) {
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+
+MRCP_DECLARE(apt_bool_t) mrcp_header_set(mrcp_header_accessor_t *accessor, const mrcp_header_accessor_t *src, const mrcp_header_accessor_t *mask, apr_pool_t *pool)
+{
+       apr_size_t i,j;
+
+       if(!accessor->vtable || !src->vtable) {
+               return FALSE;
+       }
+
+       mrcp_header_allocate(accessor,pool);
+
+       for(i=0, j=0; i < src->vtable->field_count && j < src->counter; i++) {
+               if((mask->properties[i] & src->properties[i] & MRCP_HEADER_FIELD_NAME) == MRCP_HEADER_FIELD_NAME) {
+                       j++;
+                       if((src->properties[i] & MRCP_HEADER_FIELD_VALUE) == MRCP_HEADER_FIELD_VALUE) {
+                               accessor->vtable->duplicate_field(accessor,src,i,pool);
+                               mrcp_header_property_add(accessor,i);
+                       }
+                       else {
+                               mrcp_header_name_property_add(accessor,i);
+                       }
+               }
+       }
+
+       return TRUE;
+}
+
+MRCP_DECLARE(apt_bool_t) mrcp_header_inherit(mrcp_header_accessor_t *accessor, const mrcp_header_accessor_t *parent, apr_pool_t *pool)
+{
+       apr_size_t i,j;
+
+       if(!accessor->vtable || !parent->vtable) {
+               return FALSE;
+       }
+
+       mrcp_header_allocate(accessor,pool);
+
+       for(i=0, j=0; i<parent->vtable->field_count && j < parent->counter; i++) {
+               if((parent->properties[i] & MRCP_HEADER_FIELD_NAME) == MRCP_HEADER_FIELD_NAME) {
+                       j++;
+                       if((parent->properties[i] & MRCP_HEADER_FIELD_VALUE) == MRCP_HEADER_FIELD_VALUE) {
+                               accessor->vtable->duplicate_field(accessor,parent,i,pool);
+                               mrcp_header_property_add(accessor,i);
+                       }
+                       else {
+                               mrcp_header_name_property_add(accessor,i);
+                       }
+               }
+       }
+
+       return TRUE;
+}
diff --git a/libs/unimrcp/libs/mrcp/message/src/mrcp_message.c b/libs/unimrcp/libs/mrcp/message/src/mrcp_message.c
new file mode 100644 (file)
index 0000000..dbe8627
--- /dev/null
@@ -0,0 +1,691 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mrcp_message.h"
+#include "mrcp_generic_header.h"
+#include "apt_log.h"
+
+/** Protocol name used in version string */
+#define MRCP_NAME               "MRCP"
+#define MRCP_NAME_LENGTH        (sizeof(MRCP_NAME)-1)
+
+#define MRCP_CHANNEL_ID         "Channel-Identifier"
+#define MRCP_CHANNEL_ID_LENGTH  (sizeof(MRCP_CHANNEL_ID)-1)
+
+/** Separators used in MRCP version string parse/generate */
+#define MRCP_NAME_VERSION_SEPARATOR        '/'
+#define MRCP_VERSION_MAJOR_MINOR_SEPARATOR '.'
+
+#define MRCP_MESSAGE_LENGTH_MAX_DIGITS_COUNT 4
+
+
+/** String table of MRCP request-states (mrcp_request_state_t) */
+static const apt_str_table_item_t mrcp_request_state_string_table[] = {
+       {{"COMPLETE",    8},0},
+       {{"IN-PROGRESS",11},0},
+       {{"PENDING",     7},0}
+};
+
+
+/** Parse MRCP version */
+static mrcp_version_e mrcp_version_parse(const apt_str_t *field)
+{
+       mrcp_version_e version = MRCP_VERSION_UNKNOWN;
+       const char *pos;
+       if(field->length <= MRCP_NAME_LENGTH || strncasecmp(field->buf,MRCP_NAME,MRCP_NAME_LENGTH) != 0) {
+               /* unexpected protocol name */
+               return version;
+       }
+
+       pos = field->buf + MRCP_NAME_LENGTH;
+       if(*pos == MRCP_NAME_VERSION_SEPARATOR) {
+               pos++;
+               switch(*pos) {
+                       case '1': version = MRCP_VERSION_1; break;
+                       case '2': version = MRCP_VERSION_2; break;
+                       default: ;
+               }
+       }
+       return version;
+}
+
+/** Generate MRCP version */
+static apt_bool_t mrcp_version_generate(mrcp_version_e version, apt_text_stream_t *stream)
+{
+       memcpy(stream->pos,MRCP_NAME,MRCP_NAME_LENGTH);
+       stream->pos += MRCP_NAME_LENGTH;
+       *stream->pos++ = MRCP_NAME_VERSION_SEPARATOR;
+       apt_size_value_generate(version,stream);
+       *stream->pos++ = MRCP_VERSION_MAJOR_MINOR_SEPARATOR;
+       *stream->pos++ = '0';
+       return TRUE;
+}
+
+/** Parse MRCP request-state used in MRCP response and event */
+static APR_INLINE mrcp_request_state_e mrcp_request_state_parse(const apt_str_t *request_state_str)
+{
+       return apt_string_table_id_find(mrcp_request_state_string_table,MRCP_REQUEST_STATE_COUNT,request_state_str);
+}
+
+/** Generate MRCP request-state used in MRCP response and event */
+static apt_bool_t mrcp_request_state_generate(mrcp_request_state_e request_state, apt_text_stream_t *stream)
+{
+       const apt_str_t *name;
+       name = apt_string_table_str_get(mrcp_request_state_string_table,MRCP_REQUEST_STATE_COUNT,request_state);
+       if(request_state < MRCP_REQUEST_STATE_COUNT) {
+               memcpy(stream->pos,name->buf,name->length);
+               stream->pos += name->length;
+       }
+       return TRUE;
+}
+
+
+/** Parse MRCP request-id */
+static APR_INLINE mrcp_request_id mrcp_request_id_parse(const apt_str_t *field)
+{
+       return apt_size_value_parse(field);
+}
+
+/** Generate MRCP request-id */
+static APR_INLINE apt_bool_t mrcp_request_id_generate(mrcp_request_id request_id, apt_text_stream_t *stream)
+{
+       return apt_size_value_generate(request_id,stream);
+}
+
+/** Parse MRCP status-code */
+static APR_INLINE mrcp_status_code_e mrcp_status_code_parse(const apt_str_t *field)
+{
+       return apt_size_value_parse(field);
+}
+
+/** Generate MRCP status-code */
+static APR_INLINE size_t  mrcp_status_code_generate(mrcp_status_code_e status_code, apt_text_stream_t *stream)
+{
+       return apt_size_value_generate(status_code,stream);
+}
+
+
+/** Parse MRCP request-line */
+static apt_bool_t mrcp_request_line_parse(mrcp_start_line_t *start_line, apt_text_stream_t *stream)
+{
+       apt_str_t field;
+       if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse request-id in request-line");
+               return FALSE;
+       }
+       start_line->request_id = mrcp_request_id_parse(&field);
+
+       if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse mrcp-version in request-line");
+               return FALSE;
+       }
+
+       start_line->request_state = mrcp_request_state_parse(&field);
+       if(start_line->request_state == MRCP_REQUEST_STATE_UNKNOWN) {
+               /* request-line */
+               start_line->message_type = MRCP_MESSAGE_TYPE_REQUEST;
+       }
+       else {
+               /* event line */
+               start_line->message_type = MRCP_MESSAGE_TYPE_EVENT;
+
+               if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse mrcp-version in request-line");
+                       return FALSE;
+               }
+       }
+
+       start_line->version = mrcp_version_parse(&field);
+       if(start_line->version == MRCP_VERSION_UNKNOWN) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown mrcp-version");
+               return FALSE;
+       }
+       return TRUE;
+}
+
+/** Generate MRCP request-line */
+static apt_bool_t mrcp_request_line_generate(mrcp_start_line_t *start_line, apt_text_stream_t *stream)
+{
+       memcpy(stream->pos,start_line->method_name.buf,start_line->method_name.length);
+       stream->pos += start_line->method_name.length;
+       *stream->pos++ = APT_TOKEN_SP;
+
+       mrcp_request_id_generate(start_line->request_id,stream);
+       *stream->pos++ = APT_TOKEN_SP;
+
+       if(start_line->message_type == MRCP_MESSAGE_TYPE_REQUEST) {
+               if(start_line->status_code != MRCP_STATUS_CODE_UNKNOWN) {
+                       mrcp_status_code_generate(start_line->status_code,stream);
+                       *stream->pos++ = APT_TOKEN_SP;
+               }
+       }
+       else if(start_line->message_type == MRCP_MESSAGE_TYPE_EVENT) {
+               mrcp_request_state_generate(start_line->request_state,stream);
+               *stream->pos++ = APT_TOKEN_SP;
+       }
+
+       mrcp_version_generate(start_line->version,stream);
+       return TRUE;
+}
+
+/** Parse MRCP response-line */
+static apt_bool_t mrcp_response_line_parse(mrcp_start_line_t *start_line, apt_text_stream_t *stream)
+{
+       apt_str_t field;
+       start_line->length = 0;
+       if(start_line->version == MRCP_VERSION_2) {
+               if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse message-length in response-line");
+                       return FALSE;
+               }
+               start_line->length = apt_size_value_parse(&field);
+       }
+
+       if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse request-id in response-line");
+               return FALSE;
+       }
+       start_line->request_id = mrcp_request_id_parse(&field);
+
+       if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse status-code in response-line");
+               return FALSE;
+       }
+       start_line->status_code = mrcp_status_code_parse(&field);
+
+       if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse request-state in response-line");
+               return FALSE;
+       }
+       start_line->request_state = mrcp_request_state_parse(&field);
+       return TRUE;
+}
+
+/** Generate MRCP response-line */
+static apt_bool_t mrcp_response_line_generate(mrcp_start_line_t *start_line, apt_text_stream_t *stream)
+{
+       mrcp_version_generate(start_line->version,stream);
+       *stream->pos++ = APT_TOKEN_SP;
+
+       mrcp_request_id_generate(start_line->request_id,stream);
+       *stream->pos++ = APT_TOKEN_SP;
+
+       mrcp_status_code_generate(start_line->status_code,stream);
+       *stream->pos++ = APT_TOKEN_SP;
+
+       mrcp_request_state_generate(start_line->request_state,stream);
+       return TRUE;
+}
+
+/** Parse MRCP v2 start-line */
+static apt_bool_t mrcp_v2_start_line_parse(mrcp_start_line_t *start_line, apt_text_stream_t *stream, apr_pool_t *pool)
+{
+       apt_str_t field;
+       if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse message-length in v2 start-line");
+               return FALSE;
+       }
+       start_line->length = apt_size_value_parse(&field);
+
+       if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse request-id in v2 start-line");
+               return FALSE;
+       }
+       start_line->request_id = mrcp_request_id_parse(&field);
+       if(start_line->request_id == 0 && *field.buf != '0') {
+               /* parsing MRCP v2 request or event */
+               start_line->message_type = MRCP_MESSAGE_TYPE_REQUEST;
+               apt_string_copy(&start_line->method_name,&field,pool);
+
+               if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse request-id in v2 start-line");
+                       return FALSE;
+               }
+               start_line->request_id = mrcp_request_id_parse(&field);
+
+               if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == TRUE) {
+                       /* parsing MRCP v2 event */
+                       start_line->request_state = mrcp_request_state_parse(&field);
+                       start_line->message_type = MRCP_MESSAGE_TYPE_EVENT;
+               }
+       }
+       else {
+               /* parsing MRCP v2 response */
+               start_line->message_type = MRCP_MESSAGE_TYPE_RESPONSE;
+
+               if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse status-code in v2 start-line");
+                       return FALSE;
+               }
+               start_line->status_code = mrcp_status_code_parse(&field);
+
+               if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse request-state in v2 start-line");
+                       return FALSE;
+               }
+               start_line->request_state = mrcp_request_state_parse(&field);
+       }
+
+       return TRUE;
+}
+
+/** Generate MRCP v2 start-line */
+static apt_bool_t mrcp_v2_start_line_generate(mrcp_start_line_t *start_line, apt_text_stream_t *stream)
+{
+       char *pos = stream->pos;
+       mrcp_version_generate(start_line->version,stream);
+       *stream->pos++ = APT_TOKEN_SP;
+
+       start_line->length = stream->pos - pos; /* length is temrorary used to store offset */
+       /* reserving MRCP_MESSAGE_LENGTH_MAX_DIGITS_COUNT space for start_line->length */
+       memset(stream->pos,APT_TOKEN_SP,MRCP_MESSAGE_LENGTH_MAX_DIGITS_COUNT+1);
+       stream->pos += MRCP_MESSAGE_LENGTH_MAX_DIGITS_COUNT+1;
+
+       if(start_line->message_type == MRCP_MESSAGE_TYPE_RESPONSE) {
+               mrcp_request_id_generate(start_line->request_id,stream);
+               *stream->pos++ = APT_TOKEN_SP;
+
+               mrcp_status_code_generate(start_line->status_code,stream);
+               *stream->pos++ = APT_TOKEN_SP;
+
+               mrcp_request_state_generate(start_line->request_state,stream);
+               *stream->pos++ = APT_TOKEN_SP;
+       }
+       else {
+               memcpy(stream->pos,start_line->method_name.buf,start_line->method_name.length);
+               stream->pos += start_line->method_name.length;
+               *stream->pos++ = APT_TOKEN_SP;
+
+               mrcp_request_id_generate(start_line->request_id,stream);
+               if(start_line->message_type == MRCP_MESSAGE_TYPE_EVENT) {
+                       *stream->pos++ = APT_TOKEN_SP;
+                       mrcp_request_state_generate(start_line->request_state,stream);
+               }
+       }
+       return TRUE;
+}
+
+/** Initialize MRCP start-line */
+MRCP_DECLARE(void) mrcp_start_line_init(mrcp_start_line_t *start_line)
+{
+       start_line->message_type = MRCP_MESSAGE_TYPE_UNKNOWN;
+       start_line->version = MRCP_VERSION_UNKNOWN;
+       start_line->length = 0;
+       start_line->request_id = 0;
+       apt_string_reset(&start_line->method_name);
+       start_line->status_code = MRCP_STATUS_CODE_UNKNOWN;
+       start_line->request_state = MRCP_REQUEST_STATE_UNKNOWN;
+}
+
+/** Parse MRCP start-line */
+MRCP_DECLARE(apt_bool_t) mrcp_start_line_parse(mrcp_start_line_t *start_line, apt_text_stream_t *text_stream, apr_pool_t *pool)
+{
+       apt_text_stream_t line;
+       apt_str_t field;
+       apt_bool_t status = TRUE;
+       start_line->message_type = MRCP_MESSAGE_TYPE_UNKNOWN;
+       if(apt_text_line_read(text_stream,&line.text) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse MRCP start-line");
+               return FALSE;
+       }
+       line.pos = line.text.buf;
+
+       if(apt_text_field_read(&line,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot read the first field in start-line");
+               return FALSE;
+       }
+
+       if(field.buf == strstr(field.buf,MRCP_NAME)) {
+               start_line->version = mrcp_version_parse(&field);
+
+               if(start_line->version == MRCP_VERSION_1) {
+                       /* parsing MRCP v1 response */
+                       start_line->message_type = MRCP_MESSAGE_TYPE_RESPONSE;
+                       status = mrcp_response_line_parse(start_line,&line);
+               }
+               else if(start_line->version == MRCP_VERSION_2) {
+                       /* parsing MRCP v2 start-line (request/response/event) */
+                       status = mrcp_v2_start_line_parse(start_line,&line,pool);
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown MRCP version");
+                       return FALSE;
+               }
+       }
+       else {
+               /* parsing MRCP v1 request or event */
+               apt_string_copy(&start_line->method_name,&field,pool);
+               status = mrcp_request_line_parse(start_line,&line);
+       }
+       return status;
+}
+
+/** Generate MRCP start-line */
+MRCP_DECLARE(apt_bool_t) mrcp_start_line_generate(mrcp_start_line_t *start_line, apt_text_stream_t *text_stream)
+{
+       apt_bool_t status = FALSE;
+       if(start_line->version == MRCP_VERSION_1) {
+               switch(start_line->message_type) {
+                       case MRCP_MESSAGE_TYPE_REQUEST:
+                               status = mrcp_request_line_generate(start_line,text_stream);
+                               break;
+                       case MRCP_MESSAGE_TYPE_RESPONSE:
+                               status = mrcp_response_line_generate(start_line,text_stream);
+                               break;
+                       case MRCP_MESSAGE_TYPE_EVENT:
+                               status = mrcp_request_line_generate(start_line,text_stream);
+                               break;
+                       default:
+                               break;
+               }
+       }
+       else if(start_line->version == MRCP_VERSION_2) {
+               status = mrcp_v2_start_line_generate(start_line,text_stream);
+       }
+
+       if(status == TRUE) {
+               apt_text_eol_insert(text_stream);
+       }
+       
+       return status;
+}
+
+/** Finalize MRCP start-line generation */
+MRCP_DECLARE(apt_bool_t) mrcp_start_line_finalize(mrcp_start_line_t *start_line, apr_size_t content_length, apt_text_stream_t *text_stream)
+{
+       apr_size_t length = text_stream->pos - text_stream->text.buf + content_length;
+       if(start_line->version == MRCP_VERSION_2) {
+               /* message-length includes the number of bytes that specify the message-length in the header */
+               /* too comlex to generate!!! see the discussion */
+               /* http://www1.ietf.org/mail-archive/web/speechsc/current/msg01734.html */
+               apt_str_t field;
+               field.buf = text_stream->text.buf + start_line->length; /* length is temrorary used to store offset */
+               length -= MRCP_MESSAGE_LENGTH_MAX_DIGITS_COUNT;
+               apt_var_length_value_generate(&length,MRCP_MESSAGE_LENGTH_MAX_DIGITS_COUNT,&field);
+               field.buf[field.length] = APT_TOKEN_SP;
+               start_line->length += field.length;
+
+               field.length = MRCP_MESSAGE_LENGTH_MAX_DIGITS_COUNT - field.length;
+               if(field.length) {
+                       memmove(text_stream->text.buf+field.length,text_stream->text.buf,start_line->length);
+                       text_stream->text.buf += field.length;
+                       text_stream->text.length -= field.length;
+               }
+       }
+
+       start_line->length = length;
+       return TRUE;
+}
+
+/** Initialize MRCP channel-identifier */
+MRCP_DECLARE(void) mrcp_channel_id_init(mrcp_channel_id *channel_id)
+{
+       apt_string_reset(&channel_id->session_id);
+       apt_string_reset(&channel_id->resource_name);
+       channel_id->resource_id = 0;
+}
+
+/** Parse MRCP channel-identifier */
+MRCP_DECLARE(apt_bool_t) mrcp_channel_id_parse(mrcp_channel_id *channel_id, apt_text_stream_t *text_stream, apr_pool_t *pool)
+{
+       apt_bool_t match = FALSE;
+       apt_pair_t pair;
+       do {
+               if(apt_text_header_read(text_stream,&pair) == TRUE) {
+                       if(pair.name.length) {
+                               if(pair.value.length && strncasecmp(pair.name.buf,MRCP_CHANNEL_ID,MRCP_CHANNEL_ID_LENGTH) == 0) {
+                                       match = TRUE;
+                                       apt_id_resource_parse(&pair.value,'@',&channel_id->session_id,&channel_id->resource_name,pool);
+                                       break;
+                               }
+                               /* skip this header, expecting channel identifier first */
+                       }
+                       else {
+                               /* empty header */
+                               break;
+                       }
+               }
+       }
+       while(apt_text_is_eos(text_stream) == FALSE);
+       return match;
+}
+
+/** Generate MRCP channel-identifier */
+MRCP_DECLARE(apt_bool_t) mrcp_channel_id_generate(mrcp_channel_id *channel_id, apt_text_stream_t *text_stream)
+{
+       apt_str_t *str;
+       char *pos = text_stream->pos;
+
+       memcpy(pos,MRCP_CHANNEL_ID,MRCP_CHANNEL_ID_LENGTH);
+       pos += MRCP_CHANNEL_ID_LENGTH;
+       *pos++ = ':';
+       *pos++ = ' ';
+       
+       str = &channel_id->session_id;
+       memcpy(pos,str->buf,str->length);
+       pos += str->length;
+       *pos++ = '@';
+
+       str = &channel_id->resource_name;
+       memcpy(pos,str->buf,str->length);
+       pos += str->length;
+
+       text_stream->pos = pos;
+       apt_text_eol_insert(text_stream);
+       return TRUE;
+}
+
+/** Parse MRCP message-header */
+MRCP_DECLARE(apt_bool_t) mrcp_message_header_parse(mrcp_message_header_t *message_header, apt_text_stream_t *text_stream, apr_pool_t *pool)
+{
+       apt_pair_t pair;
+       apt_bool_t result = FALSE;
+
+       mrcp_header_allocate(&message_header->generic_header_accessor,pool);
+       mrcp_header_allocate(&message_header->resource_header_accessor,pool);
+
+       do {
+               if(apt_text_header_read(text_stream,&pair) == TRUE) {
+                       if(pair.name.length) {
+                               /* normal header */
+                               if(mrcp_header_parse(&message_header->resource_header_accessor,&pair,pool) != TRUE) {
+                                       if(mrcp_header_parse(&message_header->generic_header_accessor,&pair,pool) != TRUE) {
+                                               /* unknown MRCP header */
+                                       }
+                               }
+                       }
+                       else {
+                               /* empty header -> exit */
+                               result = TRUE;
+                               break;
+                       }
+               }
+               else {
+                       /* malformed header, skip to the next one */
+               }
+       }
+       while(apt_text_is_eos(text_stream) == FALSE);
+
+       return result;
+}
+
+/** Generate MRCP message-header */
+MRCP_DECLARE(apt_bool_t) mrcp_message_header_generate(mrcp_message_header_t *message_header, apt_text_stream_t *text_stream)
+{
+       mrcp_header_generate(&message_header->resource_header_accessor,text_stream);
+       mrcp_header_generate(&message_header->generic_header_accessor,text_stream);
+       apt_text_eol_insert(text_stream);
+       return TRUE;
+}
+
+/** Set MRCP message-header */
+MRCP_DECLARE(apt_bool_t) mrcp_message_header_set(mrcp_message_header_t *message_header, const mrcp_message_header_t *src, apr_pool_t *pool)
+{
+       mrcp_header_set(
+               &message_header->resource_header_accessor,
+               &src->resource_header_accessor,
+               &src->resource_header_accessor,pool);
+       mrcp_header_set(
+               &message_header->generic_header_accessor,
+               &src->generic_header_accessor,
+               &src->generic_header_accessor,pool);
+       return TRUE;
+}
+
+/** Get MRCP message-header */
+MRCP_DECLARE(apt_bool_t) mrcp_message_header_get(mrcp_message_header_t *message_header, const mrcp_message_header_t *src, apr_pool_t *pool)
+{
+       mrcp_header_set(
+               &message_header->resource_header_accessor,
+               &src->resource_header_accessor,
+               &message_header->resource_header_accessor,
+               pool);
+       mrcp_header_set(
+               &message_header->generic_header_accessor,
+               &src->generic_header_accessor,
+               &message_header->generic_header_accessor,
+               pool);
+       return TRUE;
+}
+
+/** Inherit MRCP message-header */
+MRCP_DECLARE(apt_bool_t) mrcp_message_header_inherit(mrcp_message_header_t *message_header, const mrcp_message_header_t *parent, apr_pool_t *pool)
+{
+       mrcp_header_inherit(&message_header->resource_header_accessor,&parent->resource_header_accessor,pool);
+       mrcp_header_inherit(&message_header->generic_header_accessor,&parent->generic_header_accessor,pool);
+       return TRUE;
+}
+
+
+/** Parse MRCP message-body */
+MRCP_DECLARE(apt_bool_t) mrcp_body_parse(mrcp_message_t *message, apt_text_stream_t *text_stream, apr_pool_t *pool)
+{
+       if(mrcp_generic_header_property_check(message,GENERIC_HEADER_CONTENT_LENGTH) == TRUE) {
+               mrcp_generic_header_t *generic_header = mrcp_generic_header_get(message);
+               if(generic_header && generic_header->content_length) {
+                       apt_str_t *body = &message->body;
+                       body->length = generic_header->content_length;
+                       if(body->length > (text_stream->text.length - (text_stream->pos - text_stream->text.buf))) {
+                               body->length = text_stream->text.length - (text_stream->pos - text_stream->text.buf);
+                       }
+                       body->buf = apr_pstrmemdup(pool,text_stream->pos,body->length);
+                       text_stream->pos += body->length;
+               }
+       }
+       return TRUE;
+}
+
+/** Generate MRCP message-body */
+MRCP_DECLARE(apt_bool_t) mrcp_body_generate(mrcp_message_t *message, apt_text_stream_t *text_stream)
+{
+       apt_str_t *body = &message->body;
+       if(body->length) {
+               memcpy(text_stream->pos,body->buf,body->length);
+               text_stream->pos += body->length;
+       }
+       return TRUE;
+}
+
+
+/** Create MRCP message */
+MRCP_DECLARE(mrcp_message_t*) mrcp_message_create(apr_pool_t *pool)
+{
+       mrcp_message_t *message = apr_palloc(pool,sizeof(mrcp_message_t));
+       mrcp_message_init(message,pool);
+       return message;
+}
+
+/** Initialize MRCP message */
+MRCP_DECLARE(void) mrcp_message_init(mrcp_message_t *message, apr_pool_t *pool)
+{
+       mrcp_start_line_init(&message->start_line);
+       mrcp_channel_id_init(&message->channel_id);
+       mrcp_message_header_init(&message->header);
+       apt_string_reset(&message->body);
+       message->pool = pool;
+}
+
+/** Initialize response/event message by request message */
+MRCP_DECLARE(void) mrcp_message_init_by_request(mrcp_message_t *message, const mrcp_message_t *request_message)
+{
+       message->channel_id = request_message->channel_id;
+       message->start_line.request_id = request_message->start_line.request_id;
+       message->start_line.version = request_message->start_line.version;
+       message->start_line.method_id = request_message->start_line.method_id;
+       message->header.generic_header_accessor.vtable = request_message->header.generic_header_accessor.vtable;
+       message->header.resource_header_accessor.vtable = request_message->header.resource_header_accessor.vtable;
+}
+
+/** Create MRCP request message */
+MRCP_DECLARE(mrcp_message_t*) mrcp_request_create(mrcp_resource_id resource_id, mrcp_method_id method_id, apr_pool_t *pool)
+{
+       mrcp_message_t *request_message = mrcp_message_create(pool);
+       request_message->start_line.message_type = MRCP_MESSAGE_TYPE_REQUEST;
+       request_message->start_line.method_id = method_id;
+       request_message->channel_id.resource_id = resource_id;
+       return request_message;
+}
+
+/** Create MRCP response message */
+MRCP_DECLARE(mrcp_message_t*) mrcp_response_create(const mrcp_message_t *request_message, apr_pool_t *pool)
+{
+       mrcp_message_t *response_message = mrcp_message_create(pool);
+       if(request_message) {
+               mrcp_message_init_by_request(response_message,request_message);
+       }
+       response_message->start_line.message_type = MRCP_MESSAGE_TYPE_RESPONSE;
+       response_message->start_line.request_state = MRCP_REQUEST_STATE_COMPLETE;
+       response_message->start_line.status_code = MRCP_STATUS_CODE_SUCCESS;
+       return response_message;
+}
+
+/** Create MRCP event message */
+MRCP_DECLARE(mrcp_message_t*) mrcp_event_create(const mrcp_message_t *request_message, mrcp_method_id event_id, apr_pool_t *pool)
+{
+       mrcp_message_t *event_message = mrcp_message_create(pool);
+       if(request_message) {
+               mrcp_message_init_by_request(event_message,request_message);
+       }
+       event_message->start_line.message_type = MRCP_MESSAGE_TYPE_EVENT;
+       event_message->start_line.method_id = event_id;
+       return event_message;
+}
+
+/** Destroy MRCP message */
+MRCP_DECLARE(void) mrcp_message_destroy(mrcp_message_t *message)
+{
+       apt_string_reset(&message->body);
+       mrcp_message_header_destroy(&message->header);
+}
+
+/** Validate MRCP message */
+MRCP_DECLARE(apt_bool_t) mrcp_message_validate(mrcp_message_t *message)
+{
+       if(message->body.length) {
+               /* content length must be specified */
+               mrcp_generic_header_t *generic_header = mrcp_generic_header_prepare(message);
+               if(!generic_header) {
+                       return FALSE;
+               }
+               if(mrcp_generic_header_property_check(message,GENERIC_HEADER_CONTENT_LENGTH) != TRUE ||
+                 !generic_header->content_length) {
+                       generic_header->content_length = message->body.length;
+                       mrcp_generic_header_property_add(message,GENERIC_HEADER_CONTENT_LENGTH);
+               }
+       }
+
+       return TRUE;
+}
diff --git a/libs/unimrcp/libs/mrcp/mrcp.vcproj b/libs/unimrcp/libs/mrcp/mrcp.vcproj
new file mode 100644 (file)
index 0000000..1ea0069
--- /dev/null
@@ -0,0 +1,300 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="mrcp"
+       ProjectGUID="{1C320193-46A6-4B34-9C56-8AB584FC1B56}"
+       RootNamespace="mrcp"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\mrcp.vsprops"
+                       CharacterSet="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories=""
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\mrcp.vsprops"
+                       CharacterSet="1"
+                       WholeProgramOptimization="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories=""
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+                       <File
+                               RelativePath=".\include\mrcp.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_types.h"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="message"
+                       >
+                       <Filter
+                               Name="include"
+                               Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                               >
+                               <File
+                                       RelativePath=".\message\include\mrcp_generic_header.h"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\message\include\mrcp_header_accessor.h"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\message\include\mrcp_message.h"
+                                       >
+                               </File>
+                       </Filter>
+                       <Filter
+                               Name="src"
+                               Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                               >
+                               <File
+                                       RelativePath=".\message\src\mrcp_generic_header.c"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\message\src\mrcp_header_accessor.c"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\message\src\mrcp_message.c"
+                                       >
+                               </File>
+                       </Filter>
+               </Filter>
+               <Filter
+                       Name="control"
+                       >
+                       <Filter
+                               Name="include"
+                               Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                               >
+                               <File
+                                       RelativePath=".\control\include\mrcp_resource.h"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\control\include\mrcp_resource_factory.h"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\control\include\mrcp_state_machine.h"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\control\include\mrcp_stream.h"
+                                       >
+                               </File>
+                       </Filter>
+                       <Filter
+                               Name="src"
+                               Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                               >
+                               <File
+                                       RelativePath=".\control\src\mrcp_resource_factory.c"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\control\src\mrcp_stream.c"
+                                       >
+                               </File>
+                       </Filter>
+               </Filter>
+               <Filter
+                       Name="resources"
+                       >
+                       <Filter
+                               Name="include"
+                               Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                               >
+                               <File
+                                       RelativePath=".\resources\include\mrcp_default_factory.h"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\resources\include\mrcp_recog_header.h"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\resources\include\mrcp_recog_resource.h"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\resources\include\mrcp_recog_state_machine.h"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\resources\include\mrcp_synth_header.h"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\resources\include\mrcp_synth_resource.h"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\resources\include\mrcp_synth_state_machine.h"
+                                       >
+                               </File>
+                       </Filter>
+                       <Filter
+                               Name="src"
+                               Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                               >
+                               <File
+                                       RelativePath=".\resources\src\mrcp_default_factory.c"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\resources\src\mrcp_recog_client_state_machine.c"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\resources\src\mrcp_recog_header.c"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\resources\src\mrcp_recog_resource.c"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\resources\src\mrcp_recog_server_state_machine.c"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\resources\src\mrcp_synth_client_state_machine.c"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\resources\src\mrcp_synth_header.c"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\resources\src\mrcp_synth_resource.c"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath=".\resources\src\mrcp_synth_server_state_machine.c"
+                                       >
+                               </File>
+                       </Filter>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/libs/mrcp/resources/include/mrcp_default_factory.h b/libs/unimrcp/libs/mrcp/resources/include/mrcp_default_factory.h
new file mode 100644 (file)
index 0000000..7820aae
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_DEFAULT_FACTORY_H__
+#define __MRCP_DEFAULT_FACTORY_H__
+
+/**
+ * @file mrcp_default_factory.h
+ * @brief Default MRCP Resource Factory
+ */ 
+
+#include "mrcp_resource_factory.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Create default MRCP resource factory */
+MRCP_DECLARE(mrcp_resource_factory_t*) mrcp_default_factory_create(apr_pool_t *pool);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_DEFAULT_FACTORY_H__*/
diff --git a/libs/unimrcp/libs/mrcp/resources/include/mrcp_recog_header.h b/libs/unimrcp/libs/mrcp/resources/include/mrcp_recog_header.h
new file mode 100644 (file)
index 0000000..1669147
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_RECOG_HEADER_H__
+#define __MRCP_RECOG_HEADER_H__
+
+/**
+ * @file mrcp_recog_header.h
+ * @brief MRCP Recognizer Header
+ */ 
+
+#include "mrcp_types.h"
+#include "mrcp_header_accessor.h"
+
+APT_BEGIN_EXTERN_C
+
+/** MRCP recognizer headers */
+typedef enum {
+       RECOGNIZER_HEADER_CONFIDENCE_THRESHOLD,
+       RECOGNIZER_HEADER_SENSITIVITY_LEVEL,
+       RECOGNIZER_HEADER_SPEED_VS_ACCURACY,
+       RECOGNIZER_HEADER_N_BEST_LIST_LENGTH,
+       RECOGNIZER_HEADER_NO_INPUT_TIMEOUT,
+       RECOGNIZER_HEADER_RECOGNITION_TIMEOUT,
+       RECOGNIZER_HEADER_WAVEFORM_URI,
+       RECOGNIZER_HEADER_COMPLETION_CAUSE,
+       RECOGNIZER_HEADER_RECOGNIZER_CONTEXT_BLOCK,
+       RECOGNIZER_HEADER_START_INPUT_TIMERS,
+       RECOGNIZER_HEADER_SPEECH_COMPLETE_TIMEOUT,
+       RECOGNIZER_HEADER_SPEECH_INCOMPLETE_TIMEOUT,
+       RECOGNIZER_HEADER_DTMF_INTERDIGIT_TIMEOUT,
+       RECOGNIZER_HEADER_DTMF_TERM_TIMEOUT,
+       RECOGNIZER_HEADER_DTMF_TERM_CHAR,
+       RECOGNIZER_HEADER_FAILED_URI,
+       RECOGNIZER_HEADER_FAILED_URI_CAUSE,
+       RECOGNIZER_HEADER_SAVE_WAVEFORM,
+       RECOGNIZER_HEADER_NEW_AUDIO_CHANNEL,
+       RECOGNIZER_HEADER_SPEECH_LANGUAGE,
+
+       /** Additional headers for MRCP v2 */
+       RECOGNIZER_HEADER_INPUT_TYPE,
+       RECOGNIZER_HEADER_INPUT_WAVEFORM_URI,
+       RECOGNIZER_HEADER_COMPLETION_REASON,
+       RECOGNIZER_HEADER_MEDIA_TYPE,
+       RECOGNIZER_HEADER_VER_BUFFER_UTTERANCE,
+       RECOGNIZER_HEADER_RECOGNITION_MODE,
+       RECOGNIZER_HEADER_CANCEL_IF_QUEUE,
+       RECOGNIZER_HEADER_HOTWORD_MAX_DURATION,
+       RECOGNIZER_HEADER_HOTWORD_MIN_DURATION,
+       RECOGNIZER_HEADER_INTERPRET_TEXT,
+       RECOGNIZER_HEADER_DTMF_BUFFER_TIME,
+       RECOGNIZER_HEADER_CLEAR_DTMF_BUFFER,
+       RECOGNIZER_HEADER_EARLY_NO_MATCH,
+
+       RECOGNIZER_HEADER_COUNT
+} mrcp_recognizer_header_id;
+
+
+/** MRCP recognizer completion-cause  */
+typedef enum {
+       RECOGNIZER_COMPLETION_CAUSE_SUCCESS                 = 0,
+       RECOGNIZER_COMPLETION_CAUSE_NO_MATCH                = 1,
+       RECOGNIZER_COMPLETION_CAUSE_NO_INPUT_TIMEOUT        = 2,
+       RECOGNIZER_COMPLETION_CAUSE_RECOGNITION_TIMEOUT     = 3,
+       RECOGNIZER_COMPLETION_CAUSE_GRAM_LOAD_FAILURE       = 4,
+       RECOGNIZER_COMPLETION_CAUSE_GRAM_COMP_FAILURE       = 5,
+       RECOGNIZER_COMPLETION_CAUSE_ERROR                   = 6,
+       RECOGNIZER_COMPLETION_CAUSE_SPEECH_TOO_EARLY        = 7,
+       RECOGNIZER_COMPLETION_CAUSE_TOO_MUCH_SPEECH_TIMEOUT = 8,
+       RECOGNIZER_COMPLETION_CAUSE_URI_FAILURE             = 9,
+       RECOGNIZER_COMPLETION_CAUSE_LANGUAGE_UNSUPPORTED    = 10,
+
+       /** Additional completion-cause for MRCP v2 */
+       RECOGNIZER_COMPLETION_CAUSE_CANCELLED               = 11,
+       RECOGNIZER_COMPLETION_CAUSE_SEMANTICS_FAILURE       = 12,
+       RECOGNIZER_COMPLETION_CAUSE_PARTIAL_MATCH           = 13,
+       RECOGNIZER_COMPLETION_CAUSE_PARTIAL_MATCH_MAXTIME   = 14,
+       RECOGNIZER_COMPLETION_CAUSE_NO_MATCH_MAXTIME        = 15,
+       RECOGNIZER_COMPLETION_CAUSE_GRAM_DEFINITION_FAILURE = 16,
+
+       RECOGNIZER_COMPLETION_CAUSE_COUNT                   = 17,
+       RECOGNIZER_COMPLETION_CAUSE_UNKNOWN                 = RECOGNIZER_COMPLETION_CAUSE_COUNT
+} mrcp_recog_completion_cause_e;
+
+
+
+/** MRCP recognizer-header declaration */
+typedef struct mrcp_recog_header_t mrcp_recog_header_t;
+
+/** MRCP recognizer-header */
+struct mrcp_recog_header_t {
+       /** Tells the recognizer resource what confidence level the client considers a
+    successful match */
+       float                         confidence_threshold;
+       /** To filter out background noise and not mistake it for speech */
+       float                         sensitivity_level;
+       /** Tunable towards Performance or Accuracy */
+       float                         speed_vs_accuracy;
+       /** The client, by setting this header, can ask the recognition resource 
+       to send it more  than 1 alternative */
+       apr_size_t                    n_best_list_length;
+       /** The client can use the no-input-timeout header to set this timeout */
+       apr_size_t                    no_input_timeout;
+       /** The client can use the recognition-timeout header to set this timeout */
+       apr_size_t                    recognition_timeout;
+       /** MUST be present in the RECOGNITION-COMPLETE event if the Save-Waveform
+       header was set to true */
+       apt_str_t                     waveform_uri;
+       /** MUST be part of a RECOGNITION-COMPLETE, event coming from
+    the recognizer resource to the client */
+       mrcp_recog_completion_cause_e completion_cause;
+       /** MAY be sent as part of the SET-PARAMS or GET-PARAMS request */
+       apt_str_t                     recognizer_context_block;
+       /** MAY be sent as part of the RECOGNIZE request. A value of false tells
+       the recognizer to start recognition, but not to start the no-input timer yet */
+       apt_bool_t                    start_input_timers;
+       /** Specifies the length of silence required following user
+    speech before the speech recognizer finalizes a result */
+       apr_size_t                    speech_complete_timeout;
+       /** Specifies the required length of silence following user
+    speech after which a recognizer finalizes a result */
+       apr_size_t                    speech_incomplete_timeout;
+       /** Specifies the inter-digit timeout value to use when
+    recognizing DTMF input */
+       apr_size_t                    dtmf_interdigit_timeout;
+       /** Specifies the terminating timeout to use when 
+       recognizing DTMF input*/
+       apr_size_t                    dtmf_term_timeout;
+       /** Specifies the terminating DTMF character for DTMF input
+    recognition */
+       char                          dtmf_term_char;
+       /** When a recognizer needs to fetch or access a URI and the access fails
+    the server SHOULD provide the failed URI in this header in the method response*/
+       apt_str_t                     failed_uri;
+       /** When a recognizer method needs a recognizer to fetch or access a URI
+    and the access fails the server MUST provide the URI specific or
+    protocol specific response code for the URI in the Failed-URI header */
+       apt_str_t                     failed_uri_cause;
+       /** Allows the client to request the recognizer resource to
+    save the audio input to the recognizer */
+       apt_bool_t                    save_waveform;
+       /** MAY be specified in a RECOGNIZE request and allows the
+    client to tell the server that, from this point on, further input
+    audio comes from a different audio source */
+       apt_bool_t                    new_audio_channel;
+       /** Specifies the language of recognition grammar data within
+    a session or request, if it is not specified within the data */
+       apt_str_t                     speech_language;
+
+       /** Additional headers for MRCP v2 */
+       /** Specifies if the input that caused a barge-in was DTMF or speech */
+       apt_str_t                     input_type;
+       /** Optional header specifies a URI pointing to audio content to be
+    processed by the RECOGNIZE operation */
+       apt_str_t                     input_waveform_uri;
+       /** MAY be specified in a RECOGNITION-COMPLETE event coming from
+    the recognizer resource to the client */
+       apt_str_t                     completion_reason;
+       /** tells the server resource the Media Type in which to store captured 
+       audio such as the one captured and returned by the Waveform-URI header */
+       apt_str_t                     media_type;
+       /** lets the client request the server to buffer the
+    utterance associated with this recognition request into a buffer
+    available to a co-resident verification resource */
+       apt_bool_t                    ver_buffer_utterance;
+       /** Specifies what mode the RECOGNIZE method will operate in */
+       apt_str_t                     recognition_mode;
+       /** Specifies what will happen if the client attempts to
+    invoke another RECOGNIZE method when this RECOGNIZE request is
+    already in progress for the resource*/
+       apt_bool_t                    cancel_if_queue;
+       /** Specifies the maximum length of an utterance (in seconds) that will
+    be considered for Hotword recognition */
+       apr_size_t                    hotword_max_duration;
+       /** Specifies the minimum length of an utterance (in seconds) that will
+    be considered for Hotword recognition */
+       apr_size_t                    hotword_min_duration;
+       /** Provides a pointer to the text for which a natural language interpretation is desired */
+       apt_str_t                     interpret_text;
+       /** MAY be specified in a GET-PARAMS or SET-PARAMS method and
+    is used to specify the size in time, in milliseconds, of the
+    typeahead buffer for the recognizer */
+       apr_size_t                    dtmf_buffer_time;
+       /** MAY be specified in a RECOGNIZE method and is used to
+    tell the recognizer to clear the DTMF type-ahead buffer before
+    starting the recognize */
+       apt_bool_t                    clear_dtmf_buffer;
+       /** MAY be specified in a RECOGNIZE method and is used to
+    tell the recognizer that it MUST not wait for the end of speech
+    before processing the collected speech to match active grammars */
+       apt_bool_t                    early_no_match;
+};
+
+
+/** Get recognizer header vtable */
+MRCP_DECLARE(const mrcp_header_vtable_t*) mrcp_recog_header_vtable_get(mrcp_version_e version);
+
+/** Get recognizer completion cause string */
+MRCP_DECLARE(const apt_str_t*) mrcp_recog_completion_cause_get(mrcp_recog_completion_cause_e completion_cause, mrcp_version_e version);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_RECOG_HEADER_H__*/
diff --git a/libs/unimrcp/libs/mrcp/resources/include/mrcp_recog_resource.h b/libs/unimrcp/libs/mrcp/resources/include/mrcp_recog_resource.h
new file mode 100644 (file)
index 0000000..0131e9c
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_RECOG_RESOURCE_H__
+#define __MRCP_RECOG_RESOURCE_H__
+
+/**
+ * @file mrcp_recog_resource.h
+ * @brief MRCP Recognizer Resource
+ */ 
+
+#include "mrcp_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/** MRCP recognizer methods */
+typedef enum {
+       RECOGNIZER_SET_PARAMS,
+       RECOGNIZER_GET_PARAMS,
+       RECOGNIZER_DEFINE_GRAMMAR,
+       RECOGNIZER_RECOGNIZE,
+       RECOGNIZER_GET_RESULT,
+       RECOGNIZER_START_INPUT_TIMERS,
+       RECOGNIZER_STOP,
+
+       RECOGNIZER_METHOD_COUNT
+} mrcp_recognizer_method_id;
+
+/** MRCP recognizer events */
+typedef enum {
+       RECOGNIZER_START_OF_INPUT,
+       RECOGNIZER_RECOGNITION_COMPLETE,
+
+       RECOGNIZER_EVENT_COUNT
+} mrcp_recognizer_event_id;
+
+/** Create MRCP recognizer resource */
+MRCP_DECLARE(mrcp_resource_t*) mrcp_recog_resource_create(apr_pool_t *pool);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_RECOG_RESOURCE_H__*/
diff --git a/libs/unimrcp/libs/mrcp/resources/include/mrcp_recog_state_machine.h b/libs/unimrcp/libs/mrcp/resources/include/mrcp_recog_state_machine.h
new file mode 100644 (file)
index 0000000..0fcbd5e
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_RECOG_STATE_MACHINE_H__
+#define __MRCP_RECOG_STATE_MACHINE_H__
+
+/**
+ * @file mrcp_recog_state_machine.h
+ * @brief MRCP Recognizer State Machine
+ */ 
+
+#include "mrcp_state_machine.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Create MRCP recognizer server state machine */
+mrcp_state_machine_t* mrcp_recog_server_state_machine_create(void *obj, mrcp_message_dispatcher_f dispatcher, mrcp_version_e version, apr_pool_t *pool);
+
+/** Create MRCP recognizer client state machine */
+mrcp_state_machine_t* mrcp_recog_client_state_machine_create(void *obj, mrcp_message_dispatcher_f dispatcher, mrcp_version_e version, apr_pool_t *pool);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_RECOG_STATE_MACHINE_H__*/
diff --git a/libs/unimrcp/libs/mrcp/resources/include/mrcp_synth_header.h b/libs/unimrcp/libs/mrcp/resources/include/mrcp_synth_header.h
new file mode 100644 (file)
index 0000000..f0bf60c
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_SYNTH_HEADER_H__
+#define __MRCP_SYNTH_HEADER_H__
+
+/**
+ * @file mrcp_synth_header.h
+ * @brief MRCP Synthesizer Header
+ */ 
+
+#include "mrcp_types.h"
+#include "mrcp_header_accessor.h"
+
+APT_BEGIN_EXTERN_C
+
+/** MRCP synthesizer headers */
+typedef enum {
+       SYNTHESIZER_HEADER_JUMP_SIZE,
+       SYNTHESIZER_HEADER_KILL_ON_BARGE_IN,
+       SYNTHESIZER_HEADER_SPEAKER_PROFILE,
+       SYNTHESIZER_HEADER_COMPLETION_CAUSE,
+       SYNTHESIZER_HEADER_COMPLETION_REASON,
+       SYNTHESIZER_HEADER_VOICE_GENDER,
+       SYNTHESIZER_HEADER_VOICE_AGE,
+       SYNTHESIZER_HEADER_VOICE_VARIANT,
+       SYNTHESIZER_HEADER_VOICE_NAME,
+       SYNTHESIZER_HEADER_PROSODY_VOLUME,
+       SYNTHESIZER_HEADER_PROSODY_RATE,
+       SYNTHESIZER_HEADER_SPEECH_MARKER,
+       SYNTHESIZER_HEADER_SPEECH_LANGUAGE,
+       SYNTHESIZER_HEADER_FETCH_HINT,
+       SYNTHESIZER_HEADER_AUDIO_FETCH_HINT,
+       SYNTHESIZER_HEADER_FAILED_URI,
+       SYNTHESIZER_HEADER_FAILED_URI_CAUSE,
+       SYNTHESIZER_HEADER_SPEAK_RESTART,
+       SYNTHESIZER_HEADER_SPEAK_LENGTH,
+       SYNTHESIZER_HEADER_LOAD_LEXICON,
+       SYNTHESIZER_HEADER_LEXICON_SEARCH_ORDER,
+
+       SYNTHESIZER_HEADER_COUNT
+} mrcp_synthesizer_header_id;
+
+
+/** Speech-units */
+typedef enum {
+       SPEECH_UNIT_SECOND,
+       SPEECH_UNIT_WORD,
+       SPEECH_UNIT_SENTENCE,
+       SPEECH_UNIT_PARAGRAPH,
+
+       SPEECH_UNIT_COUNT
+} mrcp_speech_unit_e;
+
+/** Speech-length types */
+typedef enum {
+       SPEECH_LENGTH_TYPE_TEXT,
+       SPEECH_LENGTH_TYPE_NUMERIC_POSITIVE,
+       SPEECH_LENGTH_TYPE_NUMERIC_NEGATIVE,
+
+       SPEECH_LENGTH_TYPE_UNKNOWN
+} mrcp_speech_length_type_e;
+
+/** MRCP voice-gender */
+typedef enum {
+       VOICE_GENDER_MALE,
+       VOICE_GENDER_FEMALE,
+       VOICE_GENDER_NEUTRAL,
+       
+       VOICE_GENDER_COUNT,
+       VOICE_GENDER_UNKNOWN = VOICE_GENDER_COUNT
+} mrcp_voice_gender_e;
+
+/** Prosody-volume type */
+typedef enum {
+       PROSODY_VOLUME_TYPE_LABEL,
+       PROSODY_VOLUME_TYPE_NUMERIC,
+       PROSODY_VOLUME_TYPE_RELATIVE_CHANGE,
+       
+       PROSODY_VOLUME_TYPE_UNKNOWN
+} mrcp_prosody_volume_type_e;
+
+/** Prosody-rate type */
+typedef enum {
+       PROSODY_RATE_TYPE_LABEL,
+       PROSODY_RATE_TYPE_RELATIVE_CHANGE,
+
+       PROSODY_RATE_TYPE_UNKNOWN
+} mrcp_prosody_rate_type_e;
+
+/** Prosody-volume */
+typedef enum {
+       PROSODY_VOLUME_SILENT,
+       PROSODY_VOLUME_XSOFT,
+       PROSODY_VOLUME_SOFT,
+       PROSODY_VOLUME_MEDIUM,
+       PROSODY_VOLUME_LOUD,
+       PROSODY_VOLUME_XLOUD,
+       PROSODY_VOLUME_DEFAULT,
+
+       PROSODY_VOLUME_COUNT,
+       PROSODY_VOLUME_UNKNOWN = PROSODY_VOLUME_COUNT
+} mrcp_prosody_volume_label_e;
+
+/** Prosody-rate */
+typedef enum {
+       PROSODY_RATE_XSLOW,
+       PROSODY_RATE_SLOW,
+       PROSODY_RATE_MEDIUM,
+       PROSODY_RATE_FAST,
+       PROSODY_RATE_XFAST,
+       PROSODY_RATE_DEFAULT,
+
+       PROSODY_RATE_COUNT,
+       PROSODY_RATE_UNKNOWN = PROSODY_RATE_COUNT
+} mrcp_prosody_rate_label_e;
+
+/** Synthesizer completion-cause specified in SPEAK-COMPLETE event */
+typedef enum {
+       SYNTHESIZER_COMPLETION_CAUSE_NORMAL               = 0,
+       SYNTHESIZER_COMPLETION_CAUSE_BARGE_IN             = 1,
+       SYNTHESIZER_COMPLETION_CAUSE_PARSE_FAILURE        = 2,
+       SYNTHESIZER_COMPLETION_CAUSE_URI_FAILURE          = 3,
+       SYNTHESIZER_COMPLETION_CAUSE_ERROR                = 4,
+       SYNTHESIZER_COMPLETION_CAUSE_LANGUAGE_UNSUPPORTED = 5,
+       SYNTHESIZER_COMPLETION_CAUSE_LEXICON_LOAD_FAILURE = 6,
+       SYNTHESIZER_COMPLETION_CAUSE_CANCELLED            = 7,
+
+       SYNTHESIZER_COMPLETION_CAUSE_COUNT                = 8,
+       SYNTHESIZER_COMPLETION_CAUSE_UNKNOWN              = SYNTHESIZER_COMPLETION_CAUSE_COUNT
+} mrcp_synth_completion_cause_e;
+
+
+/** Speech-length value declaration */
+typedef struct mrcp_speech_length_value_t mrcp_speech_length_value_t;
+/** Numeric speech-length declaration */
+typedef struct mrcp_numeric_speech_length_t mrcp_numeric_speech_length_t;
+/** Prosody-param declaration */
+typedef struct mrcp_prosody_param_t mrcp_prosody_param_t;
+/** Voice-param declaration */
+typedef struct mrcp_voice_param_t mrcp_voice_param_t;
+/**Prosody-rate declaration*/
+typedef struct mrcp_prosody_rate_t mrcp_prosody_rate_t;
+/**Prosody-volume declaration*/
+typedef struct mrcp_prosody_volume_t mrcp_prosody_volume_t;
+/** MRCP synthesizer-header declaration */
+typedef struct mrcp_synth_header_t mrcp_synth_header_t;
+
+/** Numeric speech-length */
+struct mrcp_numeric_speech_length_t {
+       /** The length */
+       apr_size_t         length;
+       /** The unit (second/word/sentence/paragraph) */
+       mrcp_speech_unit_e unit;
+};
+
+/** Definition of speech-length value */
+struct mrcp_speech_length_value_t {
+       /** Speech-length type (numeric/text)*/
+       mrcp_speech_length_type_e type;
+       /** Speech-length value (either numeric or text) */
+       union {
+               /** Text speech-length */
+               apt_str_t                    tag;
+               /** Numeric speech-length */
+               mrcp_numeric_speech_length_t numeric;
+       } value;
+};
+
+/** MRCP voice-param */
+struct mrcp_voice_param_t {
+       /** Voice gender (male/femaile/neutral)*/
+       mrcp_voice_gender_e gender;
+       /** Voice age */
+       apr_size_t          age;
+       /** Voice variant */
+       apr_size_t          variant;
+       /** Voice name */
+       apt_str_t           name;
+};
+
+/** MRCP prosody-volume */
+struct mrcp_prosody_volume_t {
+       /** prosody-volume type (one of label,numeric,relative change) */
+       mrcp_prosody_volume_type_e type;
+
+       /** prosody-volume value */
+       union {
+               /** one of "silent", "x-soft,..." */ 
+               mrcp_prosody_volume_label_e label;
+               /** numeric value */
+               float                       numeric;
+               /** relative change */
+               float                       relative;
+       } value;
+};
+
+/** MRCP prosody-rate */
+struct mrcp_prosody_rate_t {
+       /** prosody-rate type (one of label, relative change) */
+       mrcp_prosody_rate_type_e type;
+
+       /** prosody-rate value */
+       union {
+               /** one of "x-slow", "slow,..." */ 
+               mrcp_prosody_rate_label_e label;
+               /** relative change */
+               float                     relative;
+       } value;
+};
+
+/** MRCP prosody-param */
+struct mrcp_prosody_param_t {
+       /** Prosofy volume */
+       mrcp_prosody_volume_t volume;
+       /** Prosofy rate */
+       mrcp_prosody_rate_t   rate;
+};
+
+/** MRCP synthesizer-header */
+struct mrcp_synth_header_t {
+       /** MAY be specified in a CONTROL method and controls the
+    amount to jump forward or backward in an active "SPEAK" request */
+       mrcp_speech_length_value_t    jump_size;
+       /** MAY be sent as part of the "SPEAK" method to enable kill-
+    on-barge-in support */
+       apt_bool_t                    kill_on_barge_in;
+       /** MAY be part of the "SET-PARAMS"/"GET-PARAMS" or "SPEAK"
+    request from the client to the server and specifies a URI which
+    references the profile of the speaker */
+       apt_str_t                     speaker_profile;
+       /** MUST be specified in a "SPEAK-COMPLETE" event coming from
+    the synthesizer resource to the client */
+       mrcp_synth_completion_cause_e completion_cause;
+       /** MAY be specified in a "SPEAK-COMPLETE" event coming from
+    the synthesizer resource to the client */
+       apt_str_t                     completion_reason;
+       /** This set of headers defines the voice of the speaker */
+       mrcp_voice_param_t            voice_param;
+       /** This set of headers defines the prosody of the speech */
+       mrcp_prosody_param_t          prosody_param;
+       /** Contains timestamp information in a "timestamp" field */
+       apt_str_t                     speech_marker;
+       /** specifies the default language of the speech data if the
+    language is not specified in the markup */
+       apt_str_t                     speech_language;
+       /** When the synthesizer needs to fetch documents or other resources like
+    speech markup or audio files, this header controls the corresponding
+    URI access properties */
+       apt_str_t                     fetch_hint;
+       /** When the synthesizer needs to fetch documents or other resources like
+    speech audio files, this header controls the corresponding URI access
+    properties */
+       apt_str_t                     audio_fetch_hint;
+       /** When a synthesizer method needs a synthesizer to fetch or access a
+    URI and the access fails, the server SHOULD provide the failed URI in
+    this header in the method response */
+       apt_str_t                     failed_uri;
+       /** When a synthesizer method needs a synthesizer to fetch or access a
+    URI and the access fails the server MUST provide the URI specific or
+    protocol specific response code for the URI in the Failed-URI header
+    in the method response through this header */
+       apt_str_t                     failed_uri_cause;
+       /** When a CONTROL request to jump backward is issued to a currently
+    speaking synthesizer resource, and the target jump point is before
+    the start of the current "SPEAK" request, the current "SPEAK" request
+    MUST restart */
+       apt_bool_t                    speak_restart;
+       /** MAY be specified in a CONTROL method to control the
+    length of speech to speak, relative to the current speaking point in
+    the currently active "SPEAK" request */
+       mrcp_speech_length_value_t    speak_length;
+       /** Used to indicate whether a lexicon has to be loaded or unloaded */
+       apt_bool_t                    load_lexicon;
+       /** used to specify a list of active Lexicon URIs and the
+    search order among the active lexicons */
+       apt_str_t                     lexicon_search_order;
+};
+
+/** Get synthesizer header vtable */
+MRCP_DECLARE(const mrcp_header_vtable_t*) mrcp_synth_header_vtable_get(mrcp_version_e version);
+
+/** Get synthesizer completion cause string */
+MRCP_DECLARE(const apt_str_t*) mrcp_synth_completion_cause_get(mrcp_synth_completion_cause_e completion_cause, mrcp_version_e version);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_SYNTH_HEADER_H__*/
diff --git a/libs/unimrcp/libs/mrcp/resources/include/mrcp_synth_resource.h b/libs/unimrcp/libs/mrcp/resources/include/mrcp_synth_resource.h
new file mode 100644 (file)
index 0000000..d63fbdb
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_SYNTH_RESOURCE_H__
+#define __MRCP_SYNTH_RESOURCE_H__
+
+/**
+ * @file mrcp_synth_resource.h
+ * @brief MRCP Synthesizer Resource
+ */ 
+
+#include "mrcp_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/** MRCP synthesizer methods */
+typedef enum {
+       SYNTHESIZER_SET_PARAMS,
+       SYNTHESIZER_GET_PARAMS,
+       SYNTHESIZER_SPEAK,
+       SYNTHESIZER_STOP,
+       SYNTHESIZER_PAUSE,
+       SYNTHESIZER_RESUME,
+       SYNTHESIZER_BARGE_IN_OCCURRED,
+       SYNTHESIZER_CONTROL,
+       SYNTHESIZER_DEFINE_LEXICON,
+
+       SYNTHESIZER_METHOD_COUNT
+} mrcp_synthesizer_method_id;
+
+/** MRCP synthesizer events */
+typedef enum {
+       SYNTHESIZER_SPEECH_MARKER,
+       SYNTHESIZER_SPEAK_COMPLETE,
+
+       SYNTHESIZER_EVENT_COUNT
+} mrcp_synthesizer_event_id;
+
+
+/** Create MRCP synthesizer resource */
+MRCP_DECLARE(mrcp_resource_t*) mrcp_synth_resource_create(apr_pool_t *pool);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_SYNTH_RESOURCE_H__*/
diff --git a/libs/unimrcp/libs/mrcp/resources/include/mrcp_synth_state_machine.h b/libs/unimrcp/libs/mrcp/resources/include/mrcp_synth_state_machine.h
new file mode 100644 (file)
index 0000000..524fd29
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_SYNTH_STATE_MACHINE_H__
+#define __MRCP_SYNTH_STATE_MACHINE_H__
+
+/**
+ * @file mrcp_synth_state_machine.h
+ * @brief MRCP Synthesizer State Machine
+ */ 
+
+#include "mrcp_state_machine.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Create MRCP synthesizer server state machine */
+mrcp_state_machine_t* mrcp_synth_server_state_machine_create(void *obj, mrcp_message_dispatcher_f dispatcher, mrcp_version_e version, apr_pool_t *pool);
+
+/** Create MRCP synthesizer client state machine */
+mrcp_state_machine_t* mrcp_synth_client_state_machine_create(void *obj, mrcp_message_dispatcher_f dispatcher, mrcp_version_e version, apr_pool_t *pool);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_SYNTH_STATE_MACHINE_H__*/
diff --git a/libs/unimrcp/libs/mrcp/resources/src/mrcp_default_factory.c b/libs/unimrcp/libs/mrcp/resources/src/mrcp_default_factory.c
new file mode 100644 (file)
index 0000000..d34ba99
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mrcp_default_factory.h"
+#include "mrcp_synth_resource.h"
+#include "mrcp_recog_resource.h"
+#include "apt_log.h"
+
+/** String table of MRCPv2 resources (mrcp_resource_types_e) */
+static const apt_str_table_item_t mrcp_resource_string_table[] = {
+       {{"speechsynth",11},6},
+       {{"speechrecog",11},6}
+};
+
+/** Create default MRCP resource factory */
+MRCP_DECLARE(mrcp_resource_factory_t*) mrcp_default_factory_create(apr_pool_t *pool)
+{
+       mrcp_resource_t *resource;
+       mrcp_resource_factory_t *resource_factory;
+       /* create resource factory instance */
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create MRCP Resource Factory [%d]",MRCP_RESOURCE_TYPE_COUNT);
+       resource_factory = mrcp_resource_factory_create(MRCP_RESOURCE_TYPE_COUNT,pool);
+       if(!resource_factory) {
+               return NULL;
+       }
+       
+       /* set resource string table */
+       mrcp_resource_string_table_set(resource_factory,mrcp_resource_string_table);
+
+       /* create and register resources */
+       resource = mrcp_synth_resource_create(pool);
+       if(resource) {
+               apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Register Synthesizer Resource");
+               mrcp_resource_register(resource_factory,resource,MRCP_SYNTHESIZER_RESOURCE);
+       }
+       
+       resource = mrcp_recog_resource_create(pool);
+       if(resource) {
+               apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Register Recognizer Resource");
+               mrcp_resource_register(resource_factory,resource,MRCP_RECOGNIZER_RESOURCE);
+       }
+
+       return resource_factory;
+}
diff --git a/libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_client_state_machine.c b/libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_client_state_machine.c
new file mode 100644 (file)
index 0000000..3e313d7
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mrcp_state_machine.h"
+#include "mrcp_recog_state_machine.h"
+#include "mrcp_message.h"
+
+
+/** Update state according to request received from user level or response/event received from MRCP server */
+static apt_bool_t recog_state_update(mrcp_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       /* no actual state machine processing yet, dispatch whatever received */
+       return state_machine->dispatcher(state_machine,message);
+}
+
+/** Create MRCP recognizer client state machine */
+mrcp_state_machine_t* mrcp_recog_client_state_machine_create(void *obj, mrcp_message_dispatcher_f dispatcher, mrcp_version_e version, apr_pool_t *pool)
+{
+       mrcp_state_machine_t *state_machine = apr_palloc(pool,sizeof(mrcp_state_machine_t));
+       mrcp_state_machine_init(state_machine,obj,dispatcher);
+       state_machine->update = recog_state_update;
+       return state_machine;
+}
diff --git a/libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_header.c b/libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_header.c
new file mode 100644 (file)
index 0000000..70691a5
--- /dev/null
@@ -0,0 +1,656 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mrcp_recog_header.h"
+
+/** String table of MRCPv1 recognizer headers (mrcp_recog_header_id) */
+static const apt_str_table_item_t v1_recog_header_string_table[] = {
+       {{"Confidence-Threshold",       20},7},
+       {{"Sensitivity-Level",          17},3},
+       {{"Speed-Vs-Accuracy",          17},4},
+       {{"N-Best-List-Length",         18},1},
+       {{"No-Input-Timeout",           16},2},
+       {{"Recognition-Timeout",        19},16},
+       {{"Waveform-Url",               12},0},
+       {{"Completion-Cause",           16},16},
+       {{"Recognizer-Context-Block",   24},12},
+       {{"Recognizer-Start-Timers",    23},11},
+       {{"Speech-Complete-Timeout",    23},7},
+       {{"Speech-Incomplete-Timeout",  25},8},
+       {{"DTMF-Interdigit-Timeout",    23},5},
+       {{"DTMF-Term-Timeout",          17},14},
+       {{"DTMF-Term-Char",             14},14},
+       {{"Failed-Uri",                 10},10},
+       {{"Failed-Uri-Cause",           16},16},
+       {{"Save-Waveform",              13},5},
+       {{"New-Audio-Channel",          17},2},
+       {{"Speech-Language",            15},8},
+       {{"Input-Type",                 10},10},
+       {{"Input-Waveform-Uri",         18},6},
+       {{"Completion-Reason",          17},15},
+       {{"Media-Type",                 10},0},
+       {{"Ver-Buffer-Utterance",       20},0},
+       {{"Recognition-Mode",           16},14},
+       {{"Cancel-If-Queue",            15},3},
+       {{"Hotword-Max-Duration",       20},10},
+       {{"Hotword-Min-Duration",       20},20},
+       {{"Interpret-Text",             14},7},
+       {{"DTMF-Buffer-Time",           16},5},
+       {{"Clear-DTMF-Buffer",          17},1},
+       {{"Early-No-Match",             14},0}
+};
+
+/** String table of MRCPv2 recognizer headers (mrcp_recog_header_id) */
+static const apt_str_table_item_t v2_recog_header_string_table[] = {
+       {{"Confidence-Threshold",       20},8},
+       {{"Sensitivity-Level",          17},3},
+       {{"Speed-Vs-Accuracy",          17},4},
+       {{"N-Best-List-Length",         18},1},
+       {{"No-Input-Timeout",           16},2},
+       {{"Recognition-Timeout",        19},16},
+       {{"Waveform-Uri",               12},0},
+       {{"Completion-Cause",           16},16},
+       {{"Recognizer-Context-Block",   24},7},
+       {{"Start-Input-Timers",         18},2},
+       {{"Speech-Complete-Timeout",    23},7},
+       {{"Speech-Incomplete-Timeout",  25},8},
+       {{"DTMF-Interdigit-Timeout",    23},5},
+       {{"DTMF-Term-Timeout",          17},14},
+       {{"DTMF-Term-Char",             14},14},
+       {{"Failed-Uri",                 10},10},
+       {{"Failed-Uri-Cause",           16},16},
+       {{"Save-Waveform",              13},5},
+       {{"New-Audio-Channel",          17},2},
+       {{"Speech-Language",            15},8},
+       {{"Input-Type",                 10},10},
+       {{"Input-Waveform-Uri",         18},6},
+       {{"Completion-Reason",          17},13},
+       {{"Media-Type",                 10},0},
+       {{"Ver-Buffer-Utterance",       20},0},
+       {{"Recognition-Mode",           16},14},
+       {{"Cancel-If-Queue",            15},3},
+       {{"Hotword-Max-Duration",       20},10},
+       {{"Hotword-Min-Duration",       20},20},
+       {{"Interpret-Text",             14},7},
+       {{"DTMF-Buffer-Time",           16},5},
+       {{"Clear-DTMF-Buffer",          17},1},
+       {{"Early-No-Match",             14},0}
+};
+
+/** String table of MRCPv1 recognizer completion-cause fields (mrcp_recog_completion_cause_e) */
+static const apt_str_table_item_t v1_completion_cause_string_table[] = {
+       {{"success",                     7},1},
+       {{"no-match",                    8},8},
+       {{"no-input-timeout",           16},3},
+       {{"recognition-timeout",        19},0},
+       {{"gram-load-failure",          17},7},
+       {{"gram-comp-failure",          17},5},
+       {{"error",                       5},0},
+       {{"speech-too-early",           16},1},
+       {{"too-much-speech-timeout",    23},0},
+       {{"uri-failure",                11},0},
+       {{"language-unsupported",       20},0},
+       {{"cancelled",                   9},0},
+       {{"semantics-failure",          17},2},
+       {{"partial-match",              13},13},
+       {{"partial-match-maxtime",      21},13},
+       {{"no-match-maxtime",           16},9},
+       {{"gram-definition-failure",    23},5}
+};
+
+
+/** String table of MRCPv2 recognizer completion-cause fields (mrcp_recog_completion_cause_e) */
+static const apt_str_table_item_t v2_completion_cause_string_table[] = {
+       {{"success",                     7},7},
+       {{"no-match",                    8},4},
+       {{"no-input-timeout",           16},3},
+       {{"hotword-maxtime",            15},0},
+       {{"grammar-load-failure",       20},8},
+       {{"grammar-compilation-failure",27},8},
+       {{"recognizer-error",           16},0},
+       {{"speech-too-early",           16},1},
+       {{"success-maxtime",            15},15},
+       {{"uri-failure",                11},0},
+       {{"language-unsupported",       20},0},
+       {{"cancelled",                   9},0},
+       {{"semantics-failure",          17},2},
+       {{"partial-match",              13},13},
+       {{"partial-match-maxtime",      21},13},
+       {{"no-match-maxtime",           16},9},
+       {{"grammar-definition-failure", 26},9}
+};
+
+/** Generate MRCP recognizer completion-cause */
+static apt_bool_t mrcp_completion_cause_generate(mrcp_recog_completion_cause_e completion_cause, const apt_str_t *name, apt_text_stream_t *stream)
+{
+       int length = sprintf(stream->pos,"%03"APR_SIZE_T_FMT" ",completion_cause);
+       if(length <= 0) {
+               return FALSE;
+       }
+       stream->pos += length;
+
+       if(name) {
+               memcpy(stream->pos,name->buf,name->length);
+               stream->pos += name->length;
+       }
+       return TRUE;
+}
+
+
+/** Initialize recognizer header */
+static void mrcp_recog_header_init(mrcp_recog_header_t *recog_header)
+{
+       recog_header->confidence_threshold = 0.0;
+       recog_header->sensitivity_level = 0.0;
+       recog_header->speed_vs_accuracy = 0.0;
+       recog_header->n_best_list_length = 0;
+       recog_header->no_input_timeout = 0;
+       recog_header->recognition_timeout = 0;
+       apt_string_reset(&recog_header->waveform_uri);
+       recog_header->completion_cause = RECOGNIZER_COMPLETION_CAUSE_COUNT;
+       apt_string_reset(&recog_header->recognizer_context_block);
+       recog_header->start_input_timers = FALSE;
+       recog_header->speech_complete_timeout = 0;
+       recog_header->speech_incomplete_timeout = 0;
+       recog_header->dtmf_interdigit_timeout = 0;
+       recog_header->dtmf_term_timeout = 0;
+       recog_header->dtmf_term_char = 0;
+       apt_string_reset(&recog_header->failed_uri);
+       apt_string_reset(&recog_header->failed_uri_cause);
+       recog_header->save_waveform = FALSE;
+       recog_header->new_audio_channel = FALSE;
+       apt_string_reset(&recog_header->speech_language);
+       /* initializes additionnal MRCPV2 recog headers */
+       apt_string_reset(&recog_header->input_type);
+       apt_string_reset(&recog_header->input_waveform_uri);
+       apt_string_reset(&recog_header->completion_reason);
+       apt_string_reset(&recog_header->media_type);
+       recog_header->ver_buffer_utterance = FALSE;
+       apt_string_reset(&recog_header->recognition_mode);
+       recog_header->cancel_if_queue = FALSE;
+       recog_header->hotword_max_duration = 0;
+       recog_header->hotword_min_duration = 0;
+       apt_string_reset(&recog_header->interpret_text);
+       recog_header->dtmf_buffer_time = 0;
+       recog_header->clear_dtmf_buffer = FALSE;
+       recog_header->early_no_match = FALSE;
+}
+
+/** Allocate MRCP recognizer header */
+static void* mrcp_recog_header_allocate(mrcp_header_accessor_t *accessor, apr_pool_t *pool)
+{
+       mrcp_recog_header_t *recog_header = apr_palloc(pool,sizeof(mrcp_recog_header_t));
+       mrcp_recog_header_init(recog_header);
+       accessor->data = recog_header;
+       return accessor->data;
+}
+
+/** Parse MRCP recognizer header */
+static apt_bool_t mrcp_recog_header_parse(mrcp_recog_header_t *recog_header, apr_size_t id, const apt_str_t *value, apr_pool_t *pool)
+{
+       apt_bool_t status = TRUE;
+       switch(id) {
+               case RECOGNIZER_HEADER_N_BEST_LIST_LENGTH:
+                       recog_header->n_best_list_length = apt_size_value_parse(value);
+                       break;
+               case RECOGNIZER_HEADER_NO_INPUT_TIMEOUT:
+                       recog_header->no_input_timeout = apt_size_value_parse(value);
+                       break;
+               case RECOGNIZER_HEADER_RECOGNITION_TIMEOUT:
+                       recog_header->recognition_timeout = apt_size_value_parse(value);
+                       break;
+               case RECOGNIZER_HEADER_WAVEFORM_URI:
+                       apt_string_copy(&recog_header->waveform_uri,value,pool);
+                       break;
+               case RECOGNIZER_HEADER_COMPLETION_CAUSE:
+                       recog_header->completion_cause = apt_size_value_parse(value);
+                       break;
+               case RECOGNIZER_HEADER_RECOGNIZER_CONTEXT_BLOCK:
+                       apt_string_copy(&recog_header->recognizer_context_block,value,pool);
+                       break;
+               case RECOGNIZER_HEADER_START_INPUT_TIMERS:
+                       apt_boolean_value_parse(value,&recog_header->start_input_timers);
+                       break;
+               case RECOGNIZER_HEADER_SPEECH_COMPLETE_TIMEOUT:
+                       recog_header->speech_complete_timeout = apt_size_value_parse(value);
+                       break;
+               case RECOGNIZER_HEADER_SPEECH_INCOMPLETE_TIMEOUT:
+                       recog_header->speech_incomplete_timeout = apt_size_value_parse(value);
+                       break;
+               case RECOGNIZER_HEADER_DTMF_INTERDIGIT_TIMEOUT:
+                       recog_header->dtmf_interdigit_timeout = apt_size_value_parse(value);
+                       break;
+               case RECOGNIZER_HEADER_DTMF_TERM_TIMEOUT:
+                       recog_header->dtmf_term_timeout = apt_size_value_parse(value);
+                       break;
+               case RECOGNIZER_HEADER_DTMF_TERM_CHAR:
+                       recog_header->dtmf_term_char = *value->buf;
+                       break;
+               case RECOGNIZER_HEADER_FAILED_URI:
+                       apt_string_copy(&recog_header->failed_uri,value,pool);
+                       break;
+               case RECOGNIZER_HEADER_FAILED_URI_CAUSE:
+                       apt_string_copy(&recog_header->failed_uri_cause,value,pool);
+                       break;
+               case RECOGNIZER_HEADER_SAVE_WAVEFORM:
+                       apt_boolean_value_parse(value,&recog_header->save_waveform);
+                       break;
+               case RECOGNIZER_HEADER_NEW_AUDIO_CHANNEL:
+                       apt_boolean_value_parse(value,&recog_header->new_audio_channel);
+                       break;
+               case RECOGNIZER_HEADER_SPEECH_LANGUAGE:
+                       apt_string_copy(&recog_header->speech_language,value,pool);
+                       break;
+               case RECOGNIZER_HEADER_INPUT_TYPE:
+                       apt_string_copy(&recog_header->input_type,value,pool);
+                       break;
+               case RECOGNIZER_HEADER_MEDIA_TYPE:
+                       apt_string_copy(&recog_header->media_type,value,pool);
+                       break;
+               case RECOGNIZER_HEADER_INPUT_WAVEFORM_URI:
+                       apt_string_copy(&recog_header->input_waveform_uri,value,pool);
+                       break;
+               case RECOGNIZER_HEADER_COMPLETION_REASON:
+                       apt_string_copy(&recog_header->completion_reason,value,pool);
+                       break;
+               case RECOGNIZER_HEADER_VER_BUFFER_UTTERANCE:
+                       apt_boolean_value_parse(value,&recog_header->ver_buffer_utterance);
+                       break;
+               case RECOGNIZER_HEADER_RECOGNITION_MODE:
+                       apt_string_copy(&recog_header->recognition_mode,value,pool);
+                       break;
+               case RECOGNIZER_HEADER_CANCEL_IF_QUEUE:
+                       apt_boolean_value_parse(value,&recog_header->cancel_if_queue);
+                       break;
+               case RECOGNIZER_HEADER_HOTWORD_MAX_DURATION:
+                       recog_header->hotword_max_duration = apt_size_value_parse(value);
+                       break;
+               case RECOGNIZER_HEADER_HOTWORD_MIN_DURATION:
+                       recog_header->hotword_min_duration = apt_size_value_parse(value);
+                       break;
+               case RECOGNIZER_HEADER_INTERPRET_TEXT:
+                       apt_string_copy(&recog_header->interpret_text,value,pool);
+                       break;
+               case RECOGNIZER_HEADER_DTMF_BUFFER_TIME:
+                       recog_header->dtmf_buffer_time = apt_size_value_parse(value);
+                       break;
+               case RECOGNIZER_HEADER_CLEAR_DTMF_BUFFER:
+                       apt_boolean_value_parse(value,&recog_header->clear_dtmf_buffer);
+                       break;
+               case RECOGNIZER_HEADER_EARLY_NO_MATCH:
+                       apt_boolean_value_parse(value,&recog_header->early_no_match);
+                       break;
+               default:
+                       status = FALSE;
+       }
+       return status;
+}
+
+static APR_INLINE float apt_size_value_parse_as_float(const apt_str_t *value)
+{
+       float f = (float)apt_size_value_parse(value);
+       return f / 100;
+}
+
+static APR_INLINE apt_bool_t apt_size_value_generate_from_float(float value, apt_text_stream_t *stream)
+{
+       apr_size_t s = (apr_size_t)((value + 0.001f) * 100);
+       return apt_size_value_generate(s,stream);
+}
+
+/** Parse MRCPv1 recognizer header */
+static apt_bool_t mrcp_v1_recog_header_parse(mrcp_header_accessor_t *accessor, apr_size_t id, const apt_str_t *value, apr_pool_t *pool)
+{
+       mrcp_recog_header_t *recog_header = accessor->data;
+       if(id == RECOGNIZER_HEADER_CONFIDENCE_THRESHOLD) {
+               recog_header->confidence_threshold = apt_size_value_parse_as_float(value);
+               return TRUE;
+       }
+       else if(id == RECOGNIZER_HEADER_SENSITIVITY_LEVEL) {
+               recog_header->sensitivity_level = apt_size_value_parse_as_float(value);
+               return TRUE;
+       }
+       else if(id == RECOGNIZER_HEADER_SPEED_VS_ACCURACY) {
+               recog_header->speed_vs_accuracy = apt_size_value_parse_as_float(value);
+               return TRUE;
+       }
+       return mrcp_recog_header_parse(recog_header,id,value,pool);
+}
+
+/** Parse MRCPv2 recognizer header */
+static apt_bool_t mrcp_v2_recog_header_parse(mrcp_header_accessor_t *accessor, apr_size_t id, const apt_str_t *value, apr_pool_t *pool)
+{
+       mrcp_recog_header_t *recog_header = accessor->data;
+       if(id == RECOGNIZER_HEADER_CONFIDENCE_THRESHOLD) {
+               recog_header->confidence_threshold = apt_float_value_parse(value);
+               return TRUE;
+       }
+       else if(id == RECOGNIZER_HEADER_SENSITIVITY_LEVEL) {
+               recog_header->sensitivity_level = apt_float_value_parse(value);
+               return TRUE;
+       }
+       else if(id == RECOGNIZER_HEADER_SPEED_VS_ACCURACY) {
+               recog_header->speed_vs_accuracy = apt_float_value_parse(value);
+               return TRUE;
+       }
+       return mrcp_recog_header_parse(recog_header,id,value,pool);
+}
+
+/** Generate MRCP recognizer header */
+static apt_bool_t mrcp_recog_header_generate(mrcp_recog_header_t *recog_header, apr_size_t id, apt_text_stream_t *value)
+{
+       switch(id) {
+               case RECOGNIZER_HEADER_N_BEST_LIST_LENGTH:
+                       apt_size_value_generate(recog_header->n_best_list_length,value);
+                       break;
+               case RECOGNIZER_HEADER_NO_INPUT_TIMEOUT:
+                       apt_size_value_generate(recog_header->no_input_timeout,value);
+                       break;
+               case RECOGNIZER_HEADER_RECOGNITION_TIMEOUT:
+                       apt_size_value_generate(recog_header->recognition_timeout,value);
+                       break;
+               case RECOGNIZER_HEADER_WAVEFORM_URI:
+                       apt_string_value_generate(&recog_header->waveform_uri,value);
+                       break;
+               case RECOGNIZER_HEADER_RECOGNIZER_CONTEXT_BLOCK:
+                       apt_string_value_generate(&recog_header->recognizer_context_block,value);
+                       break;
+               case RECOGNIZER_HEADER_START_INPUT_TIMERS:
+                       apt_boolean_value_generate(recog_header->start_input_timers,value);
+                       break;
+               case RECOGNIZER_HEADER_SPEECH_COMPLETE_TIMEOUT:
+                       apt_size_value_generate(recog_header->speech_complete_timeout,value);
+                       break;
+               case RECOGNIZER_HEADER_SPEECH_INCOMPLETE_TIMEOUT:
+                       apt_size_value_generate(recog_header->speech_incomplete_timeout,value);
+                       break;
+               case RECOGNIZER_HEADER_DTMF_INTERDIGIT_TIMEOUT:
+                       apt_size_value_generate(recog_header->dtmf_interdigit_timeout,value);
+                       break;
+               case RECOGNIZER_HEADER_DTMF_TERM_TIMEOUT:
+                       apt_size_value_generate(recog_header->dtmf_term_timeout,value);
+                       break;
+               case RECOGNIZER_HEADER_DTMF_TERM_CHAR:
+                       *value->pos++ = recog_header->dtmf_term_char;
+                       break;
+               case RECOGNIZER_HEADER_FAILED_URI:
+                       apt_string_value_generate(&recog_header->failed_uri,value);
+                       break;
+               case RECOGNIZER_HEADER_FAILED_URI_CAUSE:
+                       apt_string_value_generate(&recog_header->failed_uri_cause,value);
+                       break;
+               case RECOGNIZER_HEADER_SAVE_WAVEFORM:
+                       apt_boolean_value_generate(recog_header->save_waveform,value);
+                       break;
+               case RECOGNIZER_HEADER_NEW_AUDIO_CHANNEL:
+                       apt_boolean_value_generate(recog_header->new_audio_channel,value);
+                       break;
+               case RECOGNIZER_HEADER_SPEECH_LANGUAGE:
+                       apt_string_value_generate(&recog_header->speech_language,value);
+                       break;
+               case RECOGNIZER_HEADER_INPUT_TYPE:
+                       apt_string_value_generate(&recog_header->input_type,value);
+                       break;
+               case RECOGNIZER_HEADER_INPUT_WAVEFORM_URI:
+                       apt_string_value_generate(&recog_header->input_waveform_uri,value);
+                       break;
+               case RECOGNIZER_HEADER_COMPLETION_REASON:
+                       apt_string_value_generate(&recog_header->completion_reason,value);
+                       break;
+               case RECOGNIZER_HEADER_MEDIA_TYPE:
+                       apt_string_value_generate(&recog_header->media_type,value);
+                       break;
+               case RECOGNIZER_HEADER_VER_BUFFER_UTTERANCE:
+                       apt_boolean_value_generate(recog_header->ver_buffer_utterance,value);
+                       break;
+               case RECOGNIZER_HEADER_RECOGNITION_MODE:
+                       apt_string_value_generate(&recog_header->recognition_mode,value);
+                       break;
+               case RECOGNIZER_HEADER_CANCEL_IF_QUEUE:
+                       apt_boolean_value_generate(recog_header->cancel_if_queue,value);
+                       break;
+               case RECOGNIZER_HEADER_HOTWORD_MAX_DURATION:
+                       apt_size_value_generate(recog_header->hotword_max_duration,value);
+                       break;
+               case RECOGNIZER_HEADER_HOTWORD_MIN_DURATION:
+                       apt_size_value_generate(recog_header->hotword_min_duration,value);
+                       break;
+               case RECOGNIZER_HEADER_INTERPRET_TEXT:
+                       apt_string_value_generate(&recog_header->interpret_text,value);
+                       break;
+               case RECOGNIZER_HEADER_DTMF_BUFFER_TIME:
+                       apt_size_value_generate(recog_header->dtmf_buffer_time,value);
+                       break;
+               case RECOGNIZER_HEADER_CLEAR_DTMF_BUFFER:
+                       apt_boolean_value_generate(recog_header->clear_dtmf_buffer,value);
+                       break;
+               case RECOGNIZER_HEADER_EARLY_NO_MATCH:
+                       apt_boolean_value_generate(recog_header->early_no_match,value);
+                       break;
+               default:
+                       break;
+       }
+       return TRUE;
+}
+
+/** Generate MRCPv1 recognizer header */
+static apt_bool_t mrcp_v1_recog_header_generate(mrcp_header_accessor_t *accessor, apr_size_t id, apt_text_stream_t *value)
+{
+       mrcp_recog_header_t *recog_header = accessor->data;
+       if(id == RECOGNIZER_HEADER_CONFIDENCE_THRESHOLD) {
+               return apt_size_value_generate_from_float(recog_header->confidence_threshold,value);
+       }
+       else if(id == RECOGNIZER_HEADER_SENSITIVITY_LEVEL) {
+               return apt_size_value_generate_from_float(recog_header->sensitivity_level,value);
+       }
+       else if(id == RECOGNIZER_HEADER_SPEED_VS_ACCURACY) {
+               return apt_size_value_generate_from_float(recog_header->speed_vs_accuracy,value);
+       }
+       else if(id == RECOGNIZER_HEADER_COMPLETION_CAUSE) {
+               const apt_str_t *name = apt_string_table_str_get(
+                       v1_completion_cause_string_table,
+                       RECOGNIZER_COMPLETION_CAUSE_COUNT,
+                       recog_header->completion_cause);
+               return mrcp_completion_cause_generate(recog_header->completion_cause,name,value);
+       }
+       return mrcp_recog_header_generate(recog_header,id,value);
+}
+
+/** Generate MRCPv2 recognizer header */
+static apt_bool_t mrcp_v2_recog_header_generate(mrcp_header_accessor_t *accessor, apr_size_t id, apt_text_stream_t *value)
+{
+       mrcp_recog_header_t *recog_header = accessor->data;
+       if(id == RECOGNIZER_HEADER_CONFIDENCE_THRESHOLD) {
+               return apt_float_value_generate(recog_header->confidence_threshold,value);
+       }
+       else if(id == RECOGNIZER_HEADER_SENSITIVITY_LEVEL) {
+               return apt_float_value_generate(recog_header->sensitivity_level,value);
+       }
+       else if(id == RECOGNIZER_HEADER_SPEED_VS_ACCURACY) {
+               return apt_float_value_generate(recog_header->speed_vs_accuracy,value);
+       }
+       else if(id == RECOGNIZER_HEADER_COMPLETION_CAUSE) {
+               const apt_str_t *name = apt_string_table_str_get(
+                       v2_completion_cause_string_table,
+                       RECOGNIZER_COMPLETION_CAUSE_COUNT,
+                       recog_header->completion_cause);
+               return mrcp_completion_cause_generate(recog_header->completion_cause,name,value);
+       }
+       return mrcp_recog_header_generate(recog_header,id,value);
+}
+
+/** Duplicate MRCP recognizer header */
+static apt_bool_t mrcp_recog_header_duplicate(mrcp_header_accessor_t *accessor, const mrcp_header_accessor_t *src, apr_size_t id, apr_pool_t *pool)
+{
+       mrcp_recog_header_t *recog_header = accessor->data;
+       const mrcp_recog_header_t *src_recog_header = src->data;
+       apt_bool_t status = TRUE;
+
+       if(!recog_header || !src_recog_header) {
+               return FALSE;
+       }
+       
+       switch(id) {
+               case RECOGNIZER_HEADER_CONFIDENCE_THRESHOLD:
+                       recog_header->confidence_threshold = src_recog_header->confidence_threshold;
+                       break;
+               case RECOGNIZER_HEADER_SENSITIVITY_LEVEL:
+                       recog_header->sensitivity_level = src_recog_header->sensitivity_level;
+                       break;
+               case RECOGNIZER_HEADER_SPEED_VS_ACCURACY:
+                       recog_header->speed_vs_accuracy = src_recog_header->speed_vs_accuracy;
+                       break;
+               case RECOGNIZER_HEADER_N_BEST_LIST_LENGTH:
+                       recog_header->n_best_list_length = src_recog_header->n_best_list_length;
+                       break;
+               case RECOGNIZER_HEADER_NO_INPUT_TIMEOUT:
+                       recog_header->no_input_timeout = src_recog_header->no_input_timeout;
+                       break;
+               case RECOGNIZER_HEADER_RECOGNITION_TIMEOUT:
+                       recog_header->recognition_timeout = src_recog_header->recognition_timeout;
+                       break;
+               case RECOGNIZER_HEADER_WAVEFORM_URI:
+                       apt_string_copy(&recog_header->waveform_uri,&src_recog_header->waveform_uri,pool);
+                       break;
+               case RECOGNIZER_HEADER_COMPLETION_CAUSE:
+                       recog_header->completion_cause = src_recog_header->completion_cause;
+                       break;
+               case RECOGNIZER_HEADER_RECOGNIZER_CONTEXT_BLOCK:
+                       apt_string_copy(&recog_header->recognizer_context_block,&src_recog_header->recognizer_context_block,pool);
+                       break;
+               case RECOGNIZER_HEADER_START_INPUT_TIMERS:
+                       recog_header->start_input_timers = src_recog_header->start_input_timers;
+                       break;
+               case RECOGNIZER_HEADER_SPEECH_COMPLETE_TIMEOUT:
+                       recog_header->speech_complete_timeout = src_recog_header->speech_complete_timeout;
+                       break;
+               case RECOGNIZER_HEADER_SPEECH_INCOMPLETE_TIMEOUT:
+                       recog_header->speech_incomplete_timeout = src_recog_header->speech_incomplete_timeout;
+                       break;
+               case RECOGNIZER_HEADER_DTMF_INTERDIGIT_TIMEOUT:
+                       recog_header->dtmf_interdigit_timeout = src_recog_header->dtmf_interdigit_timeout;
+                       break;
+               case RECOGNIZER_HEADER_DTMF_TERM_TIMEOUT:
+                       recog_header->dtmf_term_timeout = src_recog_header->dtmf_term_timeout;
+                       break;
+               case RECOGNIZER_HEADER_DTMF_TERM_CHAR:
+                       recog_header->dtmf_term_char = src_recog_header->dtmf_term_char;
+                       break;
+               case RECOGNIZER_HEADER_FAILED_URI:
+                       apt_string_copy(&recog_header->failed_uri,&src_recog_header->failed_uri,pool);
+                       break;
+               case RECOGNIZER_HEADER_FAILED_URI_CAUSE:
+                       apt_string_copy(&recog_header->failed_uri_cause,&src_recog_header->failed_uri_cause,pool);
+                       break;
+               case RECOGNIZER_HEADER_SAVE_WAVEFORM:
+                       recog_header->save_waveform = src_recog_header->save_waveform;
+                       break;
+               case RECOGNIZER_HEADER_NEW_AUDIO_CHANNEL:
+                       recog_header->new_audio_channel = src_recog_header->new_audio_channel;
+                       break;
+               case RECOGNIZER_HEADER_SPEECH_LANGUAGE:
+                       apt_string_copy(&recog_header->speech_language,&src_recog_header->speech_language,pool);
+                       break;
+               case RECOGNIZER_HEADER_INPUT_TYPE:
+                       apt_string_copy(&recog_header->input_type,&src_recog_header->input_type,pool);
+                       break;
+               case RECOGNIZER_HEADER_INPUT_WAVEFORM_URI:
+                       apt_string_copy(&recog_header->input_waveform_uri,&src_recog_header->input_waveform_uri,pool);
+                       break;
+               case RECOGNIZER_HEADER_COMPLETION_REASON:
+                       apt_string_copy(&recog_header->completion_reason,&src_recog_header->completion_reason,pool);
+                       break;
+               case RECOGNIZER_HEADER_MEDIA_TYPE:
+                       apt_string_copy(&recog_header->media_type,&src_recog_header->media_type,pool);
+                       break;
+               case RECOGNIZER_HEADER_VER_BUFFER_UTTERANCE:
+                       recog_header->ver_buffer_utterance = src_recog_header->ver_buffer_utterance;
+                       break;
+               case RECOGNIZER_HEADER_RECOGNITION_MODE:
+                       apt_string_copy(&recog_header->recognition_mode,&src_recog_header->recognition_mode,pool);
+                       break;
+               case RECOGNIZER_HEADER_CANCEL_IF_QUEUE:
+                       recog_header->cancel_if_queue = src_recog_header->cancel_if_queue;
+                       break;
+               case RECOGNIZER_HEADER_HOTWORD_MAX_DURATION:
+                       recog_header->hotword_max_duration = src_recog_header->hotword_max_duration;
+                       break;
+               case RECOGNIZER_HEADER_HOTWORD_MIN_DURATION:
+                       recog_header->hotword_min_duration = src_recog_header->hotword_min_duration;
+                       break;
+               case RECOGNIZER_HEADER_INTERPRET_TEXT:
+                       apt_string_copy(&recog_header->interpret_text,&src_recog_header->interpret_text,pool);
+                       break;
+               case RECOGNIZER_HEADER_DTMF_BUFFER_TIME:
+                       recog_header->dtmf_buffer_time = src_recog_header->dtmf_buffer_time;
+                       break;
+               case RECOGNIZER_HEADER_CLEAR_DTMF_BUFFER:
+                       recog_header->clear_dtmf_buffer = src_recog_header->clear_dtmf_buffer;
+                       break;
+               case RECOGNIZER_HEADER_EARLY_NO_MATCH:
+                       recog_header->early_no_match = src_recog_header->early_no_match;
+                       break;
+               default:
+                       status = FALSE;
+       }
+       return status;
+}
+
+static APR_INLINE const apt_str_table_item_t* recog_header_string_table_get(mrcp_version_e version)
+{
+       if(version == MRCP_VERSION_1) {
+               return v1_recog_header_string_table;
+       }
+       return v2_recog_header_string_table;
+}
+
+static const mrcp_header_vtable_t v1_vtable = {
+       mrcp_recog_header_allocate,
+       NULL, /* nothing to destroy */
+       mrcp_v1_recog_header_parse,
+       mrcp_v1_recog_header_generate,
+       mrcp_recog_header_duplicate,
+       v1_recog_header_string_table,
+       RECOGNIZER_HEADER_COUNT
+};
+
+static const mrcp_header_vtable_t v2_vtable = {
+       mrcp_recog_header_allocate,
+       NULL, /* nothing to destroy */
+       mrcp_v2_recog_header_parse,
+       mrcp_v2_recog_header_generate,
+       mrcp_recog_header_duplicate,
+       v2_recog_header_string_table,
+       RECOGNIZER_HEADER_COUNT
+};
+
+MRCP_DECLARE(const mrcp_header_vtable_t*) mrcp_recog_header_vtable_get(mrcp_version_e version)
+{
+       if(version == MRCP_VERSION_1) {
+               return &v1_vtable;
+       }
+       return &v2_vtable;
+}
+
+MRCP_DECLARE(const apt_str_t*) mrcp_recog_completion_cause_get(mrcp_recog_completion_cause_e completion_cause, mrcp_version_e version)
+{
+       const apt_str_table_item_t *table = v2_completion_cause_string_table;
+       if(version == MRCP_VERSION_1) {
+               table = v1_completion_cause_string_table;
+       }
+
+       return apt_string_table_str_get(table,RECOGNIZER_COMPLETION_CAUSE_COUNT,completion_cause);
+}
diff --git a/libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_resource.c b/libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_resource.c
new file mode 100644 (file)
index 0000000..819b8b0
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mrcp_recog_resource.h"
+#include "mrcp_recog_header.h"
+#include "mrcp_recog_state_machine.h"
+#include "mrcp_resource.h"
+#include "mrcp_message.h"
+
+/** String table of MRCP recognizer methods (mrcp_recognizer_method_id) */
+static const apt_str_table_item_t v1_recog_method_string_table[] = {
+       {{"SET-PARAMS",               10},10},
+       {{"GET-PARAMS",               10},10},
+       {{"DEFINE-GRAMMAR",           14},0},
+       {{"RECOGNIZE",                 9},7},
+       {{"GET-RESULT",               10},4},
+       {{"RECOGNITION-START-TIMERS", 24},7},
+       {{"STOP",                      4},1}
+};
+
+/** String table of mrcpv2 recognizer methods (mrcp_recognizer_method_id) */
+static const apt_str_table_item_t v2_recog_method_string_table[] = {
+       {{"SET-PARAMS",               10},10},
+       {{"GET-PARAMS",               10},10},
+       {{"DEFINE-GRAMMAR",           14},0},
+       {{"RECOGNIZE",                 9},7},
+       {{"GET-RESULT",               10},4},
+       {{"START-INPUT-TIMERS",       18},2},
+       {{"STOP",                      4},2}
+};
+
+/** String table of MRCP recognizer events (mrcp_recognizer_event_id) */
+static const apt_str_table_item_t v1_recog_event_string_table[] = {
+       {{"START-OF-SPEECH",          15},0},
+       {{"RECOGNITION-COMPLETE",     20},0}
+};
+
+/** String table of mrcpv2 recognizer events (mrcp_recognizer_event_id) */
+static const apt_str_table_item_t v2_recog_event_string_table[] = {
+       {{"START-OF-INPUT",           14},0},
+       {{"RECOGNITION-COMPLETE",     20},0}
+};
+
+
+static APR_INLINE const apt_str_table_item_t* recog_method_string_table_get(mrcp_version_e version)
+{
+       if(version == MRCP_VERSION_1) {
+               return v1_recog_method_string_table;
+       }
+       return v2_recog_method_string_table;
+}
+
+static APR_INLINE const apt_str_table_item_t* recog_event_string_table_get(mrcp_version_e version)
+{
+       if(version == MRCP_VERSION_1) {
+               return v1_recog_event_string_table;
+       }
+       return v2_recog_event_string_table;
+}
+
+/** Set resource specifica data */
+static apt_bool_t recog_message_resourcify_by_id(mrcp_resource_t *resource, mrcp_message_t *message)
+{
+       /* associate method_name and method_id */
+       if(message->start_line.message_type == MRCP_MESSAGE_TYPE_REQUEST) {
+               const apt_str_t *name = apt_string_table_str_get(
+                       recog_method_string_table_get(message->start_line.version),
+                       RECOGNIZER_METHOD_COUNT,
+                       message->start_line.method_id);
+               if(!name) {
+                       return FALSE;
+               }
+               message->start_line.method_name = *name;
+       }
+       else if(message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
+               const apt_str_t *name = apt_string_table_str_get(
+                       recog_event_string_table_get(message->start_line.version),
+                       RECOGNIZER_EVENT_COUNT,
+                       message->start_line.method_id);
+               if(!name) {
+                       return FALSE;
+               }
+               message->start_line.method_name = *name;
+       }
+
+       message->header.resource_header_accessor.vtable = mrcp_recog_header_vtable_get(message->start_line.version);
+       return TRUE;
+}
+
+/** Set resource specifica data */
+static apt_bool_t recog_message_resourcify_by_name(mrcp_resource_t *resource, mrcp_message_t *message)
+{
+       /* associate method_name and method_id */
+       if(message->start_line.message_type == MRCP_MESSAGE_TYPE_REQUEST) {
+               message->start_line.method_id = apt_string_table_id_find(
+                       recog_method_string_table_get(message->start_line.version),
+                       RECOGNIZER_METHOD_COUNT,
+                       &message->start_line.method_name);
+               if(message->start_line.method_id >= RECOGNIZER_METHOD_COUNT) {
+                       return FALSE;
+               }
+       }
+       else if(message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
+               message->start_line.method_id = apt_string_table_id_find(
+                       recog_event_string_table_get(message->start_line.version),
+                       RECOGNIZER_EVENT_COUNT,
+                       &message->start_line.method_name);
+               if(message->start_line.method_id >= RECOGNIZER_EVENT_COUNT) {
+                       return FALSE;
+               }
+       }
+
+       message->header.resource_header_accessor.vtable = mrcp_recog_header_vtable_get(message->start_line.version);
+       return TRUE;
+}
+
+
+/** Create MRCP recognizer resource */
+MRCP_DECLARE(mrcp_resource_t*) mrcp_recog_resource_create(apr_pool_t *pool)
+{
+       mrcp_resource_t *resource = apr_palloc(pool,sizeof(mrcp_resource_t));
+       mrcp_resource_init(resource);
+
+       resource->resourcify_message_by_id = recog_message_resourcify_by_id;
+       resource->resourcify_message_by_name = recog_message_resourcify_by_name;
+
+       resource->create_client_state_machine = mrcp_recog_client_state_machine_create;
+       resource->create_server_state_machine = mrcp_recog_server_state_machine_create;
+       return resource;
+}
diff --git a/libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_server_state_machine.c b/libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_server_state_machine.c
new file mode 100644 (file)
index 0000000..13828ce
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apt_obj_list.h"
+#include "apt_log.h"
+#include "mrcp_state_machine.h"
+#include "mrcp_recog_state_machine.h"
+#include "mrcp_recog_header.h"
+#include "mrcp_generic_header.h"
+#include "mrcp_recog_resource.h"
+#include "mrcp_message.h"
+
+/** MRCP recognizer states */
+typedef enum {
+       RECOGNIZER_STATE_IDLE,
+       RECOGNIZER_STATE_RECOGNIZING,
+       RECOGNIZER_STATE_RECOGNIZED,
+
+       RECOGNIZER_STATE_COUNT
+} mrcp_recog_state_e;
+
+static const char * state_names[RECOGNIZER_STATE_COUNT] = {
+       "IDLE",
+       "RECOGNIZING",
+       "RECOGNIZED"
+};
+
+typedef struct mrcp_recog_state_machine_t mrcp_recog_state_machine_t;
+struct mrcp_recog_state_machine_t {
+       /** state machine base */
+       mrcp_state_machine_t  base;
+       /** recognizer state */
+       mrcp_recog_state_e    state;
+       /** indicate whether active_request was processed from pending request queue */
+       apt_bool_t            is_pending;
+       /** request sent to recognition engine and waiting for the response to be received */
+       mrcp_message_t       *active_request;
+       /** in-progress recognize request */
+       mrcp_message_t       *recog;
+       /** queue of pending recognition requests */
+       apt_obj_list_t       *queue;
+       /** properties used in set/get params */
+       mrcp_message_header_t properties;
+};
+
+typedef apt_bool_t (*recog_method_f)(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message);
+
+static APR_INLINE apt_bool_t recog_request_dispatch(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       state_machine->active_request = message;
+       return state_machine->base.dispatcher(&state_machine->base,message);
+}
+
+static APR_INLINE apt_bool_t recog_response_dispatch(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       state_machine->active_request = NULL;
+       return state_machine->base.dispatcher(&state_machine->base,message);
+}
+
+static APR_INLINE apt_bool_t recog_event_dispatch(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       return state_machine->base.dispatcher(&state_machine->base,message);
+}
+
+static APR_INLINE void recog_state_change(mrcp_recog_state_machine_t *state_machine, mrcp_recog_state_e state)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"State Transition %s -> %s",state_names[state_machine->state],state_names[state]);
+       state_machine->state = state;
+       if(state == RECOGNIZER_STATE_IDLE) {
+               state_machine->recog = NULL;
+       }
+}
+
+
+static apt_bool_t recog_request_set_params(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SET-PARAMS Request [%d]",message->start_line.request_id);
+       mrcp_message_header_set(&state_machine->properties,&message->header,message->pool);
+       return recog_request_dispatch(state_machine,message);
+}
+
+static apt_bool_t recog_response_set_params(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SET-PARAMS Response [%d]",message->start_line.request_id);
+       return recog_response_dispatch(state_machine,message);
+}
+
+static apt_bool_t recog_request_get_params(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process GET-PARAMS Request [%d]",message->start_line.request_id);
+       return recog_request_dispatch(state_machine,message);
+}
+
+static apt_bool_t recog_response_get_params(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process GET-PARAMS Response [%d]",message->start_line.request_id);
+       mrcp_message_header_set(&message->header,&state_machine->active_request->header,message->pool);
+       mrcp_message_header_get(&message->header,&state_machine->properties,message->pool);
+       return recog_response_dispatch(state_machine,message);
+}
+
+static apt_bool_t recog_request_define_grammar(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       if(state_machine->state == RECOGNIZER_STATE_RECOGNIZING) {
+               mrcp_message_t *response_message = mrcp_response_create(message,message->pool);
+               response_message->start_line.status_code = MRCP_STATUS_CODE_METHOD_NOT_VALID;
+               return recog_response_dispatch(state_machine,response_message);
+       }
+       else if(state_machine->state == RECOGNIZER_STATE_RECOGNIZED) {
+               recog_state_change(state_machine,RECOGNIZER_STATE_IDLE);
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process DEFINE-GRAMMAR Request [%d]",message->start_line.request_id);
+       return recog_request_dispatch(state_machine,message);
+}
+
+static apt_bool_t recog_response_define_grammar(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process DEFINE-GRAMMAR Response [%d]",message->start_line.request_id);
+       if(mrcp_resource_header_property_check(message,RECOGNIZER_HEADER_COMPLETION_CAUSE) != TRUE) {
+               mrcp_recog_header_t *recog_header = mrcp_resource_header_prepare(message);
+               recog_header->completion_cause = RECOGNIZER_COMPLETION_CAUSE_SUCCESS;
+               mrcp_resource_header_property_add(message,RECOGNIZER_HEADER_COMPLETION_CAUSE);
+       }
+       return recog_response_dispatch(state_machine,message);
+}
+
+static apt_bool_t recog_request_recognize(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       mrcp_message_header_inherit(&message->header,&state_machine->properties,message->pool);
+       if(state_machine->state == RECOGNIZER_STATE_RECOGNIZING) {
+               mrcp_message_t *response;
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Queue Up RECOGNIZE Request [%d]",message->start_line.request_id);
+               message->start_line.request_state = MRCP_REQUEST_STATE_PENDING;
+               apt_list_push_back(state_machine->queue,message,message->pool);
+               
+               response = mrcp_response_create(message,message->pool);
+               response->start_line.request_state = MRCP_REQUEST_STATE_PENDING;
+               return recog_response_dispatch(state_machine,response);
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process RECOGNIZE Request [%d]",message->start_line.request_id);
+       return recog_request_dispatch(state_machine,message);
+}
+
+static apt_bool_t recog_response_recognize(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process RECOGNIZE Response [%d]",message->start_line.request_id);
+       if(message->start_line.request_state == MRCP_REQUEST_STATE_INPROGRESS) {
+               state_machine->recog = state_machine->active_request;
+               recog_state_change(state_machine,RECOGNIZER_STATE_RECOGNIZING);
+       }
+       if(state_machine->is_pending == TRUE) {
+               state_machine->is_pending = FALSE;
+               /* not to send the response for pending request */
+               return TRUE;
+       }
+       return recog_response_dispatch(state_machine,message);
+}
+
+static apt_bool_t recog_request_get_result(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       mrcp_message_t *response_message;
+       if(state_machine->state == RECOGNIZER_STATE_RECOGNIZED) {
+               /* found recognized request */
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process GET-RESULT Request [%d]",message->start_line.request_id);
+               return recog_request_dispatch(state_machine,message);
+       }
+
+       /* found no recognized request */
+       response_message = mrcp_response_create(message,message->pool);
+       response_message->start_line.status_code = MRCP_STATUS_CODE_METHOD_NOT_VALID;
+       return recog_response_dispatch(state_machine,response_message);
+}
+
+static apt_bool_t recog_response_get_result(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process GET-RESULT Response [%d]",message->start_line.request_id);
+       return recog_response_dispatch(state_machine,message);
+}
+
+static apt_bool_t recog_request_recognition_start_timers(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       mrcp_message_t *response_message;
+       if(state_machine->state == RECOGNIZER_STATE_RECOGNIZING) {
+               /* found in-progress request */
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process START-INPUT-TIMERS Request [%d]",message->start_line.request_id);
+               return recog_request_dispatch(state_machine,message);
+       }
+
+       /* found no in-progress request */
+       response_message = mrcp_response_create(message,message->pool);
+       response_message->start_line.status_code = MRCP_STATUS_CODE_METHOD_NOT_VALID;
+       return recog_response_dispatch(state_machine,response_message);
+}
+
+static apt_bool_t recog_response_recognition_start_timers(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process START-INPUT-TIMERS Response [%d]",message->start_line.request_id);
+       return recog_response_dispatch(state_machine,message);
+}
+
+static apt_bool_t recog_pending_requests_remove(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *request_message, mrcp_message_t *response_message)
+{
+       apt_list_elem_t *elem;
+       mrcp_message_t *pending_message;
+       mrcp_request_id_list_t *request_id_list = NULL;
+       mrcp_generic_header_t *generic_header = mrcp_generic_header_get(request_message);
+       mrcp_generic_header_t *response_generic_header = mrcp_generic_header_prepare(response_message);
+       if(generic_header && mrcp_generic_header_property_check(request_message,GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST) == TRUE) {
+               if(generic_header->active_request_id_list.ids && generic_header->active_request_id_list.count) {
+                       /* selective STOP request */
+                       request_id_list = &generic_header->active_request_id_list;
+               }
+       }
+
+       elem = apt_list_first_elem_get(state_machine->queue);
+       while(elem) {
+               pending_message = apt_list_elem_object_get(elem);
+               if(!request_id_list || active_request_id_list_find(generic_header,pending_message->start_line.request_id) == TRUE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remove Pending RECOGNIZE Request [%d]",pending_message->start_line.request_id);
+                       elem = apt_list_elem_remove(state_machine->queue,elem);
+                       /* append active id list */
+                       active_request_id_list_append(response_generic_header,pending_message->start_line.request_id);
+               }
+               else {
+                       /* speak request remains in the queue, just proceed to the next one */
+                       elem = apt_list_next_elem_get(state_machine->queue,elem);
+               }
+       }
+       if(response_generic_header->active_request_id_list.count) {
+               mrcp_generic_header_property_add(response_message,GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST);
+       }
+       return TRUE;
+}
+
+static apt_bool_t recog_request_stop(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       mrcp_message_t *response_message;
+       if(state_machine->state == RECOGNIZER_STATE_RECOGNIZING) {
+               mrcp_request_id_list_t *request_id_list = NULL;
+               mrcp_generic_header_t *generic_header = mrcp_generic_header_get(message);
+               if(generic_header && mrcp_generic_header_property_check(message,GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST) == TRUE) {
+                       if(generic_header->active_request_id_list.ids && generic_header->active_request_id_list.count) {
+                               /* selective STOP request */
+                               request_id_list = &generic_header->active_request_id_list;
+                       }
+               }
+
+               if(!request_id_list || active_request_id_list_find(generic_header,state_machine->recog->start_line.request_id) == TRUE) {
+                       /* found in-progress RECOGNIZE request, stop it */
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process STOP Request [%d]",message->start_line.request_id);
+                       return recog_request_dispatch(state_machine,message);
+               }
+       }
+       else if(state_machine->state == RECOGNIZER_STATE_RECOGNIZED) {
+               recog_state_change(state_machine,RECOGNIZER_STATE_IDLE);
+       }
+
+       /* found no in-progress RECOGNIZE request, sending immediate response */
+       response_message = mrcp_response_create(message,message->pool);
+       recog_pending_requests_remove(state_machine,message,response_message);
+       return recog_response_dispatch(state_machine,response_message);
+}
+
+static apt_bool_t recog_response_stop(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       mrcp_message_t *pending_request;
+       mrcp_generic_header_t *generic_header = mrcp_generic_header_prepare(message);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process STOP Response [%d]",message->start_line.request_id);
+       /* append active id list */
+       active_request_id_list_append(generic_header,state_machine->recog->start_line.request_id);
+       mrcp_generic_header_property_add(message,GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST);
+       recog_pending_requests_remove(state_machine,state_machine->active_request,message);
+       recog_state_change(state_machine,RECOGNIZER_STATE_IDLE);
+       recog_response_dispatch(state_machine,message);
+
+       /* process pending RECOGNIZE requests / if any */
+       pending_request = apt_list_pop_front(state_machine->queue);
+       if(pending_request) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process Pending RECOGNIZE Request [%d]",pending_request->start_line.request_id);
+               state_machine->is_pending = TRUE;
+               recog_request_dispatch(state_machine,pending_request);
+       }
+       return TRUE;
+}
+
+static apt_bool_t recog_event_start_of_input(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       if(!state_machine->recog) {
+               /* unexpected event, no in-progress recognition request */
+               return FALSE;
+       }
+
+       if(state_machine->recog->start_line.request_id != message->start_line.request_id) {
+               /* unexpected event */
+               return FALSE;
+       }
+       
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process START-OF-INPUT Event [%d]",message->start_line.request_id);
+       message->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS;
+       return recog_event_dispatch(state_machine,message);
+}
+
+static apt_bool_t recog_event_recognition_complete(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       mrcp_message_t *pending_request;
+       if(!state_machine->recog) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected RECOGNITION-COMPLETE Event [%d]",message->start_line.request_id);
+               return FALSE;
+       }
+
+       if(state_machine->recog->start_line.request_id != message->start_line.request_id) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected RECOGNITION-COMPLETE Event [%d]",message->start_line.request_id);
+               return FALSE;
+       }
+
+       if(state_machine->active_request && state_machine->active_request->start_line.method_id == RECOGNIZER_STOP) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Ignore RECOGNITION-COMPLETE Event [%d]: waiting for STOP response",message->start_line.request_id);
+               return FALSE;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process RECOGNITION-COMPLETE Event [%d]",message->start_line.request_id);
+       if(mrcp_resource_header_property_check(message,RECOGNIZER_HEADER_COMPLETION_CAUSE) != TRUE) {
+               mrcp_recog_header_t *recog_header = mrcp_resource_header_prepare(message);
+               recog_header->completion_cause = RECOGNIZER_COMPLETION_CAUSE_SUCCESS;
+               mrcp_resource_header_property_add(message,RECOGNIZER_HEADER_COMPLETION_CAUSE);
+       }
+       recog_state_change(state_machine,RECOGNIZER_STATE_RECOGNIZED);
+       recog_event_dispatch(state_machine,message);
+
+       /* process pending RECOGNIZE requests */
+       pending_request = apt_list_pop_front(state_machine->queue);
+       if(pending_request) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process Pending RECOGNIZE Request [%d]",pending_request->start_line.request_id);
+               state_machine->is_pending = TRUE;
+               recog_request_dispatch(state_machine,pending_request);
+       }
+       return TRUE;
+}
+
+static recog_method_f recog_request_method_array[RECOGNIZER_METHOD_COUNT] = {
+       recog_request_set_params,
+       recog_request_get_params,
+       recog_request_define_grammar,
+       recog_request_recognize,
+       recog_request_get_result,
+       recog_request_recognition_start_timers,
+       recog_request_stop
+};
+
+static recog_method_f recog_response_method_array[RECOGNIZER_METHOD_COUNT] = {
+       recog_response_set_params,
+       recog_response_get_params,
+       recog_response_define_grammar,
+       recog_response_recognize,
+       recog_response_get_result,
+       recog_response_recognition_start_timers,
+       recog_response_stop
+};
+
+static recog_method_f recog_event_method_array[RECOGNIZER_EVENT_COUNT] = {
+       recog_event_start_of_input,
+       recog_event_recognition_complete
+};
+
+/** Update state according to received incoming request from MRCP client */
+static apt_bool_t recog_request_state_update(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       recog_method_f method;
+       if(message->start_line.method_id >= RECOGNIZER_METHOD_COUNT) {
+               return FALSE;
+       }
+       
+       method = recog_request_method_array[message->start_line.method_id];
+       if(method) {
+               return method(state_machine,message);
+       }
+       return recog_request_dispatch(state_machine,message);
+}
+
+/** Update state according to received outgoing response from recognition engine */
+static apt_bool_t recog_response_state_update(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       recog_method_f method;
+       if(!state_machine->active_request) {
+               /* unexpected response, no active request waiting for response */
+               return FALSE;
+       }
+       if(state_machine->active_request->start_line.request_id != message->start_line.request_id) {
+               /* unexpected response, request id doesn't match */
+               return FALSE;
+       }
+
+       if(message->start_line.method_id >= RECOGNIZER_METHOD_COUNT) {
+               return FALSE;
+       }
+       
+       method = recog_response_method_array[message->start_line.method_id];
+       if(method) {
+               return method(state_machine,message);
+       }
+       return recog_response_dispatch(state_machine,message);
+}
+
+/** Update state according to received outgoing event from recognition engine */
+static apt_bool_t recog_event_state_update(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       recog_method_f method;
+       if(message->start_line.method_id >= RECOGNIZER_EVENT_COUNT) {
+               return FALSE;
+       }
+       
+       method = recog_event_method_array[message->start_line.method_id];
+       if(method) {
+               return method(state_machine,message);
+       }
+       return recog_event_dispatch(state_machine,message);
+}
+
+/** Update state according to request received from MRCP client or response/event received from recognition engine */
+static apt_bool_t recog_state_update(mrcp_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       mrcp_recog_state_machine_t *recog_state_machine = (mrcp_recog_state_machine_t*)state_machine;
+       apt_bool_t status = TRUE;
+       switch(message->start_line.message_type) {
+               case MRCP_MESSAGE_TYPE_REQUEST:
+                       status = recog_request_state_update(recog_state_machine,message);
+                       break;
+               case MRCP_MESSAGE_TYPE_RESPONSE:
+                       status = recog_response_state_update(recog_state_machine,message);
+                       break;
+               case MRCP_MESSAGE_TYPE_EVENT:
+                       status = recog_event_state_update(recog_state_machine,message);
+                       break;
+               default:
+                       status = FALSE;
+                       break;
+       }
+       return status;
+}
+
+/** Create MRCP recognizer server state machine */
+mrcp_state_machine_t* mrcp_recog_server_state_machine_create(void *obj, mrcp_message_dispatcher_f dispatcher, mrcp_version_e version, apr_pool_t *pool)
+{
+       mrcp_message_header_t *properties;
+       mrcp_recog_state_machine_t *state_machine = apr_palloc(pool,sizeof(mrcp_recog_state_machine_t));
+       mrcp_state_machine_init(&state_machine->base,obj,dispatcher);
+       state_machine->base.update = recog_state_update;
+       state_machine->state = RECOGNIZER_STATE_IDLE;
+       state_machine->is_pending = FALSE;
+       state_machine->active_request = NULL;
+       state_machine->recog = NULL;
+       state_machine->queue = apt_list_create(pool);
+       properties = &state_machine->properties;
+       mrcp_message_header_init(properties);
+       properties->generic_header_accessor.vtable = mrcp_generic_header_vtable_get(version);
+       properties->resource_header_accessor.vtable = mrcp_recog_header_vtable_get(version);
+       return &state_machine->base;
+}
diff --git a/libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_client_state_machine.c b/libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_client_state_machine.c
new file mode 100644 (file)
index 0000000..6dd4da2
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mrcp_state_machine.h"
+#include "mrcp_synth_state_machine.h"
+#include "mrcp_message.h"
+
+
+/** Update state according to request received from user level or response/event received from MRCP server */
+static apt_bool_t synth_state_update(mrcp_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       /* no actual state machine processing yet, dispatch whatever received */
+       return state_machine->dispatcher(state_machine,message);
+}
+
+/** Create MRCP synthesizer client state machine */
+mrcp_state_machine_t* mrcp_synth_client_state_machine_create(void *obj, mrcp_message_dispatcher_f dispatcher, mrcp_version_e version, apr_pool_t *pool)
+{
+       mrcp_state_machine_t *state_machine = apr_palloc(pool,sizeof(mrcp_state_machine_t));
+       mrcp_state_machine_init(state_machine,obj,dispatcher);
+       state_machine->update = synth_state_update;
+       return state_machine;
+}
diff --git a/libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_header.c b/libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_header.c
new file mode 100644 (file)
index 0000000..e7c467f
--- /dev/null
@@ -0,0 +1,558 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mrcp_synth_header.h"
+
+/** String table of MRCP synthesizer headers (mrcp_synthesizer_header_id) */
+static const apt_str_table_item_t synth_header_string_table[] = {
+       {{"Jump-Size",            9},0},
+       {{"Kill-On-Barge-In",    16},0},
+       {{"Speaker-Profile",     15},8},
+       {{"Completion-Cause",    16},16},
+       {{"Completion-Reason",   17},13},
+       {{"Voice-Gender",        12},6},
+       {{"Voice-Age",            9},6},
+       {{"Voice-Variant",       13},6},
+       {{"Voice-Name",          10},8},
+       {{"Prosody-Volume",      14},8},
+       {{"Prosody-Rate",        12},12},
+       {{"Speech-Marker",       13},7},
+       {{"Speech-Language",     15},7},
+       {{"Fetch-Hint",          10},2},
+       {{"Audio-Fetch-Hint",    16},0},
+       {{"Failed-Uri",          10},10},
+       {{"Failed-Uri_Cause",    16},10},
+       {{"Speak-Restart",       13},13},
+       {{"Speak-Length",        12},6},
+       {{"Load-Lexicon",        12},2},
+       {{"Lexicon-Search-Order",20},2}
+};
+
+/** String table of MRCP speech-unit fields (mrcp_speech_unit_t) */
+static const apt_str_table_item_t speech_unit_string_table[] = {
+       {{"Second",   6},2},
+       {{"Word",     4},0},
+       {{"Sentence", 8},2},
+       {{"Paragraph",9},0}
+};
+
+/** String table of MRCP voice-gender fields (mrcp_voice_gender_t) */
+static const apt_str_table_item_t voice_gender_string_table[] = {
+       {{"male",   4},0},
+       {{"female", 6},0},
+       {{"neutral",7},0}
+};
+
+/** String table of MRCP prosody-volume fields (mrcp_prosody_volume_t) */
+static const apt_str_table_item_t prosody_volume_string_table[] = {
+       {{"silent", 6},1},
+       {{"x-soft", 6},2},
+       {{"soft",   4},3},
+       {{"medium", 6},0},
+       {{"loud",   4},0},
+       {{"x-loud", 6},5},
+       {{"default",7},0} 
+};
+
+/** String table of MRCP prosody-rate fields (mrcp_prosody_rate_t) */
+static const apt_str_table_item_t prosody_rate_string_table[] = {
+       {{"x-slow", 6},3},
+       {{"slow",   4},0},
+       {{"medium", 6},0},
+       {{"fast",   4},0},
+       {{"x-fast", 6},4},
+       {{"default",7},0}
+};
+
+/** String table of MRCP synthesizer completion-cause fields (mrcp_synthesizer_completion_cause_t) */
+static const apt_str_table_item_t completion_cause_string_table[] = {
+       {{"normal",               6},0},
+       {{"barge-in",             8},0},
+       {{"parse-failure",       13},0},
+       {{"uri-failure",         11},0},
+       {{"error",                5},0},
+       {{"language-unsupported",20},4},
+       {{"lexicon-load-failure",20},1},
+       {{"cancelled",            9},0}
+};
+
+
+static APR_INLINE apr_size_t apt_string_table_value_parse(const apt_str_table_item_t *string_table, size_t count, const apt_str_t *value)
+{
+       return apt_string_table_id_find(string_table,count,value);
+}
+
+static apt_bool_t apt_string_table_value_generate(const apt_str_table_item_t *string_table, size_t count, size_t id, apt_text_stream_t *stream)
+{
+       const apt_str_t *name = apt_string_table_str_get(string_table,count,id);
+       if(!name) {
+               return FALSE;
+       }
+
+       memcpy(stream->pos,name->buf,name->length);
+       stream->pos += name->length;
+       return TRUE;
+}
+
+/** Parse MRCP prosody-rate value */
+static apt_bool_t mrcp_prosody_param_rate_parse(mrcp_prosody_rate_t *prosody_rate, const apt_str_t *value, apr_pool_t *pool)
+{
+       if(!value->length) {
+               return FALSE;
+       }
+
+       /** For the rate attribute, relative changes are a number. (not preceded by a "+" or "-")(w3c ssml)*/
+       if('0'<=value->buf[0] && value->buf[0]<='9') {
+               prosody_rate->type = PROSODY_RATE_TYPE_RELATIVE_CHANGE;
+       }
+       else {
+               prosody_rate->type = PROSODY_RATE_TYPE_LABEL;
+       }
+
+       if(prosody_rate->type == PROSODY_RATE_TYPE_RELATIVE_CHANGE) {
+               prosody_rate->value.relative = apt_float_value_parse(value);
+       }
+       else {
+               prosody_rate->value.label = apt_string_table_value_parse(prosody_rate_string_table,PROSODY_RATE_COUNT,value);
+       }
+
+       return TRUE;
+}
+
+/** Generate MRCP prosody-rate value */
+static apt_bool_t mrcp_prosody_rate_generate(mrcp_prosody_rate_t *prosody_rate, apt_text_stream_t *stream)
+{
+       if(prosody_rate->type == PROSODY_RATE_TYPE_LABEL) {
+               apt_string_table_value_generate(prosody_rate_string_table,PROSODY_RATE_COUNT,prosody_rate->value.label,stream);
+       }
+       else {
+               apt_float_value_generate(prosody_rate->value.relative, stream);
+       }
+
+       return TRUE;
+}
+
+/** Parse MRCP prosody-volume value */
+static apt_bool_t mrcp_prosody_param_volume_parse(mrcp_prosody_volume_t *prosody_volume, const apt_str_t *value, apr_pool_t *pool)
+{
+       if(!value->length) {
+               return FALSE;
+       }
+
+       /** For the volume attribute, relative changes are a number preceded by "+" or "-" (w3c ssml)*/
+       if(value->buf[0]=='+' || value->buf[0]=='-') {
+               prosody_volume->type = PROSODY_VOLUME_TYPE_RELATIVE_CHANGE;
+       }
+       else if('0'<=value->buf[0] && value->buf[0]<='9') {
+               prosody_volume->type = PROSODY_VOLUME_TYPE_NUMERIC;
+       }
+       else {
+               prosody_volume->type = PROSODY_VOLUME_TYPE_LABEL;
+       }
+
+       if(prosody_volume->type == PROSODY_VOLUME_TYPE_RELATIVE_CHANGE) {
+               prosody_volume->value.relative = apt_float_value_parse(value);
+       }
+       else if(prosody_volume->type == PROSODY_VOLUME_TYPE_NUMERIC) {
+               prosody_volume->value.numeric = apt_float_value_parse(value);
+       }
+       else {
+               prosody_volume->value.label = apt_string_table_value_parse(prosody_volume_string_table,PROSODY_VOLUME_COUNT,value);
+       }
+
+       return TRUE;
+}
+
+/** Generate MRCP prosody-volume value */
+static apt_bool_t mrcp_prosody_volume_generate(mrcp_prosody_volume_t *prosody_volume, apt_text_stream_t *stream)
+{
+       if(prosody_volume->type == PROSODY_VOLUME_TYPE_LABEL) {
+               apt_string_table_value_generate(prosody_volume_string_table,PROSODY_VOLUME_COUNT,prosody_volume->value.label,stream);
+       }
+       else if (prosody_volume->type == PROSODY_VOLUME_TYPE_NUMERIC) {
+               apt_float_value_generate(prosody_volume->value.numeric, stream);
+       }
+       else {
+               apt_float_value_generate(prosody_volume->value.relative, stream);
+       }
+
+       return TRUE;
+}
+
+/** Parse MRCP speech-length value */
+static apt_bool_t mrcp_speech_length_value_parse(mrcp_speech_length_value_t *speech_length, const apt_str_t *value, apr_pool_t *pool)
+{
+       if(!value->length) {
+               return FALSE;
+       }
+
+       switch(*value->buf) {
+               case '+': speech_length->type = SPEECH_LENGTH_TYPE_NUMERIC_POSITIVE; break;
+               case '-': speech_length->type = SPEECH_LENGTH_TYPE_NUMERIC_NEGATIVE; break;
+               default : speech_length->type = SPEECH_LENGTH_TYPE_TEXT;
+       }
+
+       if(speech_length->type == SPEECH_LENGTH_TYPE_TEXT) {
+               apt_string_copy(&speech_length->value.tag,value,pool);
+       }
+       else {
+               mrcp_numeric_speech_length_t *numeric = &speech_length->value.numeric;
+               apt_str_t str;
+               apt_text_stream_t stream;
+               stream.text = *value;
+               stream.pos = stream.text.buf;
+               stream.pos++;
+               if(apt_text_field_read(&stream,APT_TOKEN_SP,TRUE,&str) == FALSE) {
+                       return FALSE;
+               }
+               numeric->length = apt_size_value_parse(&str);
+
+               if(apt_text_field_read(&stream,APT_TOKEN_SP,TRUE,&str) == FALSE) {
+                       return FALSE;
+               }
+               numeric->unit = apt_string_table_value_parse(speech_unit_string_table,SPEECH_UNIT_COUNT,&str);
+       }
+       return TRUE;
+}
+
+/** Generate MRCP speech-length value */
+static apt_bool_t mrcp_speech_length_generate(mrcp_speech_length_value_t *speech_length, apt_text_stream_t *stream)
+{
+       if(speech_length->type == SPEECH_LENGTH_TYPE_TEXT) {
+               apt_str_t *tag = &speech_length->value.tag;
+               if(tag->length) {
+                       memcpy(stream->pos,tag->buf,tag->length);
+                       stream->pos += tag->length;
+               }
+       }
+       else {
+               if(speech_length->type == SPEECH_LENGTH_TYPE_NUMERIC_POSITIVE) {
+                       *stream->pos++ = '+';
+               }
+               else {
+                       *stream->pos++ = '-';
+               }
+               apt_size_value_generate(speech_length->value.numeric.length,stream);
+               *stream->pos++ = ' ';
+               apt_string_table_value_generate(speech_unit_string_table,SPEECH_UNIT_COUNT,speech_length->value.numeric.unit,stream);
+       }
+       return TRUE;
+}
+
+/** Generate MRCP synthesizer completion-cause */
+static apt_bool_t mrcp_completion_cause_generate(mrcp_synth_completion_cause_e completion_cause, apt_text_stream_t *stream)
+{
+       int length;
+       const apt_str_t *name = apt_string_table_str_get(completion_cause_string_table,SYNTHESIZER_COMPLETION_CAUSE_COUNT,completion_cause);
+       if(!name) {
+               return FALSE;
+       }
+       length = sprintf(stream->pos,"%03"APR_SIZE_T_FMT" ",completion_cause);
+       if(length <= 0) {
+               return FALSE;
+       }
+       stream->pos += length;
+
+       memcpy(stream->pos,name->buf,name->length);
+       stream->pos += name->length;
+       return TRUE;
+}
+
+/** Initialize synthesizer header */
+static void mrcp_synth_header_init(mrcp_synth_header_t *synth_header)
+{
+       synth_header->jump_size.type = SPEECH_LENGTH_TYPE_UNKNOWN;
+       synth_header->kill_on_barge_in = FALSE;
+       apt_string_reset(&synth_header->speaker_profile);
+       synth_header->completion_cause = SYNTHESIZER_COMPLETION_CAUSE_UNKNOWN;
+       apt_string_reset(&synth_header->completion_reason);
+       synth_header->voice_param.gender = VOICE_GENDER_UNKNOWN;
+       synth_header->voice_param.age = 0;
+       synth_header->voice_param.variant = 0;
+       apt_string_reset(&synth_header->voice_param.name);
+       synth_header->prosody_param.volume.type = PROSODY_VOLUME_TYPE_UNKNOWN;
+       synth_header->prosody_param.rate.type = PROSODY_RATE_TYPE_UNKNOWN;
+       apt_string_reset(&synth_header->speech_marker);
+       apt_string_reset(&synth_header->speech_language);
+       apt_string_reset(&synth_header->fetch_hint);
+       apt_string_reset(&synth_header->audio_fetch_hint);
+       apt_string_reset(&synth_header->failed_uri);
+       apt_string_reset(&synth_header->failed_uri_cause);
+       synth_header->speak_restart = FALSE;
+       synth_header->speak_length.type = SPEECH_LENGTH_TYPE_UNKNOWN;
+       synth_header->load_lexicon = FALSE;
+       apt_string_reset(&synth_header->lexicon_search_order);
+}
+
+
+/** Allocate MRCP synthesizer header */
+static void* mrcp_synth_header_allocate(mrcp_header_accessor_t *accessor, apr_pool_t *pool)
+{
+       mrcp_synth_header_t *synth_header = apr_palloc(pool,sizeof(mrcp_synth_header_t));
+       mrcp_synth_header_init(synth_header);
+       accessor->data = synth_header;
+       return accessor->data;
+}
+
+/** Parse MRCP synthesizer header */
+static apt_bool_t mrcp_synth_header_parse(mrcp_header_accessor_t *accessor, size_t id, const apt_str_t *value, apr_pool_t *pool)
+{
+       apt_bool_t status = TRUE;
+       mrcp_synth_header_t *synth_header = accessor->data;
+       switch(id) {
+               case SYNTHESIZER_HEADER_JUMP_SIZE:
+                       mrcp_speech_length_value_parse(&synth_header->jump_size,value,pool);
+                       break;
+               case SYNTHESIZER_HEADER_KILL_ON_BARGE_IN:
+                       apt_boolean_value_parse(value,&synth_header->kill_on_barge_in);
+                       break;
+               case SYNTHESIZER_HEADER_SPEAKER_PROFILE:
+                       apt_string_copy(&synth_header->speaker_profile,value,pool);
+                       break;
+               case SYNTHESIZER_HEADER_COMPLETION_CAUSE:
+                       synth_header->completion_cause = apt_size_value_parse(value);
+                       break;
+               case SYNTHESIZER_HEADER_COMPLETION_REASON:
+                       apt_string_copy(&synth_header->completion_reason,value,pool);
+                       break;
+               case SYNTHESIZER_HEADER_VOICE_GENDER:
+                       synth_header->voice_param.gender = apt_string_table_value_parse(voice_gender_string_table,VOICE_GENDER_COUNT,value);
+                       break;
+               case SYNTHESIZER_HEADER_VOICE_AGE:
+                       synth_header->voice_param.age = apt_size_value_parse(value);
+                       break;
+               case SYNTHESIZER_HEADER_VOICE_VARIANT:
+                       synth_header->voice_param.variant = apt_size_value_parse(value);
+                       break;
+               case SYNTHESIZER_HEADER_VOICE_NAME:
+                       apt_string_copy(&synth_header->voice_param.name,value,pool);
+                       break;
+               case SYNTHESIZER_HEADER_PROSODY_VOLUME:
+                       mrcp_prosody_param_volume_parse(&synth_header->prosody_param.volume,value,pool);
+                       break;
+               case SYNTHESIZER_HEADER_PROSODY_RATE:
+                       mrcp_prosody_param_rate_parse(&synth_header->prosody_param.rate,value,pool);
+                       break;
+               case SYNTHESIZER_HEADER_SPEECH_MARKER:
+                       apt_string_copy(&synth_header->speech_marker,value,pool);
+                       break;
+               case SYNTHESIZER_HEADER_SPEECH_LANGUAGE:
+                       apt_string_copy(&synth_header->speech_language,value,pool);
+                       break;
+               case SYNTHESIZER_HEADER_FETCH_HINT:
+                       apt_string_copy(&synth_header->fetch_hint,value,pool);
+                       break;
+               case SYNTHESIZER_HEADER_AUDIO_FETCH_HINT:
+                       apt_string_copy(&synth_header->audio_fetch_hint,value,pool);
+                       break;
+               case SYNTHESIZER_HEADER_FAILED_URI:
+                       apt_string_copy(&synth_header->failed_uri,value,pool);
+                       break;
+               case SYNTHESIZER_HEADER_FAILED_URI_CAUSE:
+                       apt_string_copy(&synth_header->failed_uri_cause,value,pool);
+                       break;
+               case SYNTHESIZER_HEADER_SPEAK_RESTART:
+                       apt_boolean_value_parse(value,&synth_header->speak_restart);
+                       break;
+               case SYNTHESIZER_HEADER_SPEAK_LENGTH:
+                       mrcp_speech_length_value_parse(&synth_header->speak_length,value,pool);
+                       break;
+               case SYNTHESIZER_HEADER_LOAD_LEXICON:
+                       apt_boolean_value_parse(value,&synth_header->load_lexicon);
+                       break;
+               case SYNTHESIZER_HEADER_LEXICON_SEARCH_ORDER:
+                       apt_string_copy(&synth_header->lexicon_search_order,value,pool);
+                       break;
+               default:
+                       status = FALSE;
+       }
+       return status;
+}
+
+/** Generate MRCP synthesizer header */
+static apt_bool_t mrcp_synth_header_generate(mrcp_header_accessor_t *accessor, size_t id, apt_text_stream_t *value)
+{
+       mrcp_synth_header_t *synth_header = accessor->data;
+       switch(id) {
+               case SYNTHESIZER_HEADER_JUMP_SIZE:
+                       mrcp_speech_length_generate(&synth_header->jump_size,value);
+                       break;
+               case SYNTHESIZER_HEADER_KILL_ON_BARGE_IN:
+                       apt_boolean_value_generate(synth_header->kill_on_barge_in,value);
+                       break;
+               case SYNTHESIZER_HEADER_SPEAKER_PROFILE:
+                       apt_string_value_generate(&synth_header->speaker_profile,value);
+                       break;
+               case SYNTHESIZER_HEADER_COMPLETION_CAUSE:
+                       mrcp_completion_cause_generate(synth_header->completion_cause,value);
+                       break;
+               case SYNTHESIZER_HEADER_COMPLETION_REASON:
+                       apt_string_value_generate(&synth_header->completion_reason,value);
+                       break;
+               case SYNTHESIZER_HEADER_VOICE_GENDER:
+                       apt_string_table_value_generate(voice_gender_string_table,VOICE_GENDER_COUNT,synth_header->voice_param.gender,value);
+                       break;
+               case SYNTHESIZER_HEADER_VOICE_AGE:
+                       apt_size_value_generate(synth_header->voice_param.age,value);
+                       break;
+               case SYNTHESIZER_HEADER_VOICE_VARIANT:
+                       apt_size_value_generate(synth_header->voice_param.variant,value);
+                       break;
+               case SYNTHESIZER_HEADER_VOICE_NAME:
+                       apt_string_value_generate(&synth_header->voice_param.name,value);
+                       break;
+               case SYNTHESIZER_HEADER_PROSODY_VOLUME:
+                       mrcp_prosody_volume_generate(&synth_header->prosody_param.volume,value);
+                       break;
+               case SYNTHESIZER_HEADER_PROSODY_RATE:
+                       mrcp_prosody_rate_generate(&synth_header->prosody_param.rate,value);
+                       break;
+               case SYNTHESIZER_HEADER_SPEECH_MARKER:
+                       apt_string_value_generate(&synth_header->speech_marker,value);
+                       break;
+               case SYNTHESIZER_HEADER_SPEECH_LANGUAGE:
+                       apt_string_value_generate(&synth_header->speech_language,value);
+                       break;
+               case SYNTHESIZER_HEADER_FETCH_HINT:
+                       apt_string_value_generate(&synth_header->fetch_hint,value);
+                       break;
+               case SYNTHESIZER_HEADER_AUDIO_FETCH_HINT:
+                       apt_string_value_generate(&synth_header->audio_fetch_hint,value);
+                       break;
+               case SYNTHESIZER_HEADER_FAILED_URI:
+                       apt_string_value_generate(&synth_header->failed_uri,value);
+                       break;
+               case SYNTHESIZER_HEADER_FAILED_URI_CAUSE:
+                       apt_string_value_generate(&synth_header->failed_uri_cause,value);
+                       break;
+               case SYNTHESIZER_HEADER_SPEAK_RESTART:
+                       apt_boolean_value_generate(synth_header->speak_restart,value);
+                       break;
+               case SYNTHESIZER_HEADER_SPEAK_LENGTH:
+                       mrcp_speech_length_generate(&synth_header->speak_length,value);
+                       break;
+               case SYNTHESIZER_HEADER_LOAD_LEXICON:
+                       apt_boolean_value_generate(synth_header->load_lexicon,value);
+                       break;
+               case SYNTHESIZER_HEADER_LEXICON_SEARCH_ORDER:
+                       apt_string_value_generate(&synth_header->lexicon_search_order,value);
+                       break;
+               default:
+                       break;
+       }
+       return TRUE;
+}
+
+/** Duplicate MRCP synthesizer header */
+static apt_bool_t mrcp_synth_header_duplicate(mrcp_header_accessor_t *accessor, const mrcp_header_accessor_t *src, size_t id, apr_pool_t *pool)
+{
+       mrcp_synth_header_t *synth_header = accessor->data;
+       const mrcp_synth_header_t *src_synth_header = src->data;
+       apt_bool_t status = TRUE;
+
+       if(!synth_header || !src_synth_header) {
+               return FALSE;
+       }
+
+       switch(id) {
+               case SYNTHESIZER_HEADER_JUMP_SIZE:
+                       synth_header->jump_size = src_synth_header->jump_size;
+                       break;
+               case SYNTHESIZER_HEADER_KILL_ON_BARGE_IN:
+                       synth_header->kill_on_barge_in = src_synth_header->kill_on_barge_in;
+                       break;
+               case SYNTHESIZER_HEADER_SPEAKER_PROFILE:
+                       apt_string_copy(&synth_header->speaker_profile,&src_synth_header->speaker_profile,pool);
+                       break;
+               case SYNTHESIZER_HEADER_COMPLETION_CAUSE:
+                       synth_header->completion_cause = src_synth_header->completion_cause;
+                       break;
+               case SYNTHESIZER_HEADER_COMPLETION_REASON:
+                       apt_string_copy(&synth_header->completion_reason,&src_synth_header->completion_reason,pool);
+                       break;
+               case SYNTHESIZER_HEADER_VOICE_GENDER:
+                       synth_header->voice_param.gender = src_synth_header->voice_param.gender;
+                       break;
+               case SYNTHESIZER_HEADER_VOICE_AGE:
+                       synth_header->voice_param.age = src_synth_header->voice_param.age;
+                       break;
+               case SYNTHESIZER_HEADER_VOICE_VARIANT:
+                       synth_header->voice_param.variant = src_synth_header->voice_param.variant;
+                       break;
+               case SYNTHESIZER_HEADER_VOICE_NAME:
+                       apt_string_copy(&synth_header->voice_param.name,&src_synth_header->voice_param.name,pool);
+                       break;
+               case SYNTHESIZER_HEADER_PROSODY_VOLUME:
+                       synth_header->prosody_param.volume = src_synth_header->prosody_param.volume;
+                       break;
+               case SYNTHESIZER_HEADER_PROSODY_RATE:
+                       synth_header->prosody_param.rate = src_synth_header->prosody_param.rate;
+                       break;
+               case SYNTHESIZER_HEADER_SPEECH_MARKER:
+                       apt_string_copy(&synth_header->speech_marker,&src_synth_header->speech_marker,pool);
+                       break;
+               case SYNTHESIZER_HEADER_SPEECH_LANGUAGE:
+                       apt_string_copy(&synth_header->speech_language,&src_synth_header->speech_language,pool);
+                       break;
+               case SYNTHESIZER_HEADER_FETCH_HINT:
+                       apt_string_copy(&synth_header->fetch_hint,&src_synth_header->fetch_hint,pool);
+                       break;
+               case SYNTHESIZER_HEADER_AUDIO_FETCH_HINT:
+                       apt_string_copy(&synth_header->audio_fetch_hint,&src_synth_header->audio_fetch_hint,pool);
+                       break;
+               case SYNTHESIZER_HEADER_FAILED_URI:
+                       apt_string_copy(&synth_header->failed_uri,&src_synth_header->failed_uri,pool);
+                       break;
+               case SYNTHESIZER_HEADER_FAILED_URI_CAUSE:
+                       apt_string_copy(&synth_header->failed_uri_cause,&src_synth_header->failed_uri_cause,pool);
+                       break;
+               case SYNTHESIZER_HEADER_SPEAK_RESTART:
+                       synth_header->speak_restart = src_synth_header->speak_restart;
+                       break;
+               case SYNTHESIZER_HEADER_SPEAK_LENGTH:
+                       synth_header->speak_length = src_synth_header->speak_length;
+                       break;
+               case SYNTHESIZER_HEADER_LOAD_LEXICON:
+                       synth_header->load_lexicon = src_synth_header->load_lexicon;
+                       break;
+               case SYNTHESIZER_HEADER_LEXICON_SEARCH_ORDER:
+                       apt_string_copy(&synth_header->lexicon_search_order,&src_synth_header->lexicon_search_order,pool);
+                       break;
+               default:
+                       status = FALSE;
+       }
+       return status;
+}
+
+static const mrcp_header_vtable_t vtable = {
+       mrcp_synth_header_allocate,
+       NULL, /* nothing to destroy */
+       mrcp_synth_header_parse,
+       mrcp_synth_header_generate,
+       mrcp_synth_header_duplicate,
+       synth_header_string_table,
+       SYNTHESIZER_HEADER_COUNT
+};
+
+MRCP_DECLARE(const mrcp_header_vtable_t*) mrcp_synth_header_vtable_get(mrcp_version_e version)
+{
+       return &vtable;
+}
+
+MRCP_DECLARE(const apt_str_t*) mrcp_synth_completion_cause_get(mrcp_synth_completion_cause_e completion_cause, mrcp_version_e version)
+{
+       return apt_string_table_str_get(completion_cause_string_table,SYNTHESIZER_COMPLETION_CAUSE_COUNT,completion_cause);
+}
diff --git a/libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_resource.c b/libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_resource.c
new file mode 100644 (file)
index 0000000..9018f49
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mrcp_synth_resource.h"
+#include "mrcp_synth_header.h"
+#include "mrcp_synth_state_machine.h"
+#include "mrcp_resource.h"
+#include "mrcp_message.h"
+
+/** String table of MRCP synthesizer methods (mrcp_synthesizer_method_id) */
+static const apt_str_table_item_t synth_method_string_table[] = {
+       {{"SET-PARAMS",       10},10},
+       {{"GET-PARAMS",       10},0},
+       {{"SPEAK",             5},1},
+       {{"STOP",              4},1},
+       {{"PAUSE",             5},0},
+       {{"RESUME",            6},0},
+       {{"BARGE-IN-OCCURRED",17},0},
+       {{"CONTROL",           7},0},
+       {{"DEFINE-LEXICON",   14},0}
+};
+
+/** String table of MRCP synthesizer events (mrcp_synthesizer_event_id) */
+static const apt_str_table_item_t synth_event_string_table[] = {
+       {{"SPEECH-MARKER", 13},3},
+       {{"SPEAK-COMPLETE",14},3}
+};
+
+/** Set resource specifica data */
+static apt_bool_t synth_message_resourcify_by_id(mrcp_resource_t *resource, mrcp_message_t *message)
+{
+       /* associate method_name and method_id */
+       if(message->start_line.message_type == MRCP_MESSAGE_TYPE_REQUEST) {
+               const apt_str_t *name = apt_string_table_str_get(
+                       synth_method_string_table,
+                       SYNTHESIZER_METHOD_COUNT,
+                       message->start_line.method_id);
+               if(!name) {
+                       return FALSE;
+               }
+               message->start_line.method_name = *name;
+       }
+       else if(message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
+               const apt_str_t *name = apt_string_table_str_get(
+                       synth_event_string_table,
+                       SYNTHESIZER_EVENT_COUNT,
+                       message->start_line.method_id);
+               if(!name) {
+                       return FALSE;
+               }
+               message->start_line.method_name = *name;
+       }
+
+       message->header.resource_header_accessor.vtable = 
+               mrcp_synth_header_vtable_get(message->start_line.version);
+       return TRUE;
+}
+
+/** Set resource specifica data */
+static apt_bool_t synth_message_resourcify_by_name(mrcp_resource_t *resource, mrcp_message_t *message)
+{
+       /* associate method_name and method_id */
+       if(message->start_line.message_type == MRCP_MESSAGE_TYPE_REQUEST) {
+               message->start_line.method_id = apt_string_table_id_find(
+                       synth_method_string_table,
+                       SYNTHESIZER_METHOD_COUNT,
+                       &message->start_line.method_name);
+               if(message->start_line.method_id >= SYNTHESIZER_METHOD_COUNT) {
+                       return FALSE;
+               }
+       }
+       else if(message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
+               message->start_line.method_id = apt_string_table_id_find(
+                       synth_event_string_table,
+                       SYNTHESIZER_EVENT_COUNT,
+                       &message->start_line.method_name);
+               if(message->start_line.method_id >= SYNTHESIZER_EVENT_COUNT) {
+                       return FALSE;
+               }
+       }
+
+       message->header.resource_header_accessor.vtable = 
+               mrcp_synth_header_vtable_get(message->start_line.version);
+       return TRUE;
+}
+
+
+/** Create MRCP synthesizer resource */
+MRCP_DECLARE(mrcp_resource_t*) mrcp_synth_resource_create(apr_pool_t *pool)
+{
+       mrcp_resource_t *resource = apr_palloc(pool,sizeof(mrcp_resource_t));
+       mrcp_resource_init(resource);
+
+       resource->resourcify_message_by_id = synth_message_resourcify_by_id;
+       resource->resourcify_message_by_name = synth_message_resourcify_by_name;
+
+       resource->create_client_state_machine = mrcp_synth_client_state_machine_create;
+       resource->create_server_state_machine = mrcp_synth_server_state_machine_create;
+       return resource;
+}
diff --git a/libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_server_state_machine.c b/libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_server_state_machine.c
new file mode 100644 (file)
index 0000000..d569bf9
--- /dev/null
@@ -0,0 +1,563 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apt_obj_list.h"
+#include "apt_log.h"
+#include "mrcp_state_machine.h"
+#include "mrcp_synth_state_machine.h"
+#include "mrcp_synth_header.h"
+#include "mrcp_generic_header.h"
+#include "mrcp_synth_resource.h"
+#include "mrcp_message.h"
+
+/** MRCP synthesizer states */
+typedef enum {
+       SYNTHESIZER_STATE_IDLE,
+       SYNTHESIZER_STATE_SPEAKING,
+       SYNTHESIZER_STATE_PAUSED,
+
+       SYNTHESIZER_STATE_COUNT
+} mrcp_synth_state_e;
+
+static const char * state_names[SYNTHESIZER_STATE_COUNT] = {
+       "IDLE",
+       "SPEAKING",
+       "PAUSED"
+};
+
+typedef struct mrcp_synth_state_machine_t mrcp_synth_state_machine_t;
+struct mrcp_synth_state_machine_t {
+       /** state machine base */
+       mrcp_state_machine_t  base;
+       /** synthesizer state */
+       mrcp_synth_state_e    state;
+       /** indicate whether active_request was processed from pending request queue */
+       apt_bool_t            is_pending;
+       /** request sent to synthesizer engine and waiting for the response to be received */
+       mrcp_message_t       *active_request;
+       /** in-progress speak request */
+       mrcp_message_t       *speaker;
+       /** queue of pending speak requests */
+       apt_obj_list_t       *queue;
+       /** properties used in set/get params */
+       mrcp_message_header_t properties;
+};
+
+typedef apt_bool_t (*synth_method_f)(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message);
+
+static APR_INLINE apt_bool_t synth_request_dispatch(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       state_machine->active_request = message;
+       return state_machine->base.dispatcher(&state_machine->base,message);
+}
+
+static APR_INLINE apt_bool_t synth_response_dispatch(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       state_machine->active_request = NULL;
+       return state_machine->base.dispatcher(&state_machine->base,message);
+}
+
+static APR_INLINE apt_bool_t synth_event_dispatch(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       return state_machine->base.dispatcher(&state_machine->base,message);
+}
+
+static APR_INLINE void synth_state_change(mrcp_synth_state_machine_t *state_machine, mrcp_synth_state_e state)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"State Transition %s -> %s",state_names[state_machine->state],state_names[state]);
+       state_machine->state = state;
+       if(state == SYNTHESIZER_STATE_IDLE) {
+               state_machine->speaker = NULL;
+       }
+}
+
+
+static apt_bool_t synth_request_set_params(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SET-PARAMS Request [%d]",message->start_line.request_id);
+       mrcp_message_header_set(&state_machine->properties,&message->header,message->pool);
+       return synth_request_dispatch(state_machine,message);
+}
+
+static apt_bool_t synth_response_set_params(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SET-PARAMS Response [%d]",message->start_line.request_id);
+       return synth_response_dispatch(state_machine,message);
+}
+
+static apt_bool_t synth_request_get_params(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process GET-PARAMS Request [%d]",message->start_line.request_id);
+       return synth_request_dispatch(state_machine,message);
+}
+
+static apt_bool_t synth_response_get_params(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process GET-PARAMS Response [%d]",message->start_line.request_id);
+       mrcp_message_header_set(&message->header,&state_machine->active_request->header,message->pool);
+       mrcp_message_header_get(&message->header,&state_machine->properties,message->pool);
+       return synth_response_dispatch(state_machine,message);
+}
+
+static apt_bool_t synth_request_speak(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       mrcp_message_header_inherit(&message->header,&state_machine->properties,message->pool);
+       if(state_machine->speaker) {
+               mrcp_message_t *response;
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Queue Up SPEAK Request [%d]",message->start_line.request_id);
+               message->start_line.request_state = MRCP_REQUEST_STATE_PENDING;
+               apt_list_push_back(state_machine->queue,message,message->pool);
+               
+               response = mrcp_response_create(message,message->pool);
+               response->start_line.request_state = MRCP_REQUEST_STATE_PENDING;
+               return synth_response_dispatch(state_machine,response);
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SPEAK Request [%d]",message->start_line.request_id);
+       return synth_request_dispatch(state_machine,message);
+}
+
+static apt_bool_t synth_response_speak(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SPEAK Response [%d]",message->start_line.request_id);
+       if(message->start_line.request_state == MRCP_REQUEST_STATE_INPROGRESS) {
+               state_machine->speaker = state_machine->active_request;
+               synth_state_change(state_machine,SYNTHESIZER_STATE_SPEAKING);
+       }
+       if(state_machine->is_pending == TRUE) {
+               mrcp_message_t *event_message = mrcp_event_create(
+                                                       state_machine->active_request,
+                                                       SYNTHESIZER_SPEECH_MARKER,
+                                                       state_machine->active_request->pool);
+               event_message->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS;
+               state_machine->is_pending = FALSE;
+               /* not to send the response for pending request, instead send SPEECH-MARKER event */
+               return synth_event_dispatch(state_machine,event_message);
+       }
+       return synth_response_dispatch(state_machine,message);
+}
+
+static apt_bool_t synth_pending_requests_remove(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *request_message, mrcp_message_t *response_message)
+{
+       apt_list_elem_t *elem;
+       mrcp_message_t *pending_message;
+       mrcp_request_id_list_t *request_id_list = NULL;
+       mrcp_generic_header_t *generic_header = mrcp_generic_header_get(request_message);
+       mrcp_generic_header_t *response_generic_header = mrcp_generic_header_prepare(response_message);
+       if(generic_header && mrcp_generic_header_property_check(request_message,GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST) == TRUE) {
+               if(generic_header->active_request_id_list.ids && generic_header->active_request_id_list.count) {
+                       /* selective STOP request */
+                       request_id_list = &generic_header->active_request_id_list;
+               }
+       }
+
+       elem = apt_list_first_elem_get(state_machine->queue);
+       while(elem) {
+               pending_message = apt_list_elem_object_get(elem);
+               if(!request_id_list || active_request_id_list_find(generic_header,pending_message->start_line.request_id) == TRUE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remove Pending SPEAK Request [%d]",pending_message->start_line.request_id);
+                       elem = apt_list_elem_remove(state_machine->queue,elem);
+                       /* append active id list */
+                       active_request_id_list_append(response_generic_header,pending_message->start_line.request_id);
+               }
+               else {
+                       /* speak request remains in the queue, just proceed to the next one */
+                       elem = apt_list_next_elem_get(state_machine->queue,elem);
+               }
+       }
+       if(response_generic_header->active_request_id_list.count) {
+               mrcp_generic_header_property_add(response_message,GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST);
+       }
+       return TRUE;
+}
+
+static apt_bool_t synth_request_stop(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       mrcp_message_t *response_message;
+       if(state_machine->speaker) {
+               mrcp_request_id_list_t *request_id_list = NULL;
+               mrcp_generic_header_t *generic_header = mrcp_generic_header_get(message);
+               if(generic_header && mrcp_generic_header_property_check(message,GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST) == TRUE) {
+                       if(generic_header->active_request_id_list.ids && generic_header->active_request_id_list.count) {
+                               /* selective STOP request */
+                               request_id_list = &generic_header->active_request_id_list;
+                       }
+               }
+
+               if(!request_id_list || active_request_id_list_find(generic_header,state_machine->speaker->start_line.request_id) == TRUE) {
+                       /* found in-progress SPEAK request, stop it */
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process STOP Request [%d]",message->start_line.request_id);
+                       return synth_request_dispatch(state_machine,message);
+               }
+       }
+
+       /* found no in-progress SPEAK request, sending immediate response */
+       response_message = mrcp_response_create(message,message->pool);
+       synth_pending_requests_remove(state_machine,message,response_message);
+       return synth_response_dispatch(state_machine,response_message);
+}
+
+static apt_bool_t synth_response_stop(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       mrcp_message_t *pending_request;
+       mrcp_generic_header_t *generic_header = mrcp_generic_header_prepare(message);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process STOP Response [%d]",message->start_line.request_id);
+       /* append active id list */
+       active_request_id_list_append(generic_header,state_machine->speaker->start_line.request_id);
+       mrcp_generic_header_property_add(message,GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST);
+       synth_pending_requests_remove(state_machine,state_machine->active_request,message);
+       synth_state_change(state_machine,SYNTHESIZER_STATE_IDLE);
+       synth_response_dispatch(state_machine,message);
+
+       /* process pending SPEAK requests / if any */
+       pending_request = apt_list_pop_front(state_machine->queue);
+       if(pending_request) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process Pending SPEAK Request [%d]",pending_request->start_line.request_id);
+               state_machine->is_pending = TRUE;
+               synth_request_dispatch(state_machine,pending_request);
+       }
+       return TRUE;
+}
+
+static apt_bool_t synth_request_pause(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       if(state_machine->speaker) {
+               /* speaking or paused state */
+               if(state_machine->state == SYNTHESIZER_STATE_SPEAKING) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process PAUSE Request [%d]",state_machine->speaker->start_line.request_id);
+                       synth_request_dispatch(state_machine,message);
+               }
+               else {
+                       /* paused state */
+                       mrcp_message_t *response_message = mrcp_response_create(message,message->pool);
+                       synth_response_dispatch(state_machine,response_message);
+               }
+       }
+       else {
+               /* idle state */
+               mrcp_message_t *response_message = mrcp_response_create(message,message->pool);
+               response_message->start_line.status_code = MRCP_STATUS_CODE_METHOD_NOT_VALID;
+               synth_response_dispatch(state_machine,response_message);
+       }
+       return TRUE;
+}
+
+static apt_bool_t synth_response_pause(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process PAUSE Response [%d]",message->start_line.request_id);
+       if(message->start_line.status_code == MRCP_STATUS_CODE_SUCCESS) {
+               mrcp_generic_header_t *generic_header = mrcp_generic_header_prepare(message);
+               /* append active id list */
+               active_request_id_list_append(generic_header,state_machine->speaker->start_line.request_id);
+               mrcp_generic_header_property_add(message,GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST);
+               synth_state_change(state_machine,SYNTHESIZER_STATE_PAUSED);
+       }
+       synth_response_dispatch(state_machine,message);
+       return TRUE;
+}
+
+static apt_bool_t synth_request_resume(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       if(state_machine->speaker) {
+               /* speaking or paused state */
+               if(state_machine->state == SYNTHESIZER_STATE_PAUSED) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process RESUME Request [%d]",state_machine->speaker->start_line.request_id);
+                       synth_request_dispatch(state_machine,message);
+               }
+               else {
+                       /* speaking state */
+                       mrcp_message_t *response_message = mrcp_response_create(message,message->pool);
+                       synth_response_dispatch(state_machine,response_message);
+               }
+       }
+       else {
+               /* idle state */
+               mrcp_message_t *response_message = mrcp_response_create(message,message->pool);
+               response_message->start_line.status_code = MRCP_STATUS_CODE_METHOD_NOT_VALID;
+               synth_response_dispatch(state_machine,response_message);
+       }
+       return TRUE;
+}
+
+static apt_bool_t synth_response_resume(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process RESUME Response [%d]",message->start_line.request_id);
+       if(message->start_line.status_code == MRCP_STATUS_CODE_SUCCESS) {
+               mrcp_generic_header_t *generic_header = mrcp_generic_header_prepare(message);
+               /* append active id list */
+               active_request_id_list_append(generic_header,state_machine->speaker->start_line.request_id);
+               mrcp_generic_header_property_add(message,GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST);
+               synth_state_change(state_machine,SYNTHESIZER_STATE_SPEAKING);
+       }
+       synth_response_dispatch(state_machine,message);
+       return TRUE;
+}
+
+static apt_bool_t synth_request_barge_in_occurred(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       mrcp_message_t *response_message;
+       if(state_machine->speaker) {
+               apt_bool_t kill_on_barge_in = TRUE;
+               mrcp_synth_header_t *synth_header = mrcp_resource_header_get(message);
+               if(synth_header) {
+                       if(mrcp_resource_header_property_check(message,SYNTHESIZER_HEADER_KILL_ON_BARGE_IN) == TRUE) {
+                               kill_on_barge_in = synth_header->kill_on_barge_in;
+                       }
+               }
+       
+               if(kill_on_barge_in == TRUE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process BARGE-IN Request [%d]",message->start_line.request_id);
+                       return synth_request_dispatch(state_machine,message);
+               }
+       }
+
+       /* found no kill-on-bargein enabled in-progress SPEAK request, sending immediate response */
+       response_message = mrcp_response_create(message,message->pool);
+       return synth_response_dispatch(state_machine,response_message);
+}
+
+static apt_bool_t synth_response_barge_in_occurred(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       mrcp_generic_header_t *generic_header = mrcp_generic_header_prepare(message);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process BARGE-IN Response [%d]",message->start_line.request_id);
+       /* append active id list */
+       active_request_id_list_append(generic_header,state_machine->speaker->start_line.request_id);
+       mrcp_generic_header_property_add(message,GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST);
+       synth_pending_requests_remove(state_machine,state_machine->active_request,message);
+       synth_state_change(state_machine,SYNTHESIZER_STATE_IDLE);
+       return synth_response_dispatch(state_machine,message);
+}
+
+static apt_bool_t synth_request_control(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       mrcp_message_t *response_message;
+       if(state_machine->state == SYNTHESIZER_STATE_SPEAKING) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process CONTROL Request [%d]",message->start_line.request_id);
+               return synth_request_dispatch(state_machine,message);
+       }
+
+       /* found no in-progress SPEAK request, sending immediate response */
+       response_message = mrcp_response_create(message,message->pool);
+       return synth_response_dispatch(state_machine,response_message);
+}
+
+static apt_bool_t synth_response_control(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       mrcp_generic_header_t *generic_header = mrcp_generic_header_prepare(message);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process CONTROL Response [%d]",message->start_line.request_id);
+       /* append active id list */
+       active_request_id_list_append(generic_header,state_machine->speaker->start_line.request_id);
+       mrcp_generic_header_property_add(message,GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST);
+       return synth_response_dispatch(state_machine,message);
+}
+
+static apt_bool_t synth_request_define_lexicon(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       mrcp_message_t *response_message;
+       if(state_machine->state == SYNTHESIZER_STATE_IDLE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process DEFINE-LEXICON Request [%d]",message->start_line.request_id);
+               return synth_request_dispatch(state_machine,message);
+       }
+
+       /* sending failure response */
+       response_message = mrcp_response_create(message,message->pool);
+       response_message->start_line.status_code = MRCP_STATUS_CODE_METHOD_NOT_VALID;
+       return synth_response_dispatch(state_machine,response_message);
+}
+
+static apt_bool_t synth_response_define_lexicon(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process DEFINE-LEXICON Response [%d]",message->start_line.request_id);
+       return synth_response_dispatch(state_machine,message);
+}
+
+static apt_bool_t synth_event_speech_marker(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       if(!state_machine->speaker) {
+               /* unexpected event, no in-progress speak request */
+               return FALSE;
+       }
+
+       if(state_machine->speaker->start_line.request_id != message->start_line.request_id) {
+               /* unexpected event */
+               return FALSE;
+       }
+       
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SPEECH-MARKER Event [%d]",message->start_line.request_id);
+       message->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS;
+       return synth_event_dispatch(state_machine,message);
+}
+
+static apt_bool_t synth_event_speak_complete(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       mrcp_message_t *pending_request;
+       if(!state_machine->speaker) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected SPEAK-COMPLETE Event [%d]",message->start_line.request_id);
+               return FALSE;
+       }
+
+       if(state_machine->speaker->start_line.request_id != message->start_line.request_id) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected SPEAK-COMPLETE Event [%d]",message->start_line.request_id);
+               return FALSE;
+       }
+
+       if(state_machine->active_request && state_machine->active_request->start_line.method_id == SYNTHESIZER_STOP) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Ignore SPEAK-COMPLETE Event [%d]: waiting for STOP response",message->start_line.request_id);
+               return FALSE;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SPEAK-COMPLETE Event [%d]",message->start_line.request_id);
+       if(mrcp_resource_header_property_check(message,SYNTHESIZER_HEADER_COMPLETION_CAUSE) != TRUE) {
+               mrcp_synth_header_t *synth_header = mrcp_resource_header_prepare(message);
+               synth_header->completion_cause = SYNTHESIZER_COMPLETION_CAUSE_NORMAL;
+               mrcp_resource_header_property_add(message,SYNTHESIZER_HEADER_COMPLETION_CAUSE);
+       }
+       synth_state_change(state_machine,SYNTHESIZER_STATE_IDLE);
+       synth_event_dispatch(state_machine,message);
+
+       /* process pending SPEAK requests */
+       pending_request = apt_list_pop_front(state_machine->queue);
+       if(pending_request) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process Pending SPEAK Request [%d]",pending_request->start_line.request_id);
+               state_machine->is_pending = TRUE;
+               synth_request_dispatch(state_machine,pending_request);
+       }
+       return TRUE;
+}
+
+static synth_method_f synth_request_method_array[SYNTHESIZER_METHOD_COUNT] = {
+       synth_request_set_params,
+       synth_request_get_params,
+       synth_request_speak,
+       synth_request_stop,
+       synth_request_pause,
+       synth_request_resume,
+       synth_request_barge_in_occurred,
+       synth_request_control,
+       synth_request_define_lexicon
+};
+
+static synth_method_f synth_response_method_array[SYNTHESIZER_METHOD_COUNT] = {
+       synth_response_set_params,
+       synth_response_get_params,
+       synth_response_speak,
+       synth_response_stop,
+       synth_response_pause,
+       synth_response_resume,
+       synth_response_barge_in_occurred,
+       synth_response_control,
+       synth_response_define_lexicon,
+};
+
+static synth_method_f synth_event_method_array[SYNTHESIZER_EVENT_COUNT] = {
+       synth_event_speech_marker,
+       synth_event_speak_complete
+};
+
+/** Update state according to received incoming request from MRCP client */
+static apt_bool_t synth_request_state_update(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       synth_method_f method;
+       if(message->start_line.method_id >= SYNTHESIZER_METHOD_COUNT) {
+               return FALSE;
+       }
+       
+       method = synth_request_method_array[message->start_line.method_id];
+       if(method) {
+               return method(state_machine,message);
+       }
+       return synth_request_dispatch(state_machine,message);
+}
+
+/** Update state according to received outgoing response from synthesizer engine */
+static apt_bool_t synth_response_state_update(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       synth_method_f method;
+       if(!state_machine->active_request) {
+               /* unexpected response, no active request waiting for response */
+               return FALSE;
+       }
+       if(state_machine->active_request->start_line.request_id != message->start_line.request_id) {
+               /* unexpected response, request id doesn't match */
+               return FALSE;
+       }
+
+       if(message->start_line.method_id >= SYNTHESIZER_METHOD_COUNT) {
+               return FALSE;
+       }
+       
+       method = synth_response_method_array[message->start_line.method_id];
+       if(method) {
+               return method(state_machine,message);
+       }
+       return synth_response_dispatch(state_machine,message);
+}
+
+/** Update state according to received outgoing event from synthesizer engine */
+static apt_bool_t synth_event_state_update(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       synth_method_f method;
+       if(message->start_line.method_id >= SYNTHESIZER_EVENT_COUNT) {
+               return FALSE;
+       }
+       
+       method = synth_event_method_array[message->start_line.method_id];
+       if(method) {
+               return method(state_machine,message);
+       }
+       return synth_event_dispatch(state_machine,message);
+}
+
+/** Update state according to request received from MRCP client or response/event received from synthesizer engine */
+static apt_bool_t synth_state_update(mrcp_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       mrcp_synth_state_machine_t *synth_state_machine = (mrcp_synth_state_machine_t*)state_machine;
+       apt_bool_t status = TRUE;
+       switch(message->start_line.message_type) {
+               case MRCP_MESSAGE_TYPE_REQUEST:
+                       status = synth_request_state_update(synth_state_machine,message);
+                       break;
+               case MRCP_MESSAGE_TYPE_RESPONSE:
+                       status = synth_response_state_update(synth_state_machine,message);
+                       break;
+               case MRCP_MESSAGE_TYPE_EVENT:
+                       status = synth_event_state_update(synth_state_machine,message);
+                       break;
+               default:
+                       status = FALSE;
+                       break;
+       }
+       return status;
+}
+
+/** Create MRCP synthesizer server state machine */
+mrcp_state_machine_t* mrcp_synth_server_state_machine_create(void *obj, mrcp_message_dispatcher_f dispatcher, mrcp_version_e version, apr_pool_t *pool)
+{
+       mrcp_message_header_t *properties;
+       mrcp_synth_state_machine_t *state_machine = apr_palloc(pool,sizeof(mrcp_synth_state_machine_t));
+       mrcp_state_machine_init(&state_machine->base,obj,dispatcher);
+       state_machine->base.update = synth_state_update;
+       state_machine->state = SYNTHESIZER_STATE_IDLE;
+       state_machine->is_pending = FALSE;
+       state_machine->active_request = NULL;
+       state_machine->speaker = NULL;
+       state_machine->queue = apt_list_create(pool);
+       properties = &state_machine->properties;
+       mrcp_message_header_init(properties);
+       properties->generic_header_accessor.vtable = mrcp_generic_header_vtable_get(version);
+       properties->resource_header_accessor.vtable = mrcp_synth_header_vtable_get(version);
+       return &state_machine->base;
+}
diff --git a/libs/unimrcp/libs/mrcpv2-transport/Makefile.am b/libs/unimrcp/libs/mrcpv2-transport/Makefile.am
new file mode 100644 (file)
index 0000000..e86055d
--- /dev/null
@@ -0,0 +1,21 @@
+MAINTAINERCLEANFILES         = Makefile.in
+
+INCLUDES                      = -I$(top_srcdir)/libs/mrcpv2-transport/include \
+                                -I$(top_srcdir)/libs/mrcp/include \
+                                -I$(top_srcdir)/libs/mrcp/message/include \
+                                -I$(top_srcdir)/libs/mrcp/control/include \
+                                -I$(top_srcdir)/libs/apr-toolkit/include \
+                                $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+noinst_LTLIBRARIES            = libmrcpv2transport.la
+
+include_HEADERS               = include/mrcp_connection_types.h \
+                                include/mrcp_control_descriptor.h \
+                                include/mrcp_connection.h \
+                                include/mrcp_client_connection.h \
+                                include/mrcp_server_connection.h
+
+libmrcpv2transport_la_SOURCES = src/mrcp_control_descriptor.c \
+                                src/mrcp_connection.c \
+                                src/mrcp_client_connection.c \
+                                src/mrcp_server_connection.c
diff --git a/libs/unimrcp/libs/mrcpv2-transport/include/mrcp_client_connection.h b/libs/unimrcp/libs/mrcpv2-transport/include/mrcp_client_connection.h
new file mode 100644 (file)
index 0000000..2918169
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_CLIENT_CONNECTION_H__
+#define __MRCP_CLIENT_CONNECTION_H__
+
+/**
+ * @file mrcp_client_connection.h
+ * @brief MRCPv2 Client Connection
+ */ 
+
+#include "apt_task.h"
+#include "mrcp_connection_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/**
+ * Create connection agent.
+ * @param max_connection_count the number of max MRCPv2 connections
+ * @param offer_new_connection the connection establishment policy in o/a
+ * @param pool the pool to allocate memory from
+ */
+MRCP_DECLARE(mrcp_connection_agent_t*) mrcp_client_connection_agent_create(
+                                                                                       apr_size_t max_connection_count, 
+                                                                                       apt_bool_t offer_new_connection,
+                                                                                       apr_pool_t *pool);
+
+/**
+ * Destroy connection agent.
+ * @param agent the agent to destroy
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_client_connection_agent_destroy(mrcp_connection_agent_t *agent);
+
+/**
+ * Start connection agent and wait for incoming requests.
+ * @param agent the agent to start
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_client_connection_agent_start(mrcp_connection_agent_t *agent);
+
+/**
+ * Terminate connection agent.
+ * @param agent the agent to terminate
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_client_connection_agent_terminate(mrcp_connection_agent_t *agent);
+
+
+/**
+ * Set connection event handler.
+ * @param agent the agent to set event hadler for
+ * @param obj the external object to associate with the agent
+ * @param vtable the event handler virtual methods
+ */
+MRCP_DECLARE(void) mrcp_client_connection_agent_handler_set(
+                                                               mrcp_connection_agent_t *agent, 
+                                                               void *obj, 
+                                                               const mrcp_connection_event_vtable_t *vtable);
+
+/**
+ * Set MRCP resource factory.
+ * @param agent the agent to set resource factory for
+ * @param resource_factory the MRCP resource factory to set
+ */
+MRCP_DECLARE(void) mrcp_client_connection_resource_factory_set(
+                                                               mrcp_connection_agent_t *agent, 
+                                                               mrcp_resource_factory_t *resource_factory);
+
+/**
+ * Get task.
+ * @param agent the agent to get task from
+ */
+MRCP_DECLARE(apt_task_t*) mrcp_client_connection_agent_task_get(mrcp_connection_agent_t *agent);
+
+/**
+ * Get external object.
+ * @param agent the agent to get object from
+ */
+MRCP_DECLARE(void*) mrcp_client_connection_agent_object_get(mrcp_connection_agent_t *agent);
+
+
+/**
+ * Create control channel.
+ * @param agent the agent to create channel for
+ * @param obj the external object to associate with the control channel
+ * @param pool the pool to allocate memory from
+ */
+MRCP_DECLARE(mrcp_control_channel_t*) mrcp_client_control_channel_create(mrcp_connection_agent_t *agent, void *obj, apr_pool_t *pool);
+
+/**
+ * Add MRCPv2 control channel.
+ * @param channel the control channel to add
+ * @param descriptor the control descriptor
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_client_control_channel_add(mrcp_control_channel_t *channel, mrcp_control_descriptor_t *descriptor);
+
+/**
+ * Modify MRCPv2 control channel.
+ * @param channel the control channel to modify
+ * @param descriptor the control descriptor
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_client_control_channel_modify(mrcp_control_channel_t *channel, mrcp_control_descriptor_t *descriptor);
+
+/**
+ * Remove MRCPv2 control channel.
+ * @param channel the control channel to remove
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_client_control_channel_remove(mrcp_control_channel_t *channel);
+
+/**
+ * Destroy MRCPv2 control channel.
+ * @param channel the control channel to destroy
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_client_control_channel_destroy(mrcp_control_channel_t *channel);
+
+/**
+ * Send MRCPv2 message.
+ * @param channel the control channel to send message through
+ * @param message the message to send
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_client_control_message_send(mrcp_control_channel_t *channel, mrcp_message_t *message);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_CLIENT_CONNECTION_H__*/
diff --git a/libs/unimrcp/libs/mrcpv2-transport/include/mrcp_connection.h b/libs/unimrcp/libs/mrcpv2-transport/include/mrcp_connection.h
new file mode 100644 (file)
index 0000000..bcef530
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_CONNECTION_H__
+#define __MRCP_CONNECTION_H__
+
+/**
+ * @file mrcp_connection.h
+ * @brief MRCP Connection
+ */ 
+
+#include <apr_poll.h>
+#include <apr_hash.h>
+#include "apt_obj_list.h"
+#include "mrcp_connection_types.h"
+#include "mrcp_stream.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Size of the buffer used for MRCP rx/tx stream */
+#define MRCP_STREAM_BUFFER_SIZE 1024
+
+/** MRCPv2 connection */
+struct mrcp_connection_t {
+       /** Memory pool */
+       apr_pool_t       *pool;
+
+       /** Accepted/Connected socket */
+       apr_socket_t     *sock;
+       /** Socket poll descriptor */
+       apr_pollfd_t      sock_pfd;
+       /** Local sockaddr */
+       apr_sockaddr_t   *l_sockaddr;
+       /** Remote sockaddr */
+       apr_sockaddr_t   *r_sockaddr;
+       /** Remote IP */
+       apt_str_t         remote_ip;
+       /** String identifier used for traces */
+       const char       *id;
+
+       /** Reference count */
+       apr_size_t        access_count;
+       /** Agent list element */
+       apt_list_elem_t  *it;
+       /** Opaque agent */
+       void             *agent;
+
+       /** Table of control channels */
+       apr_hash_t       *channel_table;
+
+       /** Rx buffer */
+       char              rx_buffer[MRCP_STREAM_BUFFER_SIZE];
+       /** Rx stream */
+       apt_text_stream_t rx_stream;
+       /** MRCP parser to parser MRCP messages out of rx stream */
+       mrcp_parser_t    *parser;
+
+       /** Tx buffer */
+       char              tx_buffer[MRCP_STREAM_BUFFER_SIZE];
+       /** Tx stream */
+       apt_text_stream_t tx_stream;
+       /** MRCP generator to generate MRCP messages out of tx stream */
+       mrcp_generator_t *generator;
+};
+
+/** Create MRCP connection. */
+mrcp_connection_t* mrcp_connection_create();
+
+/** Destroy MRCP connection. */
+void mrcp_connection_destroy(mrcp_connection_t *connection);
+
+/** Add Control Channel to MRCP connection. */
+apt_bool_t mrcp_connection_channel_add(mrcp_connection_t *connection, mrcp_control_channel_t *channel);
+
+/** Find Control Channel by Channel Identifier. */
+mrcp_control_channel_t* mrcp_connection_channel_find(mrcp_connection_t *connection, const apt_str_t *identifier);
+
+/** Remove Control Channel from MRCP connection. */
+apt_bool_t mrcp_connection_channel_remove(mrcp_connection_t *connection, mrcp_control_channel_t *channel);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_CONNECTION_H__*/
diff --git a/libs/unimrcp/libs/mrcpv2-transport/include/mrcp_connection_types.h b/libs/unimrcp/libs/mrcpv2-transport/include/mrcp_connection_types.h
new file mode 100644 (file)
index 0000000..5374451
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_CONNECTION_TYPES_H__
+#define __MRCP_CONNECTION_TYPES_H__
+
+/**
+ * @file mrcp_connection_types.h
+ * @brief MRCP Connection Types Declaration
+ */ 
+
+#include <apr_network_io.h>
+#include "apt_string.h"
+#include "mrcp_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque MRCPv2 control descriptor declaration */
+typedef struct mrcp_control_descriptor_t mrcp_control_descriptor_t;
+
+/** Opaque MRCPv2 connection declaration */
+typedef struct mrcp_connection_t mrcp_connection_t;
+
+/** Opaque MRCPv2 control channel declaration */
+typedef struct mrcp_control_channel_t mrcp_control_channel_t;
+
+/** Opaque MRCPv2 connection agent declaration */
+typedef struct mrcp_connection_agent_t mrcp_connection_agent_t;
+
+/** MRCPv2 connection event vtable declaration */
+typedef struct mrcp_connection_event_vtable_t mrcp_connection_event_vtable_t;
+
+/** MRCPv2 connection event vtable */
+struct mrcp_connection_event_vtable_t {
+       /** Channel add event handler */
+       apt_bool_t (*on_add)(mrcp_control_channel_t *channel, mrcp_control_descriptor_t *descriptor, apt_bool_t status);
+       /** Channel modify event handler */
+       apt_bool_t (*on_modify)(mrcp_control_channel_t *channel, mrcp_control_descriptor_t *descriptor, apt_bool_t status);
+       /** Channel remove event handler */
+       apt_bool_t (*on_remove)(mrcp_control_channel_t *channel, apt_bool_t status);
+       /** Message receive event handler */
+       apt_bool_t (*on_receive)(mrcp_control_channel_t *channel, mrcp_message_t *message);
+};
+
+/** MRCPv2 control channel */
+struct mrcp_control_channel_t {
+       /** MRCPv2 Connection agent */
+       mrcp_connection_agent_t *agent;
+       /** MRCPv2 (shared) connection */
+       mrcp_connection_t       *connection;
+       /** Indicate removed connection (safe to destroy) */
+       apt_bool_t               removed;
+       /** External object associated with the channel */
+       void                    *obj;
+       /** Pool to allocate memory from */
+       apr_pool_t              *pool;
+       /** Channel identifier (id at resource) */
+       apt_str_t                identifier;
+};
+
+/** Send channel add response */
+static APR_INLINE apt_bool_t mrcp_control_channel_add_respond(
+                                               const mrcp_connection_event_vtable_t *vtable, 
+                                               mrcp_control_channel_t *channel, 
+                                               mrcp_control_descriptor_t *descriptor,
+                                               apt_bool_t status)
+{
+       if(vtable && vtable->on_add) {
+               return vtable->on_add(channel,descriptor,status);
+       }
+       return FALSE;
+}
+
+/** Send channel modify response */
+static APR_INLINE apt_bool_t mrcp_control_channel_modify_respond(
+                                               const mrcp_connection_event_vtable_t *vtable, 
+                                               mrcp_control_channel_t *channel, 
+                                               mrcp_control_descriptor_t *descriptor,
+                                               apt_bool_t status)
+{
+       if(vtable && vtable->on_modify) {
+               return vtable->on_modify(channel,descriptor,status);
+       }
+       return FALSE;
+}
+
+/** Send channel remove response */
+static APR_INLINE apt_bool_t mrcp_control_channel_remove_respond(
+                                               const mrcp_connection_event_vtable_t *vtable, 
+                                               mrcp_control_channel_t *channel,
+                                               apt_bool_t status)
+{
+       if(vtable && vtable->on_remove) {
+               return vtable->on_remove(channel,status);
+       }
+       return FALSE;
+}
+
+/** Send MRCP message receive event */
+static APR_INLINE apt_bool_t mrcp_connection_message_receive(
+                                               const mrcp_connection_event_vtable_t *vtable,
+                                               mrcp_control_channel_t *channel, 
+                                               mrcp_message_t *message)
+{
+       if(vtable && vtable->on_receive) {
+               return vtable->on_receive(channel,message);
+       }
+       return FALSE;
+}
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_CONNECTION_TYPES_H__*/
diff --git a/libs/unimrcp/libs/mrcpv2-transport/include/mrcp_control_descriptor.h b/libs/unimrcp/libs/mrcpv2-transport/include/mrcp_control_descriptor.h
new file mode 100644 (file)
index 0000000..a9323ae
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_CONTROL_DESCRIPTOR_H__
+#define __MRCP_CONTROL_DESCRIPTOR_H__
+
+/**
+ * @file mrcp_control_descriptor.h
+ * @brief MRCPv2 Control Descriptor
+ */ 
+
+#include "apt_string.h"
+#include "mrcp_connection_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/** MRCPv2 proto transport */
+typedef enum {
+       MRCP_PROTO_TCP,
+       MRCP_PROTO_TLS,
+
+       MRCP_PROTO_COUNT,
+       MRCP_PROTO_UNKNOWN = MRCP_PROTO_COUNT
+}mrcp_proto_type_e;
+
+
+/** MRCPv2 attributes */
+typedef enum {
+       MRCP_ATTRIB_SETUP,
+       MRCP_ATTRIB_CONNECTION,
+       MRCP_ATTRIB_RESOURCE,
+       MRCP_ATTRIB_CHANNEL,
+       MRCP_ATTRIB_CMID,
+
+       MRCP_ATTRIB_COUNT,
+       MRCP_ATTRIB_UNKNOWN = MRCP_ATTRIB_COUNT
+}mrcp_attrib_e;
+
+
+/** MRCPv2 setup attributes */
+typedef enum {
+       MRCP_SETUP_TYPE_ACTIVE,
+       MRCP_SETUP_TYPE_PASSIVE,
+
+       MRCP_SETUP_TYPE_COUNT,
+       MRCP_SETUP_TYPE_UNKNOWN = MRCP_SETUP_TYPE_COUNT
+} mrcp_setup_type_e;
+
+/** MRCPv2 connection attributes */
+typedef enum {
+       MRCP_CONNECTION_TYPE_NEW,
+       MRCP_CONNECTION_TYPE_EXISTING,
+
+       MRCP_CONNECTION_TYPE_COUNT,
+       MRCP_CONNECTION_TYPE_UNKNOWN = MRCP_CONNECTION_TYPE_COUNT
+} mrcp_connection_type_e;
+
+
+/** MRCPv2 control descriptor */
+struct mrcp_control_descriptor_t {
+       /** IP address */
+       apt_str_t              ip;
+       /** Port */
+       apr_port_t             port;
+       /** Protocol type */
+       mrcp_proto_type_e      proto;
+       /** Setup type */
+       mrcp_setup_type_e      setup_type;
+       /** Connection type */
+       mrcp_connection_type_e connection_type;
+       /** Resource name */
+       apt_str_t              resource_name;
+       /** Session identifier */
+       apt_str_t              session_id;
+       /** Control media identifier */
+       apr_size_t             cmid;
+       /** Base identifier */
+       apr_size_t             id;
+};
+
+/** Initialize MRCP control descriptor */
+static APR_INLINE void mrcp_control_descriptor_init(mrcp_control_descriptor_t *descriptor)
+{
+       apt_string_reset(&descriptor->ip);
+       descriptor->port = 0;
+       descriptor->proto = MRCP_PROTO_UNKNOWN;
+       descriptor->setup_type = MRCP_SETUP_TYPE_UNKNOWN;
+       descriptor->connection_type = MRCP_CONNECTION_TYPE_UNKNOWN;
+       apt_string_reset(&descriptor->resource_name);
+       apt_string_reset(&descriptor->session_id);
+       descriptor->cmid = 0;
+       descriptor->id = 0;
+}
+
+/** Create MRCP control offer */
+MRCP_DECLARE(mrcp_control_descriptor_t*) mrcp_control_offer_create(apr_pool_t *pool);
+
+/** Create MRCP control answer */
+MRCP_DECLARE(mrcp_control_descriptor_t*) mrcp_control_answer_create(mrcp_control_descriptor_t *offer, apr_pool_t *pool);
+
+/** Get MRCP protocol transport name by identifier */
+MRCP_DECLARE(const apt_str_t*) mrcp_proto_get(mrcp_proto_type_e proto);
+
+/** Find MRCP protocol transport identifier by name */
+MRCP_DECLARE(mrcp_proto_type_e) mrcp_proto_find(const apt_str_t *attrib);
+
+
+/** Get MRCP attribute name by identifier */
+MRCP_DECLARE(const apt_str_t*) mrcp_attrib_str_get(mrcp_attrib_e attrib_id);
+
+/** Find MRCP attribute identifier by name */
+MRCP_DECLARE(mrcp_attrib_e) mrcp_attrib_id_find(const apt_str_t *attrib);
+
+
+/** Get MRCP setup type name by identifier */
+MRCP_DECLARE(const apt_str_t*) mrcp_setup_type_get(mrcp_setup_type_e setup_type);
+
+/** Find MRCP setup type identifier by name */
+MRCP_DECLARE(mrcp_setup_type_e) mrcp_setup_type_find(const apt_str_t *attrib);
+
+
+/** Get MRCP connection type name by identifier */
+MRCP_DECLARE(const apt_str_t*) mrcp_connection_type_get(mrcp_connection_type_e connection_type);
+
+/** Find MRCP connection type identifier by name */
+MRCP_DECLARE(mrcp_connection_type_e) mrcp_connection_type_find(const apt_str_t *attrib);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_CONTROL_DESCRIPTOR_H__*/
diff --git a/libs/unimrcp/libs/mrcpv2-transport/include/mrcp_server_connection.h b/libs/unimrcp/libs/mrcpv2-transport/include/mrcp_server_connection.h
new file mode 100644 (file)
index 0000000..c72b9c5
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_SERVER_CONNECTION_H__
+#define __MRCP_SERVER_CONNECTION_H__
+
+/**
+ * @file mrcp_server_connection.h
+ * @brief MRCPv2 Server Connection
+ */ 
+
+#include "apt_task.h"
+#include "mrcp_connection_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/**
+ * Create connection agent.
+ * @param listen_ip the listen IP address
+ * @param listen_port the listen port
+ * @param max_connection_count the number of max MRCPv2 connections
+ * @param force_new_connection the connection establishment policy in o/a
+ * @param pool the pool to allocate memory from
+ */
+MRCP_DECLARE(mrcp_connection_agent_t*) mrcp_server_connection_agent_create(
+                                                                               const char *listen_ip, 
+                                                                               apr_port_t listen_port, 
+                                                                               apr_size_t max_connection_count,
+                                                                               apt_bool_t force_new_connection,
+                                                                               apr_pool_t *pool);
+
+/**
+ * Destroy connection agent.
+ * @param agent the agent to destroy
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_server_connection_agent_destroy(mrcp_connection_agent_t *agent);
+
+/**
+ * Start connection agent and wait for incoming requests.
+ * @param agent the agent to start
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_server_connection_agent_start(mrcp_connection_agent_t *agent);
+
+/**
+ * Terminate connection agent.
+ * @param agent the agent to terminate
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_server_connection_agent_terminate(mrcp_connection_agent_t *agent);
+
+/**
+ * Set connection event handler.
+ * @param agent the agent to set event hadler for
+ * @param obj the external object to associate with the agent
+ * @param vtable the event handler virtual methods
+ */
+MRCP_DECLARE(void) mrcp_server_connection_agent_handler_set(
+                                                               mrcp_connection_agent_t *agent, 
+                                                               void *obj, 
+                                                               const mrcp_connection_event_vtable_t *vtable);
+
+/**
+ * Set MRCP resource factory.
+ * @param agent the agent to set resource factory for
+ * @param resource_factory the MRCP resource factory to set
+ */
+MRCP_DECLARE(void) mrcp_server_connection_resource_factory_set(
+                                                               mrcp_connection_agent_t *agent, 
+                                                               mrcp_resource_factory_t *resource_factory);
+
+/**
+ * Get task.
+ * @param agent the agent to get task from
+ */
+MRCP_DECLARE(apt_task_t*) mrcp_server_connection_agent_task_get(mrcp_connection_agent_t *agent);
+
+/**
+ * Get external object.
+ * @param agent the agent to get object from
+ */
+MRCP_DECLARE(void*) mrcp_server_connection_agent_object_get(mrcp_connection_agent_t *agent);
+
+
+/**
+ * Create control channel.
+ * @param agent the agent to create channel for
+ * @param obj the external object to associate with the control channel
+ * @param pool the pool to allocate memory from
+ */
+MRCP_DECLARE(mrcp_control_channel_t*) mrcp_server_control_channel_create(mrcp_connection_agent_t *agent, void *obj, apr_pool_t *pool);
+
+/**
+ * Add MRCPv2 control channel.
+ * @param channel the control channel to add
+ * @param descriptor the control descriptor
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_server_control_channel_add(mrcp_control_channel_t *channel, mrcp_control_descriptor_t *descriptor);
+
+/**
+ * Modify MRCPv2 control channel.
+ * @param channel the control channel to modify
+ * @param descriptor the control descriptor
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_server_control_channel_modify(mrcp_control_channel_t *channel, mrcp_control_descriptor_t *descriptor);
+
+/**
+ * Remove MRCPv2 control channel.
+ * @param channel the control channel to remove
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_server_control_channel_remove(mrcp_control_channel_t *channel);
+
+/**
+ * Destroy MRCPv2 control channel.
+ * @param channel the control channel to destroy
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_server_control_channel_destroy(mrcp_control_channel_t *channel);
+
+/**
+ * Send MRCPv2 message.
+ * @param channel the control channel to send message through
+ * @param message the message to send
+ */
+MRCP_DECLARE(apt_bool_t) mrcp_server_control_message_send(mrcp_control_channel_t *channel, mrcp_message_t *message);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_SERVER_CONNECTION_H__*/
diff --git a/libs/unimrcp/libs/mrcpv2-transport/mrcpv2transport.vcproj b/libs/unimrcp/libs/mrcpv2-transport/mrcpv2transport.vcproj
new file mode 100644 (file)
index 0000000..de34484
--- /dev/null
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="mrcpv2transport"
+       ProjectGUID="{A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}"
+       RootNamespace="mrcpv2transport"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\mrcpv2transport.vsprops"
+                       CharacterSet="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\mrcpv2transport.vsprops"
+                       CharacterSet="1"
+                       WholeProgramOptimization="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+                       <File
+                               RelativePath=".\include\mrcp_client_connection.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_connection.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_connection_types.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_control_descriptor.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_server_connection.h"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       >
+                       <File
+                               RelativePath=".\src\mrcp_client_connection.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\mrcp_connection.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\mrcp_control_descriptor.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\mrcp_server_connection.c"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_client_connection.c b/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_client_connection.c
new file mode 100644 (file)
index 0000000..89f636e
--- /dev/null
@@ -0,0 +1,636 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mrcp_connection.h"
+#include "mrcp_client_connection.h"
+#include "mrcp_control_descriptor.h"
+#include "mrcp_resource_factory.h"
+#include "mrcp_message.h"
+#include "apt_text_stream.h"
+#include "apt_task.h"
+#include "apt_pollset.h"
+#include "apt_cyclic_queue.h"
+#include "apt_log.h"
+
+#define MRCPV2_CONNECTION_TASK_NAME "TCP/MRCPv2 Connection Agent"
+
+struct mrcp_connection_agent_t {
+       apr_pool_t              *pool;
+       apt_task_t              *task;
+
+       mrcp_resource_factory_t *resource_factory;
+
+       apt_obj_list_t          *connection_list;
+
+       apt_bool_t               offer_new_connection;
+       apr_size_t               max_connection_count;
+
+       apr_thread_mutex_t      *guard;
+       apt_cyclic_queue_t      *msg_queue;
+       apt_pollset_t           *pollset;
+
+       void                                 *obj;
+       const mrcp_connection_event_vtable_t *vtable;
+};
+
+typedef enum {
+       CONNECTION_TASK_MSG_ADD_CHANNEL,
+       CONNECTION_TASK_MSG_MODIFY_CHANNEL,
+       CONNECTION_TASK_MSG_REMOVE_CHANNEL,
+       CONNECTION_TASK_MSG_SEND_MESSAGE,
+       CONNECTION_TASK_MSG_TERMINATE
+} connection_task_msg_type_e;
+
+typedef struct connection_task_msg_t connection_task_msg_t;
+struct connection_task_msg_t {
+       connection_task_msg_type_e type;
+       mrcp_connection_agent_t   *agent;
+       mrcp_control_channel_t    *channel;
+       mrcp_control_descriptor_t *descriptor;
+       mrcp_message_t            *message;
+};
+
+
+static apt_bool_t mrcp_client_agent_task_run(apt_task_t *task);
+static apt_bool_t mrcp_client_agent_task_terminate(apt_task_t *task);
+static apt_bool_t mrcp_client_agent_task_on_destroy(apt_task_t *task);
+
+/** Create connection agent. */
+MRCP_DECLARE(mrcp_connection_agent_t*) mrcp_client_connection_agent_create(
+                                                                                       apr_size_t max_connection_count, 
+                                                                                       apt_bool_t offer_new_connection,
+                                                                                       apr_pool_t *pool)
+{
+       apt_task_vtable_t *vtable;
+       mrcp_connection_agent_t *agent;
+       
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create "MRCPV2_CONNECTION_TASK_NAME" [%d]",max_connection_count);
+       agent = apr_palloc(pool,sizeof(mrcp_connection_agent_t));
+       agent->pool = pool;
+       agent->pollset = NULL;
+       agent->max_connection_count = max_connection_count;
+       agent->offer_new_connection = offer_new_connection;
+
+       agent->task = apt_task_create(agent,NULL,pool);
+       if(!agent->task) {
+               return NULL;
+       }
+
+       apt_task_name_set(agent->task,MRCPV2_CONNECTION_TASK_NAME);
+       vtable = apt_task_vtable_get(agent->task);
+       if(vtable) {
+               vtable->run = mrcp_client_agent_task_run;
+               vtable->terminate = mrcp_client_agent_task_terminate;
+               vtable->destroy = mrcp_client_agent_task_on_destroy;
+       }
+
+       agent->connection_list = apt_list_create(pool);
+
+       agent->msg_queue = apt_cyclic_queue_create(CYCLIC_QUEUE_DEFAULT_SIZE);
+       apr_thread_mutex_create(&agent->guard,APR_THREAD_MUTEX_UNNESTED,pool);
+       return agent;
+}
+
+/** Virtual destroy handler. */
+static apt_bool_t mrcp_client_agent_task_on_destroy(apt_task_t *task)
+{
+       mrcp_connection_agent_t *agent = apt_task_object_get(task);
+       if(agent->guard) {
+               apr_thread_mutex_destroy(agent->guard);
+               agent->guard = NULL;
+       }
+       if(agent->msg_queue) {
+               apt_cyclic_queue_destroy(agent->msg_queue);
+               agent->msg_queue = NULL;
+       }
+       return TRUE;
+}
+
+/** Destroy connection agent. */
+MRCP_DECLARE(apt_bool_t) mrcp_client_connection_agent_destroy(mrcp_connection_agent_t *agent)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy MRCPv2 Agent");
+       return apt_task_destroy(agent->task);
+}
+
+/** Start connection agent. */
+MRCP_DECLARE(apt_bool_t) mrcp_client_connection_agent_start(mrcp_connection_agent_t *agent)
+{
+       return apt_task_start(agent->task);
+}
+
+/** Terminate connection agent. */
+MRCP_DECLARE(apt_bool_t) mrcp_client_connection_agent_terminate(mrcp_connection_agent_t *agent)
+{
+       return apt_task_terminate(agent->task,TRUE);
+}
+
+/** Set connection event handler. */
+MRCP_DECLARE(void) mrcp_client_connection_agent_handler_set(
+                                                                       mrcp_connection_agent_t *agent, 
+                                                                       void *obj, 
+                                                                       const mrcp_connection_event_vtable_t *vtable)
+{
+       agent->obj = obj;
+       agent->vtable = vtable;
+}
+
+/** Set MRCP resource factory */
+MRCP_DECLARE(void) mrcp_client_connection_resource_factory_set(
+                                                               mrcp_connection_agent_t *agent, 
+                                                               mrcp_resource_factory_t *resource_factroy)
+{
+       agent->resource_factory = resource_factroy;
+}
+
+/** Get task */
+MRCP_DECLARE(apt_task_t*) mrcp_client_connection_agent_task_get(mrcp_connection_agent_t *agent)
+{
+       return agent->task;
+}
+
+/** Get external object */
+MRCP_DECLARE(void*) mrcp_client_connection_agent_object_get(mrcp_connection_agent_t *agent)
+{
+       return agent->obj;
+}
+
+
+/** Create control channel */
+MRCP_DECLARE(mrcp_control_channel_t*) mrcp_client_control_channel_create(mrcp_connection_agent_t *agent, void *obj, apr_pool_t *pool)
+{
+       mrcp_control_channel_t *channel = apr_palloc(pool,sizeof(mrcp_control_channel_t));
+       channel->agent = agent;
+       channel->connection = NULL;
+       channel->removed = FALSE;
+       channel->obj = obj;
+       channel->pool = pool;
+       return channel;
+}
+
+/** Destroy MRCPv2 control channel */
+MRCP_DECLARE(apt_bool_t) mrcp_client_control_channel_destroy(mrcp_control_channel_t *channel)
+{
+       if(channel && channel->connection && channel->removed == TRUE) {
+               mrcp_connection_t *connection = channel->connection;
+               channel->connection = NULL;
+               apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy TCP/MRCPv2 Connection %s",connection->id);
+               mrcp_connection_destroy(connection);
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_client_control_message_signal(
+                                                               connection_task_msg_type_e type,
+                                                               mrcp_connection_agent_t *agent,
+                                                               mrcp_control_channel_t *channel,
+                                                               mrcp_control_descriptor_t *descriptor,
+                                                               mrcp_message_t *message)
+{
+       apt_bool_t status;
+       connection_task_msg_t *msg = apr_palloc(channel->pool,sizeof(connection_task_msg_t));
+       msg->type = type;
+       msg->agent = agent;
+       msg->channel = channel;
+       msg->descriptor = descriptor;
+       msg->message = message;
+
+       apr_thread_mutex_lock(agent->guard);
+       status = apt_cyclic_queue_push(agent->msg_queue,msg);
+       apr_thread_mutex_unlock(agent->guard);
+       if(apt_pollset_wakeup(agent->pollset) != TRUE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Signal Control Message");
+               status = FALSE;
+       }
+       return status;
+}
+
+/** Add MRCPv2 control channel */
+MRCP_DECLARE(apt_bool_t) mrcp_client_control_channel_add(mrcp_control_channel_t *channel, mrcp_control_descriptor_t *descriptor)
+{
+       return mrcp_client_control_message_signal(CONNECTION_TASK_MSG_ADD_CHANNEL,channel->agent,channel,descriptor,NULL);
+}
+
+/** Modify MRCPv2 control channel */
+MRCP_DECLARE(apt_bool_t) mrcp_client_control_channel_modify(mrcp_control_channel_t *channel, mrcp_control_descriptor_t *descriptor)
+{
+       return mrcp_client_control_message_signal(CONNECTION_TASK_MSG_MODIFY_CHANNEL,channel->agent,channel,descriptor,NULL);
+}
+
+/** Remove MRCPv2 control channel */
+MRCP_DECLARE(apt_bool_t) mrcp_client_control_channel_remove(mrcp_control_channel_t *channel)
+{
+       return mrcp_client_control_message_signal(CONNECTION_TASK_MSG_REMOVE_CHANNEL,channel->agent,channel,NULL,NULL);
+}
+
+/** Send MRCPv2 message */
+MRCP_DECLARE(apt_bool_t) mrcp_client_control_message_send(mrcp_control_channel_t *channel, mrcp_message_t *message)
+{
+       return mrcp_client_control_message_signal(CONNECTION_TASK_MSG_SEND_MESSAGE,channel->agent,channel,NULL,message);
+}
+
+static mrcp_connection_t* mrcp_client_agent_connection_create(mrcp_connection_agent_t *agent, mrcp_control_descriptor_t *descriptor)
+{
+       char *local_ip = NULL;
+       char *remote_ip = NULL;
+       mrcp_connection_t *connection = mrcp_connection_create();
+
+       apr_sockaddr_info_get(&connection->r_sockaddr,descriptor->ip.buf,APR_INET,descriptor->port,0,connection->pool);
+       if(!connection->r_sockaddr) {
+               mrcp_connection_destroy(connection);
+               return NULL;
+       }
+
+       if(apr_socket_create(&connection->sock,connection->r_sockaddr->family,SOCK_STREAM,APR_PROTO_TCP,connection->pool) != APR_SUCCESS) {
+               mrcp_connection_destroy(connection);
+               return NULL;
+       }
+
+       apr_socket_opt_set(connection->sock, APR_SO_NONBLOCK, 0);
+       apr_socket_timeout_set(connection->sock, -1);
+       apr_socket_opt_set(connection->sock, APR_SO_REUSEADDR, 1);
+
+       if(apr_socket_connect(connection->sock, connection->r_sockaddr) != APR_SUCCESS) {
+               apr_socket_close(connection->sock);
+               mrcp_connection_destroy(connection);
+               return NULL;
+       }
+
+       if(apr_socket_addr_get(&connection->l_sockaddr,APR_LOCAL,connection->sock) != APR_SUCCESS) {
+               apr_socket_close(connection->sock);
+               mrcp_connection_destroy(connection);
+               return NULL;
+       }
+
+       apr_sockaddr_ip_get(&local_ip,connection->l_sockaddr);
+       apr_sockaddr_ip_get(&remote_ip,connection->r_sockaddr);
+       connection->id = apr_psprintf(connection->pool,"%s:%hu <-> %s:%hu",
+               local_ip,connection->l_sockaddr->port,
+               remote_ip,connection->r_sockaddr->port);
+
+       memset(&connection->sock_pfd,0,sizeof(apr_pollfd_t));
+       connection->sock_pfd.desc_type = APR_POLL_SOCKET;
+       connection->sock_pfd.reqevents = APR_POLLIN;
+       connection->sock_pfd.desc.s = connection->sock;
+       connection->sock_pfd.client_data = connection;
+       if(apt_pollset_add(agent->pollset, &connection->sock_pfd) != TRUE) {
+               apr_socket_close(connection->sock);
+               mrcp_connection_destroy(connection);
+               return NULL;
+       }
+       
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Established TCP/MRCPv2 Connection %s",connection->id);
+       connection->agent = agent;
+       connection->it = apt_list_push_back(agent->connection_list,connection,connection->pool);
+       connection->parser = mrcp_parser_create(agent->resource_factory,connection->pool);
+       connection->generator = mrcp_generator_create(agent->resource_factory,connection->pool);
+       return connection;
+}
+
+static mrcp_connection_t* mrcp_client_agent_connection_find(mrcp_connection_agent_t *agent, mrcp_control_descriptor_t *descriptor)
+{
+       apr_sockaddr_t *sockaddr;
+       mrcp_connection_t *connection = NULL;
+       apt_list_elem_t *elem = apt_list_first_elem_get(agent->connection_list);
+       /* walk through the list of connections */
+       while(elem) {
+               connection = apt_list_elem_object_get(elem);
+               if(connection) {
+                       if(apr_sockaddr_info_get(&sockaddr,descriptor->ip.buf,APR_INET,descriptor->port,0,connection->pool) == APR_SUCCESS) {
+                               if(apr_sockaddr_equal(sockaddr,connection->r_sockaddr) != 0) {
+                                       return connection;
+                               }
+                       }
+               }
+               elem = apt_list_next_elem_get(agent->connection_list,elem);
+       }
+       return NULL;
+}
+
+static apt_bool_t mrcp_client_agent_connection_remove(mrcp_connection_agent_t *agent, mrcp_connection_t *connection)
+{
+       /* remove from the list */
+       if(connection->it) {
+               apt_list_elem_remove(agent->connection_list,connection->it);
+               connection->it = NULL;
+       }
+       apt_pollset_remove(agent->pollset,&connection->sock_pfd);
+       if(connection->sock) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close TCP/MRCPv2 Connection %s",connection->id);
+               apr_socket_close(connection->sock);
+               connection->sock = NULL;
+       }
+       return TRUE;
+}
+
+
+static apt_bool_t mrcp_client_agent_channel_add(mrcp_connection_agent_t *agent, mrcp_control_channel_t *channel, mrcp_control_descriptor_t *descriptor)
+{
+       if(agent->offer_new_connection == TRUE) {
+               descriptor->connection_type = MRCP_CONNECTION_TYPE_NEW;
+       }
+       else {
+               descriptor->connection_type = MRCP_CONNECTION_TYPE_EXISTING;
+               if(apt_list_is_empty(agent->connection_list) == TRUE) {
+                       /* offer new connection if there is no established connection yet */
+                       descriptor->connection_type = MRCP_CONNECTION_TYPE_NEW;
+               }
+       }
+       /* send response */
+       return mrcp_control_channel_add_respond(agent->vtable,channel,descriptor,TRUE);
+}
+
+static apt_bool_t mrcp_client_agent_channel_modify(mrcp_connection_agent_t *agent, mrcp_control_channel_t *channel, mrcp_control_descriptor_t *descriptor)
+{
+       apt_bool_t status = TRUE;
+       if(descriptor->port) {
+               if(!channel->connection) {
+                       mrcp_connection_t *connection = NULL;
+                       apt_id_resource_generate(&descriptor->session_id,&descriptor->resource_name,'@',&channel->identifier,channel->pool);
+                       /* no connection yet */
+                       if(descriptor->connection_type == MRCP_CONNECTION_TYPE_EXISTING) {
+                               /* try to find existing connection */
+                               connection = mrcp_client_agent_connection_find(agent,descriptor);
+                               if(!connection) {
+                                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Found No Existing TCP/MRCPv2 Connection");
+                               }
+                       }
+                       if(!connection) {
+                               /* create new connection */
+                               connection = mrcp_client_agent_connection_create(agent,descriptor);
+                               if(!connection) {
+                                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Establish TCP/MRCPv2 Connection");
+                               }
+                       }
+
+                       if(connection) {
+                               mrcp_connection_channel_add(connection,channel);
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Add Control Channel <%s> %s [%d]",
+                                               channel->identifier.buf,
+                                               connection->id,
+                                               apr_hash_count(connection->channel_table));
+                               if(descriptor->connection_type == MRCP_CONNECTION_TYPE_NEW) {
+                                       /* set connection type to existing for the next offers / if any */
+                                       descriptor->connection_type = MRCP_CONNECTION_TYPE_EXISTING;
+                               }
+                       }
+                       else {
+                               descriptor->port = 0;
+                               status = FALSE;
+                       }
+               }
+       }
+       /* send response */
+       return mrcp_control_channel_modify_respond(agent->vtable,channel,descriptor,status);
+}
+
+static apt_bool_t mrcp_client_agent_channel_remove(mrcp_connection_agent_t *agent, mrcp_control_channel_t *channel)
+{
+       if(channel->connection) {
+               mrcp_connection_t *connection = channel->connection;
+               mrcp_connection_channel_remove(connection,channel);
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remove Control Channel <%s> [%d]",
+                               channel->identifier.buf,
+                               apr_hash_count(connection->channel_table));
+               if(!connection->access_count) {
+                       mrcp_client_agent_connection_remove(agent,connection);
+                       /* set connection to be destroyed on channel destroy */
+                       channel->connection = connection;
+                       channel->removed = TRUE;
+               }
+       }
+       
+       /* send response */
+       return mrcp_control_channel_remove_respond(agent->vtable,channel,TRUE);
+}
+
+static apt_bool_t mrcp_client_agent_messsage_send(mrcp_connection_agent_t *agent, mrcp_control_channel_t *channel, mrcp_message_t *message)
+{
+       apt_bool_t status = FALSE;
+       mrcp_connection_t *connection = channel->connection;
+       apt_text_stream_t *stream;
+       mrcp_stream_result_e result;
+
+       if(!connection || !connection->sock) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No MRCPv2 Connection");
+               return FALSE;
+       }
+       stream = &connection->tx_stream;
+
+       mrcp_generator_message_set(connection->generator,message);
+       do {
+               apt_text_stream_init(&connection->tx_stream,connection->tx_buffer,sizeof(connection->tx_buffer)-1);
+               result = mrcp_generator_run(connection->generator,stream);
+               if(result == MRCP_STREAM_MESSAGE_COMPLETE || result == MRCP_STREAM_MESSAGE_TRUNCATED) {
+                       stream->text.length = stream->pos - stream->text.buf;
+                       *stream->pos = '\0';
+
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Send MRCPv2 Stream %s [%lu bytes]\n%s",
+                               connection->id,
+                               stream->text.length,
+                               stream->text.buf);
+                       if(apr_socket_send(connection->sock,stream->text.buf,&stream->text.length) == APR_SUCCESS) {
+                               status = TRUE;
+                       }
+                       else {
+                               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Send MRCPv2 Stream");
+                       }
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Generate MRCPv2 Stream");
+               }
+       }
+       while(result == MRCP_STREAM_MESSAGE_TRUNCATED);
+
+       if(status == FALSE) {
+               mrcp_message_t *response = mrcp_response_create(message,message->pool);
+               response->start_line.method_id = message->start_line.method_id;
+               response->start_line.method_name = message->start_line.method_name;
+               response->start_line.status_code = MRCP_STATUS_CODE_METHOD_FAILED;
+               mrcp_connection_message_receive(agent->vtable,channel,response);
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_client_message_handler(void *obj, mrcp_message_t *message, mrcp_stream_result_e result)
+{
+       if(result == MRCP_STREAM_MESSAGE_COMPLETE) {
+               /* message is completely parsed */
+               mrcp_connection_t *connection = obj;
+               mrcp_control_channel_t *channel;
+               apt_str_t identifier;
+               apt_id_resource_generate(&message->channel_id.session_id,&message->channel_id.resource_name,'@',&identifier,message->pool);
+               channel = mrcp_connection_channel_find(connection,&identifier);
+               if(channel) {
+                       mrcp_connection_agent_t *agent = connection->agent;
+                       mrcp_connection_message_receive(agent->vtable,channel,message);
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Find Channel <%s@%s> in Connection %s [%d]",
+                               message->channel_id.session_id.buf,
+                               message->channel_id.resource_name.buf,
+                               connection->id,
+                               apr_hash_count(connection->channel_table));
+               }
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_client_agent_messsage_receive(mrcp_connection_agent_t *agent, mrcp_connection_t *connection)
+{
+       apr_status_t status;
+       apr_size_t offset;
+       apr_size_t length;
+       apt_text_stream_t *stream;
+
+       if(!connection || !connection->sock) {
+               return FALSE;
+       }
+       stream = &connection->rx_stream;
+
+       /* init length of the stream */
+       stream->text.length = sizeof(connection->rx_buffer)-1;
+       /* calculate offset remaining from the previous receive / if any */
+       offset = stream->pos - stream->text.buf;
+       /* calculate available length */
+       length = stream->text.length - offset;
+       status = apr_socket_recv(connection->sock,stream->pos,&length);
+       if(status == APR_EOF || length == 0) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"TCP/MRCPv2 Peer Disconnected %s",connection->id);
+               apt_pollset_remove(agent->pollset,&connection->sock_pfd);
+               apr_socket_close(connection->sock);
+               connection->sock = NULL;
+
+//             agent->vtable->on_disconnect(agent,connection);
+               return TRUE;
+       }
+       /* calculate actual length of the stream */
+       stream->text.length = offset + length;
+       stream->pos[length] = '\0';
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive MRCPv2 Stream %s [%lu bytes]\n%s",
+               connection->id,
+               length,
+               stream->pos);
+
+       /* reset pos */
+       stream->pos = stream->text.buf;
+       /* walk through the stream parsing RTSP messages */
+       return mrcp_stream_walk(connection->parser,stream,mrcp_client_message_handler,connection);
+}
+
+static apt_bool_t mrcp_client_agent_control_process(mrcp_connection_agent_t *agent)
+{
+       apt_bool_t status = TRUE;
+       apt_bool_t running = TRUE;
+       connection_task_msg_t *msg;
+
+       do {
+               apr_thread_mutex_lock(agent->guard);
+               msg = apt_cyclic_queue_pop(agent->msg_queue);
+               apr_thread_mutex_unlock(agent->guard);
+               if(msg) {
+                       switch(msg->type) {
+                               case CONNECTION_TASK_MSG_ADD_CHANNEL:
+                                       mrcp_client_agent_channel_add(agent,msg->channel,msg->descriptor);
+                                       break;
+                               case CONNECTION_TASK_MSG_MODIFY_CHANNEL:
+                                       mrcp_client_agent_channel_modify(agent,msg->channel,msg->descriptor);
+                                       break;
+                               case CONNECTION_TASK_MSG_REMOVE_CHANNEL:
+                                       mrcp_client_agent_channel_remove(agent,msg->channel);
+                                       break;
+                               case CONNECTION_TASK_MSG_SEND_MESSAGE:
+                                       mrcp_client_agent_messsage_send(agent,msg->channel,msg->message);
+                                       break;
+                               case CONNECTION_TASK_MSG_TERMINATE:
+                                       status = FALSE;
+                                       break;
+                       }
+               }
+               else {
+                       running = FALSE;
+               }
+       }
+       while(running == TRUE);
+       return status;
+}
+
+static apt_bool_t mrcp_client_agent_task_run(apt_task_t *task)
+{
+       mrcp_connection_agent_t *agent = apt_task_object_get(task);
+       apt_bool_t running = TRUE;
+       apr_status_t status;
+       apr_int32_t num;
+       const apr_pollfd_t *ret_pfd;
+       int i;
+
+       if(!agent) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Start MRCPv2 Agent");
+               return FALSE;
+       }
+
+       agent->pollset = apt_pollset_create((apr_uint32_t)agent->max_connection_count,agent->pool);
+       if(!agent->pollset) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Pollset");
+               return FALSE;
+       }
+
+       while(running) {
+               status = apt_pollset_poll(agent->pollset, -1, &num, &ret_pfd);
+               if(status != APR_SUCCESS) {
+                       continue;
+               }
+               for(i = 0; i < num; i++) {
+                       if(apt_pollset_is_wakeup(agent->pollset,&ret_pfd[i])) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process Control Message");
+                               if(mrcp_client_agent_control_process(agent) == FALSE) {
+                                       running = FALSE;
+                                       break;
+                               }
+                               continue;
+                       }
+       
+                       mrcp_client_agent_messsage_receive(agent,ret_pfd[i].client_data);
+               }
+       }
+
+       apt_pollset_destroy(agent->pollset);
+       agent->pollset = NULL;
+
+       apt_task_child_terminate(agent->task);
+       return TRUE;
+}
+
+static apt_bool_t mrcp_client_agent_task_terminate(apt_task_t *task)
+{
+       apt_bool_t status = FALSE;
+       mrcp_connection_agent_t *agent = apt_task_object_get(task);
+       if(agent->pollset) {
+               connection_task_msg_t *msg = apr_pcalloc(agent->pool,sizeof(connection_task_msg_t));
+               msg->type = CONNECTION_TASK_MSG_TERMINATE;
+
+               apr_thread_mutex_lock(agent->guard);
+               status = apt_cyclic_queue_push(agent->msg_queue,msg);
+               apr_thread_mutex_unlock(agent->guard);
+               if(apt_pollset_wakeup(agent->pollset) == TRUE) {
+                       status = TRUE;
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Signal Control Message");
+               }
+       }
+       return status;
+}
diff --git a/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_connection.c b/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_connection.c
new file mode 100644 (file)
index 0000000..079671a
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mrcp_connection.h"
+#include "apt_pool.h"
+
+mrcp_connection_t* mrcp_connection_create()
+{
+       mrcp_connection_t *connection;
+       apr_pool_t *pool = apt_pool_create();
+       if(!pool) {
+               return NULL;
+       }
+       
+       connection = apr_palloc(pool,sizeof(mrcp_connection_t));
+       connection->pool = pool;
+       apt_string_reset(&connection->remote_ip);
+       connection->l_sockaddr = NULL;
+       connection->r_sockaddr = NULL;
+       connection->sock = NULL;
+       connection->id = NULL;
+       connection->access_count = 0;
+       connection->it = NULL;
+       connection->channel_table = apr_hash_make(pool);
+       apt_text_stream_init(&connection->rx_stream,connection->rx_buffer,sizeof(connection->rx_buffer)-1);
+       apt_text_stream_init(&connection->tx_stream,connection->tx_buffer,sizeof(connection->tx_buffer)-1);
+       connection->parser = NULL;
+       connection->generator = NULL;
+       return connection;
+}
+
+void mrcp_connection_destroy(mrcp_connection_t *connection)
+{
+       if(connection && connection->pool) {
+               apr_pool_destroy(connection->pool);
+       }
+}
+
+apt_bool_t mrcp_connection_channel_add(mrcp_connection_t *connection, mrcp_control_channel_t *channel)
+{
+       if(!connection || !channel) {
+               return FALSE;
+       }
+       apr_hash_set(connection->channel_table,channel->identifier.buf,channel->identifier.length,channel);
+       channel->connection = connection;
+       connection->access_count++;
+       return TRUE;
+}
+
+mrcp_control_channel_t* mrcp_connection_channel_find(mrcp_connection_t *connection, const apt_str_t *identifier)
+{
+       if(!connection || !identifier) {
+               return NULL;
+       }
+       return apr_hash_get(connection->channel_table,identifier->buf,identifier->length);
+}
+
+apt_bool_t mrcp_connection_channel_remove(mrcp_connection_t *connection, mrcp_control_channel_t *channel)
+{
+       if(!connection || !channel) {
+               return FALSE;
+       }
+       apr_hash_set(connection->channel_table,channel->identifier.buf,channel->identifier.length,NULL);
+       channel->connection = NULL;
+       connection->access_count--;
+       return TRUE;
+}
diff --git a/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_control_descriptor.c b/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_control_descriptor.c
new file mode 100644 (file)
index 0000000..2e9a0e4
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apt_string_table.h"
+#include "mrcp_control_descriptor.h"
+
+/** String table of mrcp proto types (mrcp_proto_type_e) */
+static const apt_str_table_item_t mrcp_proto_type_table[] = {
+       {{"TCP/MRCPv2",    10},4},
+       {{"TCP/TLS/MRCPv2",14},4}
+};
+
+/** String table of mrcp attributes (mrcp_attrib_e) */
+static const apt_str_table_item_t mrcp_attrib_table[] = {
+       {{"setup",      5},0},
+       {{"connection",10},1},
+       {{"resource",   8},0},
+       {{"channel",    7},1},
+       {{"cmid",       4},1}
+};
+
+/** String table of mrcp setup attribute values (mrcp_setup_type_e) */
+static const apt_str_table_item_t mrcp_setup_value_table[] = {
+       {{"active",      6},0},
+       {{"passive",     7},0}
+};
+
+/** String table of mrcp connection attribute values (mrcp_connection_type_e) */
+static const apt_str_table_item_t mrcp_connection_value_table[] = {
+       {{"new",         3},0},
+       {{"existing",    8},0}
+};
+
+
+MRCP_DECLARE(const apt_str_t*) mrcp_proto_get(mrcp_proto_type_e proto)
+{
+       return apt_string_table_str_get(mrcp_proto_type_table,MRCP_PROTO_COUNT,proto);
+}
+
+MRCP_DECLARE(mrcp_proto_type_e) mrcp_proto_find(const apt_str_t *attrib)
+{
+       return apt_string_table_id_find(mrcp_proto_type_table,MRCP_PROTO_COUNT,attrib);
+}
+
+MRCP_DECLARE(const apt_str_t*) mrcp_attrib_str_get(mrcp_attrib_e attrib_id)
+{
+       return apt_string_table_str_get(mrcp_attrib_table,MRCP_ATTRIB_COUNT,attrib_id);
+}
+
+MRCP_DECLARE(mrcp_attrib_e) mrcp_attrib_id_find(const apt_str_t *attrib)
+{
+       return apt_string_table_id_find(mrcp_attrib_table,MRCP_ATTRIB_COUNT,attrib);
+}
+
+MRCP_DECLARE(const apt_str_t*) mrcp_setup_type_get(mrcp_setup_type_e setup_type)
+{
+       return apt_string_table_str_get(mrcp_setup_value_table,MRCP_SETUP_TYPE_COUNT,setup_type);
+}
+
+MRCP_DECLARE(mrcp_setup_type_e) mrcp_setup_type_find(const apt_str_t *attrib)
+{
+       return apt_string_table_id_find(mrcp_setup_value_table,MRCP_SETUP_TYPE_COUNT,attrib);
+}
+
+MRCP_DECLARE(const apt_str_t*) mrcp_connection_type_get(mrcp_connection_type_e connection_type)
+{
+       return apt_string_table_str_get(mrcp_connection_value_table,MRCP_CONNECTION_TYPE_COUNT,connection_type);
+}
+
+MRCP_DECLARE(mrcp_connection_type_e) mrcp_connection_type_find(const apt_str_t *attrib)
+{
+       return apt_string_table_id_find(mrcp_connection_value_table,MRCP_CONNECTION_TYPE_COUNT,attrib);
+}
+
+/** Create MRCP control offer */
+MRCP_DECLARE(mrcp_control_descriptor_t*) mrcp_control_offer_create(apr_pool_t *pool)
+{
+       mrcp_control_descriptor_t *offer;
+       offer = apr_palloc(pool,sizeof(mrcp_control_descriptor_t));
+       mrcp_control_descriptor_init(offer);
+       offer->proto = MRCP_PROTO_TCP;
+       offer->port = 9;
+       offer->setup_type = MRCP_SETUP_TYPE_ACTIVE;
+       offer->connection_type = MRCP_CONNECTION_TYPE_EXISTING;
+       return offer;
+}
+
+/** Create MRCP control answer */
+MRCP_DECLARE(mrcp_control_descriptor_t*) mrcp_control_answer_create(mrcp_control_descriptor_t *offer, apr_pool_t *pool)
+{
+       mrcp_control_descriptor_t *answer;
+       answer = apr_palloc(pool,sizeof(mrcp_control_descriptor_t));
+       mrcp_control_descriptor_init(answer);
+       if(offer) {
+               *answer = *offer;
+       }
+       answer->setup_type = MRCP_SETUP_TYPE_PASSIVE;
+       return answer;
+}
diff --git a/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_server_connection.c b/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_server_connection.c
new file mode 100644 (file)
index 0000000..1655697
--- /dev/null
@@ -0,0 +1,766 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mrcp_connection.h"
+#include "mrcp_server_connection.h"
+#include "mrcp_control_descriptor.h"
+#include "mrcp_resource_factory.h"
+#include "mrcp_message.h"
+#include "apt_text_stream.h"
+#include "apt_task.h"
+#include "apt_pool.h"
+#include "apt_pollset.h"
+#include "apt_cyclic_queue.h"
+#include "apt_log.h"
+
+#define MRCPV2_CONNECTION_TASK_NAME "TCP/MRCPv2 Connection Agent"
+
+struct mrcp_connection_agent_t {
+       apr_pool_t              *pool;
+       apt_task_t              *task;
+       mrcp_resource_factory_t *resource_factory;
+
+       apt_obj_list_t          *connection_list;
+       mrcp_connection_t       *null_connection;
+
+       apt_bool_t               force_new_connection;
+       apr_size_t               max_connection_count;
+
+       apr_sockaddr_t          *sockaddr;
+       /* Listening socket */
+       apr_socket_t            *listen_sock;
+       apr_pollfd_t             listen_sock_pfd;
+
+       apr_thread_mutex_t      *guard;
+       apt_cyclic_queue_t      *msg_queue;
+       apt_pollset_t           *pollset;
+
+       void                                 *obj;
+       const mrcp_connection_event_vtable_t *vtable;
+};
+
+typedef enum {
+       CONNECTION_TASK_MSG_ADD_CHANNEL,
+       CONNECTION_TASK_MSG_MODIFY_CHANNEL,
+       CONNECTION_TASK_MSG_REMOVE_CHANNEL,
+       CONNECTION_TASK_MSG_SEND_MESSAGE,
+       CONNECTION_TASK_MSG_TERMINATE
+} connection_task_msg_type_e;
+
+typedef struct connection_task_msg_t connection_task_msg_t;
+struct connection_task_msg_t {
+       connection_task_msg_type_e type;
+       mrcp_connection_agent_t   *agent;
+       mrcp_control_channel_t    *channel;
+       mrcp_control_descriptor_t *descriptor;
+       mrcp_message_t            *message;
+};
+
+static apt_bool_t mrcp_server_agent_task_run(apt_task_t *task);
+static apt_bool_t mrcp_server_agent_task_terminate(apt_task_t *task);
+static apt_bool_t mrcp_server_agent_task_on_destroy(apt_task_t *task);
+
+/** Create connection agent */
+MRCP_DECLARE(mrcp_connection_agent_t*) mrcp_server_connection_agent_create(
+                                                                               const char *listen_ip,
+                                                                               apr_port_t listen_port,
+                                                                               apr_size_t max_connection_count,
+                                                                               apt_bool_t force_new_connection,
+                                                                               apr_pool_t *pool)
+{
+       apt_task_vtable_t *vtable;
+       mrcp_connection_agent_t *agent;
+
+       if(!listen_ip) {
+               return NULL;
+       }
+       
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create "MRCPV2_CONNECTION_TASK_NAME" %s:%hu [%d]",listen_ip,listen_port,max_connection_count);
+       agent = apr_palloc(pool,sizeof(mrcp_connection_agent_t));
+       agent->pool = pool;
+       agent->sockaddr = NULL;
+       agent->listen_sock = NULL;
+       agent->pollset = NULL;
+       agent->max_connection_count = max_connection_count;
+       agent->force_new_connection = force_new_connection;
+
+       apr_sockaddr_info_get(&agent->sockaddr,listen_ip,APR_INET,listen_port,0,agent->pool);
+       if(!agent->sockaddr) {
+               return NULL;
+       }
+
+       agent->task = apt_task_create(agent,NULL,pool);
+       if(!agent->task) {
+               return NULL;
+       }
+
+       apt_task_name_set(agent->task,MRCPV2_CONNECTION_TASK_NAME);
+       vtable = apt_task_vtable_get(agent->task);
+       if(vtable) {
+               vtable->run = mrcp_server_agent_task_run;
+               vtable->terminate = mrcp_server_agent_task_terminate;
+               vtable->destroy = mrcp_server_agent_task_on_destroy;
+       }
+
+       agent->msg_queue = apt_cyclic_queue_create(CYCLIC_QUEUE_DEFAULT_SIZE);
+       apr_thread_mutex_create(&agent->guard,APR_THREAD_MUTEX_UNNESTED,pool);
+
+       agent->connection_list = NULL;
+       agent->null_connection = NULL;
+       return agent;
+}
+
+/** Virtual destroy handler. */
+static apt_bool_t mrcp_server_agent_task_on_destroy(apt_task_t *task)
+{
+       mrcp_connection_agent_t *agent = apt_task_object_get(task);
+       if(agent->guard) {
+               apr_thread_mutex_destroy(agent->guard);
+               agent->guard = NULL;
+       }
+       if(agent->msg_queue) {
+               apt_cyclic_queue_destroy(agent->msg_queue);
+               agent->msg_queue = NULL;
+       }
+       return TRUE;
+}
+
+/** Destroy connection agent. */
+MRCP_DECLARE(apt_bool_t) mrcp_server_connection_agent_destroy(mrcp_connection_agent_t *agent)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy MRCPv2 Agent");
+       return apt_task_destroy(agent->task);
+}
+
+/** Start connection agent. */
+MRCP_DECLARE(apt_bool_t) mrcp_server_connection_agent_start(mrcp_connection_agent_t *agent)
+{
+       return apt_task_start(agent->task);
+}
+
+/** Terminate connection agent. */
+MRCP_DECLARE(apt_bool_t) mrcp_server_connection_agent_terminate(mrcp_connection_agent_t *agent)
+{
+       return apt_task_terminate(agent->task,TRUE);
+}
+
+/** Set connection event handler. */
+MRCP_DECLARE(void) mrcp_server_connection_agent_handler_set(
+                                                                       mrcp_connection_agent_t *agent, 
+                                                                       void *obj, 
+                                                                       const mrcp_connection_event_vtable_t *vtable)
+{
+       agent->obj = obj;
+       agent->vtable = vtable;
+}
+
+/** Set MRCP resource factory */
+MRCP_DECLARE(void) mrcp_server_connection_resource_factory_set(
+                                                               mrcp_connection_agent_t *agent, 
+                                                               mrcp_resource_factory_t *resource_factroy)
+{
+       agent->resource_factory = resource_factroy;
+}
+
+/** Get task */
+MRCP_DECLARE(apt_task_t*) mrcp_server_connection_agent_task_get(mrcp_connection_agent_t *agent)
+{
+       return agent->task;
+}
+
+/** Get external object */
+MRCP_DECLARE(void*) mrcp_server_connection_agent_object_get(mrcp_connection_agent_t *agent)
+{
+       return agent->obj;
+}
+
+/** Create MRCPv2 control channel */
+MRCP_DECLARE(mrcp_control_channel_t*) mrcp_server_control_channel_create(mrcp_connection_agent_t *agent, void *obj, apr_pool_t *pool)
+{
+       mrcp_control_channel_t *channel = apr_palloc(pool,sizeof(mrcp_control_channel_t));
+       channel->agent = agent;
+       channel->connection = NULL;
+       channel->removed = FALSE;
+       channel->obj = obj;
+       channel->pool = pool;
+       return channel;
+}
+
+/** Destroy MRCPv2 control channel */
+MRCP_DECLARE(apt_bool_t) mrcp_server_control_channel_destroy(mrcp_control_channel_t *channel)
+{
+       if(channel && channel->connection && channel->removed == TRUE) {
+               mrcp_connection_t *connection = channel->connection;
+               channel->connection = NULL;
+               apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy TCP/MRCPv2 Connection %s",connection->id);
+               mrcp_connection_destroy(connection);
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_server_control_message_signal(
+                                                               connection_task_msg_type_e type,
+                                                               mrcp_connection_agent_t *agent,
+                                                               mrcp_control_channel_t *channel,
+                                                               mrcp_control_descriptor_t *descriptor,
+                                                               mrcp_message_t *message)
+{
+       apt_bool_t status;
+       connection_task_msg_t *msg = apr_palloc(channel->pool,sizeof(connection_task_msg_t));
+       msg->type = type;
+       msg->agent = agent;
+       msg->channel = channel;
+       msg->descriptor = descriptor;
+       msg->message = message;
+
+       apr_thread_mutex_lock(agent->guard);
+       status = apt_cyclic_queue_push(agent->msg_queue,msg);
+       apr_thread_mutex_unlock(agent->guard);
+       if(apt_pollset_wakeup(agent->pollset) != TRUE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Signal Control Message");
+               status = FALSE;
+       }
+       return status;
+}
+
+/** Add MRCPv2 control channel */
+MRCP_DECLARE(apt_bool_t) mrcp_server_control_channel_add(mrcp_control_channel_t *channel, mrcp_control_descriptor_t *descriptor)
+{
+       return mrcp_server_control_message_signal(CONNECTION_TASK_MSG_ADD_CHANNEL,channel->agent,channel,descriptor,NULL);
+}
+
+/** Modify MRCPv2 control channel */
+MRCP_DECLARE(apt_bool_t) mrcp_server_control_channel_modify(mrcp_control_channel_t *channel, mrcp_control_descriptor_t *descriptor)
+{
+       return mrcp_server_control_message_signal(CONNECTION_TASK_MSG_MODIFY_CHANNEL,channel->agent,channel,descriptor,NULL);
+}
+
+/** Remove MRCPv2 control channel */
+MRCP_DECLARE(apt_bool_t) mrcp_server_control_channel_remove(mrcp_control_channel_t *channel)
+{
+       return mrcp_server_control_message_signal(CONNECTION_TASK_MSG_REMOVE_CHANNEL,channel->agent,channel,NULL,NULL);
+}
+
+/** Send MRCPv2 message */
+MRCP_DECLARE(apt_bool_t) mrcp_server_control_message_send(mrcp_control_channel_t *channel, mrcp_message_t *message)
+{
+       return mrcp_server_control_message_signal(CONNECTION_TASK_MSG_SEND_MESSAGE,channel->agent,channel,NULL,message);
+}
+
+
+static apt_bool_t mrcp_server_agent_listen_socket_create(mrcp_connection_agent_t *agent)
+{
+       apr_status_t status;
+       if(!agent->sockaddr) {
+               return FALSE;
+       }
+
+       /* create listening socket */
+       status = apr_socket_create(&agent->listen_sock, agent->sockaddr->family, SOCK_STREAM, APR_PROTO_TCP, agent->pool);
+       if(status != APR_SUCCESS) {
+               return FALSE;
+       }
+
+       apr_socket_opt_set(agent->listen_sock, APR_SO_NONBLOCK, 0);
+       apr_socket_timeout_set(agent->listen_sock, -1);
+       apr_socket_opt_set(agent->listen_sock, APR_SO_REUSEADDR, 1);
+
+       status = apr_socket_bind(agent->listen_sock, agent->sockaddr);
+       if(status != APR_SUCCESS) {
+               apr_socket_close(agent->listen_sock);
+               agent->listen_sock = NULL;
+               return FALSE;
+       }
+       status = apr_socket_listen(agent->listen_sock, SOMAXCONN);
+       if(status != APR_SUCCESS) {
+               apr_socket_close(agent->listen_sock);
+               agent->listen_sock = NULL;
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static void mrcp_server_agent_listen_socket_destroy(mrcp_connection_agent_t *agent)
+{
+       if(agent->listen_sock) {
+               apr_socket_close(agent->listen_sock);
+               agent->listen_sock = NULL;
+       }
+}
+
+static apt_bool_t mrcp_server_agent_pollset_create(mrcp_connection_agent_t *agent)
+{
+       /* create pollset */
+       agent->pollset = apt_pollset_create((apr_uint32_t)agent->max_connection_count + 1, agent->pool);
+       if(!agent->pollset) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Pollset");
+               return FALSE;
+       }
+
+       if(mrcp_server_agent_listen_socket_create(agent) == TRUE) {
+               /* add listen socket to pollset */
+               memset(&agent->listen_sock_pfd,0,sizeof(apr_pollfd_t));
+               agent->listen_sock_pfd.desc_type = APR_POLL_SOCKET;
+               agent->listen_sock_pfd.reqevents = APR_POLLIN;
+               agent->listen_sock_pfd.desc.s = agent->listen_sock;
+               agent->listen_sock_pfd.client_data = agent->listen_sock;
+               if(apt_pollset_add(agent->pollset, &agent->listen_sock_pfd) != TRUE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Add Listen Socket to Pollset");
+                       mrcp_server_agent_listen_socket_destroy(agent);
+               }
+       }
+       else {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Listen Socket");
+       }
+
+       return TRUE;
+}
+
+static void mrcp_server_agent_pollset_destroy(mrcp_connection_agent_t *agent)
+{
+       mrcp_server_agent_listen_socket_destroy(agent);
+       if(agent->pollset) {
+               apt_pollset_destroy(agent->pollset);
+               agent->pollset = NULL;
+       }
+}
+
+
+static mrcp_control_channel_t* mrcp_connection_channel_associate(mrcp_connection_agent_t *agent, mrcp_connection_t *connection, const mrcp_message_t *message)
+{
+       apt_str_t identifier;
+       mrcp_control_channel_t *channel;
+       if(!connection || !message) {
+               return NULL;
+       }
+       apt_id_resource_generate(&message->channel_id.session_id,&message->channel_id.resource_name,'@',&identifier,connection->pool);
+       channel = mrcp_connection_channel_find(connection,&identifier);
+       if(!channel) {
+               channel = mrcp_connection_channel_find(agent->null_connection,&identifier);
+               if(channel) {
+                       mrcp_connection_channel_remove(agent->null_connection,channel);
+                       mrcp_connection_channel_add(connection,channel);
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Move Control Channel <%s> to Connection %s [%d]",
+                               channel->identifier.buf,
+                               connection->id,
+                               apr_hash_count(connection->channel_table));
+               }
+       }
+       return channel;
+}
+
+static mrcp_connection_t* mrcp_connection_find(mrcp_connection_agent_t *agent, const apt_str_t *remote_ip)
+{
+       mrcp_connection_t *connection = NULL;
+       apt_list_elem_t *elem;
+       if(!agent || !agent->connection_list || !remote_ip) {
+               return NULL;
+       }
+
+       elem = apt_list_first_elem_get(agent->connection_list);
+       /* walk through the list of connections */
+       while(elem) {
+               connection = apt_list_elem_object_get(elem);
+               if(connection) {
+                       if(apt_string_compare(&connection->remote_ip,remote_ip) == TRUE) {
+                               return connection;
+                       }
+               }
+               elem = apt_list_next_elem_get(agent->connection_list,elem);
+       }
+       return NULL;
+}
+
+static apt_bool_t mrcp_connection_remove(mrcp_connection_agent_t *agent, mrcp_connection_t *connection)
+{
+       if(connection->it) {
+               apt_list_elem_remove(agent->connection_list,connection->it);
+               connection->it = NULL;
+       }
+       if(agent->null_connection) {
+               if(apt_list_is_empty(agent->connection_list) == TRUE && apr_hash_count(agent->null_connection->channel_table) == 0) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Destroy Pending Connection");
+                       mrcp_connection_destroy(agent->null_connection);
+                       agent->null_connection = NULL;
+                       agent->connection_list = NULL;
+               }
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_server_agent_connection_accept(mrcp_connection_agent_t *agent)
+{
+       char *local_ip = NULL;
+       char *remote_ip = NULL;
+       apr_socket_t *sock;
+       apr_pool_t *pool;
+       mrcp_connection_t *connection;
+
+       if(!agent->null_connection) {
+               pool = apt_pool_create();
+               if(apr_socket_accept(&sock,agent->listen_sock,pool) != APR_SUCCESS) {
+                       return FALSE;
+               }
+               apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Rejected TCP/MRCPv2 Connection");
+               apr_socket_close(sock);
+               apr_pool_destroy(pool);
+               return FALSE;
+       }
+
+       pool = agent->null_connection->pool;
+       if(apr_socket_accept(&sock,agent->listen_sock,pool) != APR_SUCCESS) {
+               return FALSE;
+       }
+
+       connection = mrcp_connection_create();
+       connection->sock = sock;
+
+       if(apr_socket_addr_get(&connection->r_sockaddr,APR_REMOTE,sock) != APR_SUCCESS ||
+               apr_socket_addr_get(&connection->l_sockaddr,APR_LOCAL,sock) != APR_SUCCESS) {
+               apr_socket_close(sock);
+               mrcp_connection_destroy(connection);
+               return FALSE;
+       }
+
+       apr_sockaddr_ip_get(&local_ip,connection->l_sockaddr);
+       apr_sockaddr_ip_get(&remote_ip,connection->r_sockaddr);
+       apt_string_set(&connection->remote_ip,remote_ip);
+       connection->id = apr_psprintf(connection->pool,"%s:%hu <-> %s:%hu",
+               local_ip,connection->l_sockaddr->port,
+               remote_ip,connection->r_sockaddr->port);
+
+       memset(&connection->sock_pfd,0,sizeof(apr_pollfd_t));
+       connection->sock_pfd.desc_type = APR_POLL_SOCKET;
+       connection->sock_pfd.reqevents = APR_POLLIN;
+       connection->sock_pfd.desc.s = connection->sock;
+       connection->sock_pfd.client_data = connection;
+       if(apt_pollset_add(agent->pollset, &connection->sock_pfd) != TRUE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Add to Pollset");
+               apr_socket_close(sock);
+               mrcp_connection_destroy(connection);
+               return FALSE;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Accepted TCP/MRCPv2 Connection %s",connection->id);
+       connection->agent = agent;
+       connection->it = apt_list_push_back(agent->connection_list,connection,connection->pool);
+       connection->parser = mrcp_parser_create(agent->resource_factory,connection->pool);
+       connection->generator = mrcp_generator_create(agent->resource_factory,connection->pool);
+       return TRUE;
+}
+
+static apt_bool_t mrcp_server_agent_connection_close(mrcp_connection_agent_t *agent, mrcp_connection_t *connection)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"TCP/MRCPv2 Peer Disconnected %s",connection->id);
+       apt_pollset_remove(agent->pollset,&connection->sock_pfd);
+       apr_socket_close(connection->sock);
+       connection->sock = NULL;
+       if(!connection->access_count) {
+               mrcp_connection_remove(agent,connection);
+               apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy TCP/MRCPv2 Connection %s",connection->id);
+               mrcp_connection_destroy(connection);
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_server_agent_channel_add(mrcp_connection_agent_t *agent, mrcp_control_channel_t *channel, mrcp_control_descriptor_t *offer)
+{
+       mrcp_control_descriptor_t *answer = mrcp_control_answer_create(offer,channel->pool);
+       apt_id_resource_generate(&offer->session_id,&offer->resource_name,'@',&channel->identifier,channel->pool);
+       if(offer->port) {
+               answer->port = agent->sockaddr->port;
+       }
+       if(offer->connection_type == MRCP_CONNECTION_TYPE_EXISTING) {
+               if(agent->force_new_connection == TRUE) {
+                       /* force client to establish new connection */
+                       answer->connection_type = MRCP_CONNECTION_TYPE_NEW;
+               }
+               else {
+                       mrcp_connection_t *connection = NULL;
+                       /* try to find any existing connection */
+                       connection = mrcp_connection_find(agent,&offer->ip);
+                       if(!connection) {
+                               /* no existing conection found, force the new one */
+                               answer->connection_type = MRCP_CONNECTION_TYPE_NEW;
+                       }
+               }
+       }
+
+       if(!agent->null_connection) {
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Create Pending Connection");
+               agent->null_connection = mrcp_connection_create();
+               agent->connection_list = apt_list_create(agent->null_connection->pool);
+       }
+       mrcp_connection_channel_add(agent->null_connection,channel);    
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Add Control Channel <%s> to Pending Connection [%d]",
+                       channel->identifier.buf,
+                       apr_hash_count(agent->null_connection->channel_table));
+       /* send response */
+       return mrcp_control_channel_add_respond(agent->vtable,channel,answer,TRUE);
+}
+
+static apt_bool_t mrcp_server_agent_channel_modify(mrcp_connection_agent_t *agent, mrcp_control_channel_t *channel, mrcp_control_descriptor_t *offer)
+{
+       mrcp_control_descriptor_t *answer = mrcp_control_answer_create(offer,channel->pool);
+       if(offer->port) {
+               answer->port = agent->sockaddr->port;
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Modify Control Channel <%s>",channel->identifier.buf);
+       /* send response */
+       return mrcp_control_channel_modify_respond(agent->vtable,channel,answer,TRUE);
+}
+
+static apt_bool_t mrcp_server_agent_channel_remove(mrcp_connection_agent_t *agent, mrcp_control_channel_t *channel)
+{
+       mrcp_connection_t *connection = channel->connection;
+       mrcp_connection_channel_remove(connection,channel);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remove Control Channel <%s> [%d]",
+                       channel->identifier.buf,
+                       apr_hash_count(connection->channel_table));
+       if(!connection->access_count) {
+               if(connection == agent->null_connection) {
+                       if(apt_list_is_empty(agent->connection_list) == TRUE) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Destroy Pending Connection");
+                               mrcp_connection_destroy(agent->null_connection);
+                               agent->null_connection = NULL;
+                               agent->connection_list = NULL;
+                       }
+               }
+               else if(!connection->sock) {
+                       mrcp_connection_remove(agent,connection);
+                       /* set connection to be destroyed on channel destroy */
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Mark Connection for Late Destroy");
+                       channel->connection = connection;
+                       channel->removed = TRUE;
+               }
+       }
+       /* send response */
+       return mrcp_control_channel_remove_respond(agent->vtable,channel,TRUE);
+}
+
+static apt_bool_t mrcp_server_agent_messsage_send(mrcp_connection_agent_t *agent, mrcp_connection_t *connection, mrcp_message_t *message)
+{
+       apt_bool_t status = FALSE;
+       apt_text_stream_t *stream;
+       mrcp_stream_result_e result;
+       if(!connection || !connection->sock) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No MRCPv2 Connection");
+               return FALSE;
+       }
+       stream = &connection->tx_stream;
+
+       mrcp_generator_message_set(connection->generator,message);
+       do {
+               apt_text_stream_init(&connection->tx_stream,connection->tx_buffer,sizeof(connection->tx_buffer)-1);
+               result = mrcp_generator_run(connection->generator,stream);
+               if(result == MRCP_STREAM_MESSAGE_COMPLETE || result == MRCP_STREAM_MESSAGE_TRUNCATED) {
+                       stream->text.length = stream->pos - stream->text.buf;
+                       *stream->pos = '\0';
+
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Send MRCPv2 Stream %s [%lu bytes]\n%s",
+                               connection->id,
+                               stream->text.length,
+                               stream->text.buf);
+                       if(apr_socket_send(connection->sock,stream->text.buf,&stream->text.length) == APR_SUCCESS) {
+                               status = TRUE;
+                       }
+                       else {
+                               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Send MRCPv2 Stream");
+                       }
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Generate MRCPv2 Stream");
+               }
+       }
+       while(result == MRCP_STREAM_MESSAGE_TRUNCATED);
+
+       return status;
+}
+
+static apt_bool_t mrcp_server_message_handler(void *obj, mrcp_message_t *message, mrcp_stream_result_e result)
+{
+       mrcp_connection_t *connection = obj;
+       mrcp_connection_agent_t *agent = connection->agent;
+       if(result == MRCP_STREAM_MESSAGE_COMPLETE) {
+               /* message is completely parsed */
+               mrcp_control_channel_t *channel = mrcp_connection_channel_associate(agent,connection,message);
+               if(channel) {
+                       mrcp_connection_message_receive(agent->vtable,channel,message);
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Find Channel <%s@%s> in Connection %s",
+                               message->channel_id.session_id.buf,
+                               message->channel_id.resource_name.buf,
+                               connection->id);
+               }
+       }
+       else if(result == MRCP_STREAM_MESSAGE_INVALID) {
+               /* error case */
+               mrcp_message_t *response;
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse MRCPv2 Stream");
+               response = mrcp_response_create(message,message->pool);
+               response->start_line.status_code = MRCP_STATUS_CODE_UNRECOGNIZED_MESSAGE;
+               if(mrcp_server_agent_messsage_send(agent,connection,response) == FALSE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Send MRCPv2 Response");
+               }
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_server_agent_messsage_receive(mrcp_connection_agent_t *agent, mrcp_connection_t *connection)
+{
+       apr_status_t status;
+       apr_size_t offset;
+       apr_size_t length;
+       apt_text_stream_t *stream;
+
+       if(!connection || !connection->sock) {
+               return FALSE;
+       }
+       stream = &connection->rx_stream;
+       
+       /* init length of the stream */
+       stream->text.length = sizeof(connection->rx_buffer)-1;
+       /* calculate offset remaining from the previous receive / if any */
+       offset = stream->pos - stream->text.buf;
+       /* calculate available length */
+       length = stream->text.length - offset;
+       status = apr_socket_recv(connection->sock,stream->pos,&length);
+       if(status == APR_EOF || length == 0) {
+               return mrcp_server_agent_connection_close(agent,connection);
+       }
+       /* calculate actual length of the stream */
+       stream->text.length = offset + length;
+       stream->pos[length] = '\0';
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive MRCPv2 Stream %s [%lu bytes]\n%s",
+               connection->id,
+               length,
+               stream->pos);
+
+       /* reset pos */
+       stream->pos = stream->text.buf;
+       /* walk through the stream parsing RTSP messages */
+       return mrcp_stream_walk(connection->parser,stream,mrcp_server_message_handler,connection);
+}
+
+static apt_bool_t mrcp_server_agent_control_process(mrcp_connection_agent_t *agent)
+{
+       apt_bool_t status = TRUE;
+       apt_bool_t running = TRUE;
+       connection_task_msg_t *msg;
+
+       do {
+               apr_thread_mutex_lock(agent->guard);
+               msg = apt_cyclic_queue_pop(agent->msg_queue);
+               apr_thread_mutex_unlock(agent->guard);
+               if(msg) {
+                       switch(msg->type) {
+                               case CONNECTION_TASK_MSG_ADD_CHANNEL:
+                                       mrcp_server_agent_channel_add(agent,msg->channel,msg->descriptor);
+                                       break;
+                               case CONNECTION_TASK_MSG_MODIFY_CHANNEL:
+                                       mrcp_server_agent_channel_modify(agent,msg->channel,msg->descriptor);
+                                       break;
+                               case CONNECTION_TASK_MSG_REMOVE_CHANNEL:
+                                       mrcp_server_agent_channel_remove(agent,msg->channel);
+                                       break;
+                               case CONNECTION_TASK_MSG_SEND_MESSAGE:
+                                       mrcp_server_agent_messsage_send(agent,msg->channel->connection,msg->message);
+                                       break;
+                               case CONNECTION_TASK_MSG_TERMINATE:
+                                       status = FALSE;
+                                       break;
+                       }
+               }
+               else {
+                       running = FALSE;
+               }
+       }
+       while(running == TRUE);
+       return status;
+}
+
+static apt_bool_t mrcp_server_agent_task_run(apt_task_t *task)
+{
+       mrcp_connection_agent_t *agent = apt_task_object_get(task);
+       apt_bool_t running = TRUE;
+       apr_status_t status;
+       apr_int32_t num;
+       const apr_pollfd_t *ret_pfd;
+       int i;
+
+       if(!agent) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Start MRCPv2 Agent");
+               return FALSE;
+       }
+
+       if(mrcp_server_agent_pollset_create(agent) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Pollset");
+               return FALSE;
+       }
+
+       while(running) {
+               status = apt_pollset_poll(agent->pollset, -1, &num, &ret_pfd);
+               if(status != APR_SUCCESS) {
+                       continue;
+               }
+               for(i = 0; i < num; i++) {
+                       if(ret_pfd[i].desc.s == agent->listen_sock) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Accept MRCPv2 Connection");
+                               mrcp_server_agent_connection_accept(agent);
+                               continue;
+                       }
+                       if(apt_pollset_is_wakeup(agent->pollset,&ret_pfd[i])) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process Control Message");
+                               if(mrcp_server_agent_control_process(agent) == FALSE) {
+                                       running = FALSE;
+                                       break;
+                               }
+                               continue;
+                       }
+       
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process MRCPv2 Message");
+                       mrcp_server_agent_messsage_receive(agent,ret_pfd[i].client_data);
+               }
+       }
+
+       mrcp_server_agent_pollset_destroy(agent);
+
+       apt_task_child_terminate(agent->task);
+       return TRUE;
+}
+
+static apt_bool_t mrcp_server_agent_task_terminate(apt_task_t *task)
+{
+       apt_bool_t status = FALSE;
+       mrcp_connection_agent_t *agent = apt_task_object_get(task);
+       if(agent->pollset) {
+               connection_task_msg_t *msg = apr_pcalloc(agent->pool,sizeof(connection_task_msg_t));
+               msg->type = CONNECTION_TASK_MSG_TERMINATE;
+
+               apr_thread_mutex_lock(agent->guard);
+               status = apt_cyclic_queue_push(agent->msg_queue,msg);
+               apr_thread_mutex_unlock(agent->guard);
+               if(apt_pollset_wakeup(agent->pollset) == TRUE) {
+                       status = TRUE;
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Signal Control Message");
+               }
+       }
+       return status;
+}
diff --git a/libs/unimrcp/libs/uni-rtsp/Makefile.am b/libs/unimrcp/libs/uni-rtsp/Makefile.am
new file mode 100644 (file)
index 0000000..00f5ec5
--- /dev/null
@@ -0,0 +1,22 @@
+MAINTAINERCLEANFILES    = Makefile.in
+
+INCLUDES                 = -I$(top_srcdir)/libs/uni-rtsp/include \
+                           -I$(top_srcdir)/libs/apr-toolkit/include \
+                           $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+noinst_LTLIBRARIES       = libunirtsp.la
+
+include_HEADERS          = include/rtsp.h \
+                           include/rtsp_header.h \
+                           include/rtsp_start_line.h \
+                           include/rtsp_message.h \
+                           include/rtsp_stream.h \
+                           include/rtsp_server.h \
+                           include/rtsp_client.h
+
+libunirtsp_la_SOURCES    = src/rtsp_header.c \
+                           src/rtsp_start_line.c \
+                           src/rtsp_message.c \
+                           src/rtsp_stream.c \
+                           src/rtsp_server.c \
+                           src/rtsp_client.c
diff --git a/libs/unimrcp/libs/uni-rtsp/include/rtsp.h b/libs/unimrcp/libs/uni-rtsp/include/rtsp.h
new file mode 100644 (file)
index 0000000..d2d029f
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __RTSP_H__
+#define __RTSP_H__
+
+/**
+ * @file rtsp.h
+ * @brief RTSP Core Definitions
+ */ 
+
+#include <apt.h>
+#include <apr_network_io.h>
+
+/** Library export/import defines */
+#ifdef WIN32
+#ifdef RTSP_STATIC_LIB
+#define RTSP_DECLARE(type)   type __stdcall
+#else
+#ifdef RTSP_LIB_EXPORT
+#define RTSP_DECLARE(type)   __declspec(dllexport) type __stdcall
+#else
+#define RTSP_DECLARE(type)   __declspec(dllimport) type __stdcall
+#endif
+#endif
+#else
+#define RTSP_DECLARE(type) type
+#endif
+
+#endif /*__RTSP_H__*/
diff --git a/libs/unimrcp/libs/uni-rtsp/include/rtsp_client.h b/libs/unimrcp/libs/uni-rtsp/include/rtsp_client.h
new file mode 100644 (file)
index 0000000..4d3bd1f
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __RTSP_CLIENT_H__
+#define __RTSP_CLIENT_H__
+
+/**
+ * @file rtsp_client.h
+ * @brief RTSP Client
+ */ 
+
+#include "apt_task.h"
+#include "rtsp_message.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque RTSP client declaration */
+typedef struct rtsp_client_t rtsp_client_t;
+/** Opaque RTSP client session declaration */
+typedef struct rtsp_client_session_t rtsp_client_session_t;
+
+/** RTSP client vtable declaration */
+typedef struct rtsp_client_vtable_t rtsp_client_vtable_t;
+
+/** RTSP client vtable */
+struct rtsp_client_vtable_t {
+       /** Sesssion termination response handler */
+       apt_bool_t (*on_session_terminate_response)(rtsp_client_t *client, rtsp_client_session_t *session);
+       /** Sesssion termination event handler */
+       apt_bool_t (*on_session_terminate_event)(rtsp_client_t *client, rtsp_client_session_t *session);
+       /** Sesssion setup response handler */
+       apt_bool_t (*on_session_response)(rtsp_client_t *client, rtsp_client_session_t *session, rtsp_message_t *request, rtsp_message_t *response);
+       /** Sesssion event handler */
+       apt_bool_t (*on_session_event)(rtsp_client_t *client, rtsp_client_session_t *session, rtsp_message_t *message);
+};
+
+/**
+ * Create RTSP client.
+ * @param max_connection_count the number of max RTSP connections
+ * @param obj the external object to send event to
+ * @param handler the response/event handler
+ * @param pool the pool to allocate memory from
+ */
+RTSP_DECLARE(rtsp_client_t*) rtsp_client_create(
+                                                               apr_size_t max_connection_count,
+                                                               void *obj,
+                                                               const rtsp_client_vtable_t *handler,
+                                                               apr_pool_t *pool);
+
+/**
+ * Destroy RTSP client.
+ * @param client the client to destroy
+ */
+RTSP_DECLARE(apt_bool_t) rtsp_client_destroy(rtsp_client_t *client);
+
+/**
+ * Start client and wait for incoming requests.
+ * @param client the client to start
+ */
+RTSP_DECLARE(apt_bool_t) rtsp_client_start(rtsp_client_t *client);
+
+/**
+ * Terminate client.
+ * @param client the client to terminate
+ */
+RTSP_DECLARE(apt_bool_t) rtsp_client_terminate(rtsp_client_t *client);
+
+/**
+ * Get task.
+ * @param client the client to get task from
+ */
+RTSP_DECLARE(apt_task_t*) rtsp_client_task_get(rtsp_client_t *client);
+
+/**
+ * Get external object.
+ * @param client the client to get object from
+ */
+RTSP_DECLARE(void*) rtsp_client_object_get(rtsp_client_t *client);
+
+
+/**
+ * Create RTSP session.
+ * @param client the client to create session for
+ * @param server_ip the IP address of RTSP server
+ * @param server_port the port of RTSP server
+ * @param resource_location the location of RTSP resource (path in RTSP URI)
+ */
+RTSP_DECLARE(rtsp_client_session_t*) rtsp_client_session_create(
+                                                                                       rtsp_client_t *client, 
+                                                                                       const char *server_ip, 
+                                                                                       apr_port_t server_port,
+                                                                                       const char *resource_location);
+
+/**
+ * Destroy RTSP session.
+ * @param session the session to destroy
+ */
+RTSP_DECLARE(void) rtsp_client_session_destroy(rtsp_client_session_t *session);
+
+/**
+ * Terminate RTSP session.
+ * @param client the client to use
+ * @param session the session to terminate
+ */
+RTSP_DECLARE(apt_bool_t) rtsp_client_session_terminate(rtsp_client_t *client, rtsp_client_session_t *session);
+
+/**
+ * Send RTSP message.
+ * @param client the client to use
+ * @param session the session to send RTSP request for
+ * @param message the RTSP request to send
+ */
+RTSP_DECLARE(apt_bool_t) rtsp_client_session_request(rtsp_client_t *client, rtsp_client_session_t *session, rtsp_message_t *message);
+
+/**
+ * Get object associated with the session.
+ * @param session the session to get object from
+ */
+RTSP_DECLARE(void*) rtsp_client_session_object_get(const rtsp_client_session_t *session);
+
+/**
+ * Set object associated with the session.
+ * @param session the session to set object for
+ * @param obj the object to set
+ */
+RTSP_DECLARE(void) rtsp_client_session_object_set(rtsp_client_session_t *session, void *obj);
+
+/**
+ * Get the session identifier.
+ * @param session the session to get identifier from
+ */
+RTSP_DECLARE(const apt_str_t*) rtsp_client_session_id_get(const rtsp_client_session_t *session);
+
+APT_END_EXTERN_C
+
+#endif /*__RTSP_CLIENT_H__*/
diff --git a/libs/unimrcp/libs/uni-rtsp/include/rtsp_header.h b/libs/unimrcp/libs/uni-rtsp/include/rtsp_header.h
new file mode 100644 (file)
index 0000000..68b5ec2
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __RTSP_HEADER_H__
+#define __RTSP_HEADER_H__
+
+/**
+ * @file rtsp_header.h
+ * @brief RTSP Header
+ */ 
+
+#include "rtsp.h"
+#include "apt_text_stream.h"
+
+APT_BEGIN_EXTERN_C
+
+/** RTSP transport protocol */
+typedef enum{
+       RTSP_TRANSPORT_RTP,
+
+       RTSP_TRANSPORT_COUNT,
+       RTSP_TRANSPORT_NONE = RTSP_TRANSPORT_COUNT
+} rtsp_transport_e;
+
+/** RTSP transport profile */
+typedef enum{
+       RTSP_PROFILE_AVP,
+       RTSP_PROFILE_SAVP,
+
+       RTSP_PROFILE_COUNT,
+       RTSP_PROFILE_NONE = RTSP_PROFILE_COUNT
+} rtsp_profile_e;
+
+/** RTSP lower-transport */
+typedef enum{
+       RTSP_LOWER_TRANSPORT_UDP,
+       RTSP_LOWER_TRANSPORT_TCP,
+
+       RTSP_LOWER_TRANSPORT_COUNT,
+       RTSP_LOWER_TRANSPORT_NONE = RTSP_LOWER_TRANSPORT_COUNT
+} rtsp_lower_transport_e;
+
+/** RTSP transport attributes */
+typedef enum{
+       RTSP_TRANSPORT_ATTRIB_CLIENT_PORT,
+       RTSP_TRANSPORT_ATTRIB_SERVER_PORT,
+       RTSP_TRANSPORT_ATTRIB_SOURCE,
+       RTSP_TRANSPORT_ATTRIB_DESTINATION,
+       RTSP_TRANSPORT_ATTRIB_UNICAST,
+       RTSP_TRANSPORT_ATTRIB_MULTICAST,
+
+       RTSP_TRANSPORT_ATTRIB_COUNT,
+       RTSP_TRANSPORT_ATTRIB_NONE = RTSP_TRANSPORT_ATTRIB_COUNT
+} rtsp_transport_attrib_e;
+
+/** RTSP delivery */
+typedef enum{
+       RTSP_DELIVERY_UNICAST,
+       RTSP_DELIVERY_MULTICAST,
+
+       RTSP_DELIVERY_COUNT,
+       RTSP_DELIVERY_NONE = RTSP_DELIVERY_COUNT
+} rtsp_delivery_e;
+
+/** RTSP header fields */
+typedef enum{
+       RTSP_HEADER_FIELD_CSEQ,
+       RTSP_HEADER_FIELD_TRANSPORT,
+       RTSP_HEADER_FIELD_SESSION_ID,
+       RTSP_HEADER_FIELD_RTP_INFO,
+       RTSP_HEADER_FIELD_CONTENT_TYPE,
+       RTSP_HEADER_FIELD_CONTENT_LENGTH,
+
+       RTSP_HEADER_FIELD_COUNT,
+       RTSP_HEADER_FIELD_UNKNOWN = RTSP_HEADER_FIELD_COUNT
+} rtsp_header_field_id;
+
+/** RTSP content types */
+typedef enum {
+       RTSP_CONTENT_TYPE_SDP,
+       RTSP_CONTENT_TYPE_MRCP,
+
+       RTSP_CONTENT_TYPE_COUNT,
+       RTSP_CONTENT_TYPE_NONE = RTSP_CONTENT_TYPE_COUNT
+} rtsp_content_type_e;
+
+
+/** Bit field masks are used to define property set */
+typedef int rtsp_header_property_t;
+
+
+/** RTSP/RTP port range declaration */
+typedef struct rtsp_port_range_t rtsp_port_range_t;
+/** RTSP transport declaration */
+typedef struct rtsp_transport_t rtsp_transport_t;
+/** RTSP header declaration */
+typedef struct rtsp_header_t rtsp_header_t;
+
+/** RTSP/RTP port range */
+struct rtsp_port_range_t {
+       /** Min (low) port */
+       apr_port_t min;
+       /** Max (high) port */
+       apr_port_t max;
+};
+
+/** RTSP transport */
+struct rtsp_transport_t {
+       /** Transport profile */
+       rtsp_transport_e         protocol;
+       /** Transport profile */
+       rtsp_profile_e           profile;
+       /** Lower transport */
+       rtsp_lower_transport_e   lower_protocol;
+       /** Delivery method */
+       rtsp_delivery_e          delivery;
+       /** Client port range */
+       rtsp_port_range_t        client_port_range;
+       /** Server port range */
+       rtsp_port_range_t        server_port_range;
+       /** Source IP address */
+       apt_str_t                source;
+       /** Destination IP address */
+       apt_str_t                destination;
+};
+
+/** RTSP header */
+struct rtsp_header_t {
+       /** Sequence number */
+       apr_size_t             cseq;
+       /** Transport */
+       rtsp_transport_t       transport; 
+       /** Session identifier */
+       apt_str_t              session_id;
+       /** RTP-info */
+       apt_str_t              rtp_info;
+
+       /** Content type */
+       rtsp_content_type_e    content_type;
+       /** Content length */
+       apr_size_t             content_length;
+
+       /** Property set */
+       rtsp_header_property_t property_set;
+};
+
+
+/** Initialize port range */
+static APR_INLINE void rtsp_port_range_init(rtsp_port_range_t *port_range)
+{
+       port_range->min = 0;
+       port_range->max = 0;
+}
+
+/** Initialize port range */
+static APR_INLINE apt_bool_t rtsp_port_range_is_valid(const rtsp_port_range_t *port_range)
+{
+       return (port_range->min == 0 && port_range->max == 0) == FALSE;
+}
+
+/** Initialize transport */
+static APR_INLINE void rtsp_transport_init(rtsp_transport_t *transport)
+{
+       transport->protocol = RTSP_TRANSPORT_RTP;
+       transport->profile = RTSP_PROFILE_NONE;
+       transport->lower_protocol = RTSP_LOWER_TRANSPORT_NONE;
+       rtsp_port_range_init(&transport->client_port_range);
+       rtsp_port_range_init(&transport->server_port_range);
+       apt_string_reset(&transport->source);
+       apt_string_reset(&transport->destination);
+}
+
+/** Initialize header */
+static APR_INLINE void rtsp_header_init(rtsp_header_t *header)
+{
+       header->cseq = 0;
+       rtsp_transport_init(&header->transport);
+       apt_string_reset(&header->session_id);
+       apt_string_reset(&header->rtp_info);
+       header->content_type = RTSP_CONTENT_TYPE_NONE;
+       header->content_length = 0;
+       header->property_set = 0;
+}
+
+/** Parse RTSP message */
+RTSP_DECLARE(apt_bool_t) rtsp_header_parse(rtsp_header_t *header, apt_text_stream_t *text_stream, apr_pool_t *pool);
+/** Generate RTSP message */
+RTSP_DECLARE(apt_bool_t) rtsp_header_generate(rtsp_header_t *header, apt_text_stream_t *text_stream);
+
+
+
+/** Add property to property set */
+static APR_INLINE void rtsp_header_property_add(rtsp_header_property_t *property_set, apr_size_t id)
+{
+       int mask = 1 << id;
+       *property_set |= mask;
+}
+
+/** Remove property from property set */
+static APR_INLINE void rtsp_header_property_remove(rtsp_header_property_t *property_set, apr_size_t id)
+{
+       int mask = 1 << id;
+       *property_set &= ~mask;
+}
+
+/** Check property in property set */
+static APR_INLINE apt_bool_t rtsp_header_property_check(const rtsp_header_property_t *property_set, apr_size_t id)
+{
+       int mask = 1 << id;
+       return ((*property_set & mask) == mask) ? TRUE : FALSE;
+}
+
+APT_END_EXTERN_C
+
+#endif /*__RTSP_HEADER_H__*/
diff --git a/libs/unimrcp/libs/uni-rtsp/include/rtsp_message.h b/libs/unimrcp/libs/uni-rtsp/include/rtsp_message.h
new file mode 100644 (file)
index 0000000..ae57237
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __RTSP_MESSAGE_H__
+#define __RTSP_MESSAGE_H__
+
+/**
+ * @file rtsp_message.h
+ * @brief RTSP Message Definition
+ */ 
+
+#include "rtsp_start_line.h"
+#include "rtsp_header.h"
+
+APT_BEGIN_EXTERN_C
+
+/** RTSP message declaration */
+typedef struct rtsp_message_t rtsp_message_t;
+
+/** RTSP message */
+struct rtsp_message_t {
+       /** RTSP mesage type (request/response) */
+       rtsp_start_line_t start_line;     
+       /** RTSP header */
+       rtsp_header_t     header;
+       /** RTSP message body */
+       apt_str_t         body;
+
+       /** Pool to allocate memory from */
+       apr_pool_t       *pool;
+};
+
+/** 
+ * Create RTSP message.
+ * @param message_type the message type
+ * @param pool the pool to allocate memory from
+ */
+RTSP_DECLARE(rtsp_message_t*) rtsp_message_create(rtsp_message_type_e message_type, apr_pool_t *pool);
+
+/** 
+ * Create RTSP request message.
+ * @param pool the pool to allocate memory from
+ */
+RTSP_DECLARE(rtsp_message_t*) rtsp_request_create(apr_pool_t *pool);
+
+/** 
+ * Create RTSP response message.
+ * @param request the request to create response to
+ * @param status_code the status code of the response
+ * @param reason the reason phrase id of the response
+ * @param pool the pool to allocate memory from
+ */
+RTSP_DECLARE(rtsp_message_t*) rtsp_response_create(const rtsp_message_t *request, rtsp_status_code_e status_code, rtsp_reason_phrase_e reason, apr_pool_t *pool);
+
+/** 
+ * Destroy RTSP message 
+ * @param message the message to destroy
+ */
+RTSP_DECLARE(void) rtsp_message_destroy(rtsp_message_t *message);
+
+APT_END_EXTERN_C
+
+#endif /*__RTSP_MESSAGE_H__*/
diff --git a/libs/unimrcp/libs/uni-rtsp/include/rtsp_server.h b/libs/unimrcp/libs/uni-rtsp/include/rtsp_server.h
new file mode 100644 (file)
index 0000000..bf57ce1
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __RTSP_SERVER_H__
+#define __RTSP_SERVER_H__
+
+/**
+ * @file rtsp_server.h
+ * @brief RTSP Server
+ */ 
+
+#include "apt_task.h"
+#include "rtsp_message.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque RTSP server declaration */
+typedef struct rtsp_server_t rtsp_server_t;
+/** Opaque RTSP server session declaration */
+typedef struct rtsp_server_session_t rtsp_server_session_t;
+
+/** RTSP server vtable declaration */
+typedef struct rtsp_server_vtable_t rtsp_server_vtable_t;
+
+/** RTSP server vtable declaration */
+struct rtsp_server_vtable_t {
+       /** Virtual create session */
+       apt_bool_t (*create_session)(rtsp_server_t *server, rtsp_server_session_t *session);
+       /** Virtual terminate session */
+       apt_bool_t (*terminate_session)(rtsp_server_t *server, rtsp_server_session_t *session);
+       /** Virtual message handler */
+       apt_bool_t (*handle_message)(rtsp_server_t *server, rtsp_server_session_t *session, rtsp_message_t *message);
+};
+
+/**
+ * Create RTSP server.
+ * @param listen_ip the listen IP address
+ * @param listen_port the listen port
+ * @param max_connection_count the number of max RTSP connections
+ * @param obj the external object to send events to
+ * @param handler the request handler
+ * @param pool the pool to allocate memory from
+ */
+RTSP_DECLARE(rtsp_server_t*) rtsp_server_create(
+                                                               const char *listen_ip, 
+                                                               apr_port_t listen_port, 
+                                                               apr_size_t max_connection_count,
+                                                               void *obj,
+                                                               const rtsp_server_vtable_t *handler,
+                                                               apr_pool_t *pool);
+
+/**
+ * Destroy RTSP server.
+ * @param server the server to destroy
+ */
+RTSP_DECLARE(apt_bool_t) rtsp_server_destroy(rtsp_server_t *server);
+
+/**
+ * Start server and wait for incoming requests.
+ * @param server the server to start
+ */
+RTSP_DECLARE(apt_bool_t) rtsp_server_start(rtsp_server_t *server);
+
+/**
+ * Terminate server.
+ * @param server the server to terminate
+ */
+RTSP_DECLARE(apt_bool_t) rtsp_server_terminate(rtsp_server_t *server);
+
+/**
+ * Get task.
+ * @param server the server to get task from
+ */
+RTSP_DECLARE(apt_task_t*) rtsp_server_task_get(rtsp_server_t *server);
+
+/**
+ * Get external object.
+ * @param server the server to get object from
+ */
+RTSP_DECLARE(void*) rtsp_server_object_get(rtsp_server_t *server);
+
+/**
+ * Send RTSP message.
+ * @param server the server to use
+ * @param session the session to send RTSP response for
+ * @param message the RTSP response to send
+ */
+RTSP_DECLARE(apt_bool_t) rtsp_server_session_respond(rtsp_server_t *server, rtsp_server_session_t *session, rtsp_message_t *message);
+
+/**
+ * Terminate RTSP session (respond to terminate request).
+ * @param server the server to use
+ * @param session the session to terminate
+ */
+RTSP_DECLARE(apt_bool_t) rtsp_server_session_terminate(rtsp_server_t *server, rtsp_server_session_t *session);
+
+/**
+ * Get object associated with the session.
+ * @param session the session to get object from
+ */
+RTSP_DECLARE(void*) rtsp_server_session_object_get(const rtsp_server_session_t *session);
+
+/**
+ * Set object associated with the session.
+ * @param session the session to set object for
+ * @param obj the object to set
+ */
+RTSP_DECLARE(void) rtsp_server_session_object_set(rtsp_server_session_t *session, void *obj);
+
+/**
+ * Get the session identifier.
+ * @param session the session to get identifier from
+ */
+RTSP_DECLARE(const apt_str_t*) rtsp_server_session_id_get(const rtsp_server_session_t *session);
+
+/**
+ * Get active (in-progress) session request.
+ * @param session the session to get from
+ */
+RTSP_DECLARE(const rtsp_message_t*) rtsp_server_session_request_get(const rtsp_server_session_t *session);
+
+/**
+ * Get the session destination (client) ip address.
+ * @param session the session to get ip address from
+ */
+RTSP_DECLARE(const char*) rtsp_server_session_destination_get(const rtsp_server_session_t *session);
+
+APT_END_EXTERN_C
+
+#endif /*__RTSP_SERVER_H__*/
diff --git a/libs/unimrcp/libs/uni-rtsp/include/rtsp_start_line.h b/libs/unimrcp/libs/uni-rtsp/include/rtsp_start_line.h
new file mode 100644 (file)
index 0000000..99b7388
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __RTSP_START_LINE_H__
+#define __RTSP_START_LINE_H__
+
+/**
+ * @file rtsp_start_line.h
+ * @brief RTSP Start Line (request-line/status-line)
+ */ 
+
+#include "rtsp.h"
+#include "apt_text_stream.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Protocol version */
+typedef enum {
+       /** Unknown version */
+       RTSP_VERSION_UNKNOWN = 0, 
+       /** RTSP 1.0 */
+       RTSP_VERSION_1 = 1, 
+} rtsp_version_e;
+
+/** RTSP message types */
+typedef enum {
+       RTSP_MESSAGE_TYPE_UNKNOWN,
+       RTSP_MESSAGE_TYPE_REQUEST,
+       RTSP_MESSAGE_TYPE_RESPONSE
+} rtsp_message_type_e;
+
+/** RTSP methods */
+typedef enum{
+       RTSP_METHOD_SETUP,
+       RTSP_METHOD_ANNOUNCE,
+       RTSP_METHOD_TEARDOWN,
+       RTSP_METHOD_DESCRIBE,
+
+       RTSP_METHOD_COUNT,
+       RTSP_METHOD_UNKNOWN = RTSP_METHOD_COUNT
+} rtsp_method_id;
+
+/** Status codes */
+typedef enum {
+       RTSP_STATUS_CODE_UNKNOWN                   = 0,
+       /** Success codes (2xx) */
+       RTSP_STATUS_CODE_OK                        = 200,
+       RTSP_STATUS_CODE_CREATED                   = 201,
+       /** Failure codec (4xx) */
+       RTSP_STATUS_CODE_BAD_REQUEST               = 400,
+       RTSP_STATUS_CODE_UNAUTHORIZED              = 401,
+       RTSP_STATUS_CODE_NOT_FOUND                 = 404,
+       RTSP_STATUS_CODE_METHOD_NOT_ALLOWED        = 405,
+       RTSP_STATUS_CODE_NOT_ACCEPTABLE            = 406,
+       RTSP_STATUS_CODE_SESSION_NOT_FOUND         = 454,
+
+       RTSP_STATUS_CODE_INTERNAL_SERVER_ERROR     = 500,
+       RTSP_STATUS_CODE_NOT_IMPLEMENTED           = 501,
+} rtsp_status_code_e;
+
+/** Reason phrases */
+typedef enum {
+       RTSP_REASON_PHRASE_OK,
+       RTSP_REASON_PHRASE_CREATED,
+       RTSP_REASON_PHRASE_BAD_REQUEST,
+       RTSP_REASON_PHRASE_UNAUTHORIZED,
+       RTSP_REASON_PHRASE_NOT_FOUND,
+       RTSP_REASON_PHRASE_METHOD_NOT_ALLOWED,
+       RTSP_REASON_PHRASE_NOT_ACCEPTABLE,
+       RTSP_REASON_PHRASE_SESSION_NOT_FOUND,
+       RTSP_REASON_PHRASE_INTERNAL_SERVER_ERROR,
+       RTSP_REASON_PHRASE_NOT_IMPLEMENTED,
+       RTSP_REASON_PHRASE_COUNT,
+
+       /** Unknown reason phrase */
+       RTSP_REASON_PHRASE_UNKNOWN = RTSP_REASON_PHRASE_COUNT
+} rtsp_reason_phrase_e;
+
+
+/** RTSP request-line declaration */
+typedef struct rtsp_request_line_t rtsp_request_line_t;
+/** RTSP status-line declaration */
+typedef struct rtsp_status_line_t rtsp_status_line_t;
+/** RTSP start-line declaration */
+typedef struct rtsp_start_line_t rtsp_start_line_t;
+
+/** RTSP request-line */
+struct rtsp_request_line_t {
+       /** Method name */
+       apt_str_t      method_name;
+       /** Method id */
+       rtsp_method_id method_id;
+       /** RTSP URL */
+       apt_str_t      url;
+       /** Resource name parsed from RTSP URL */
+       const char    *resource_name;
+       /** Version of protocol in use */
+       rtsp_version_e version;
+};
+
+/** RTSP status-line */
+struct rtsp_status_line_t {
+       /** Version of protocol in use */
+       rtsp_version_e     version;
+       /** success or failure or other status of the request */
+       rtsp_status_code_e status_code;
+       /** Reason phrase */
+       apt_str_t          reason;
+};
+
+/** RTSP start-line */
+struct rtsp_start_line_t {
+       /** RTSP message type */
+       rtsp_message_type_e     message_type;
+       /** RTSP start-line */
+       union {
+               rtsp_request_line_t request_line;
+               rtsp_status_line_t  status_line;
+       } common;
+};
+
+
+static APR_INLINE void rtsp_request_line_init(rtsp_request_line_t *request_line)
+{
+       apt_string_reset(&request_line->method_name);
+       request_line->method_id = RTSP_METHOD_UNKNOWN;
+       apt_string_reset(&request_line->url);
+       request_line->resource_name = NULL;
+       request_line->version = RTSP_VERSION_1;
+}
+
+static APR_INLINE void rtsp_status_line_init(rtsp_status_line_t *status_line)
+{
+       status_line->version = RTSP_VERSION_1;
+       status_line->status_code = RTSP_STATUS_CODE_OK;
+       apt_string_reset(&status_line->reason);
+}
+
+/** Initialize RTSP start-line */
+static APR_INLINE void rtsp_start_line_init(rtsp_start_line_t *start_line, rtsp_message_type_e message_type)
+{
+       start_line->message_type = message_type;
+       if(message_type == RTSP_MESSAGE_TYPE_REQUEST) {
+               rtsp_request_line_init(&start_line->common.request_line);
+       }
+       else if(message_type == RTSP_MESSAGE_TYPE_RESPONSE) {
+               rtsp_status_line_init(&start_line->common.status_line);
+       }
+}
+
+/** Parse RTSP start-line */
+RTSP_DECLARE(apt_bool_t) rtsp_start_line_parse(rtsp_start_line_t *start_line, apt_text_stream_t *text_stream, apr_pool_t *pool);
+
+/** Generate RTSP start-line */
+RTSP_DECLARE(apt_bool_t) rtsp_start_line_generate(rtsp_start_line_t *start_line, apt_text_stream_t *text_stream);
+
+/** Get reason phrase by status code */
+RTSP_DECLARE(const apt_str_t*) rtsp_reason_phrase_get(rtsp_reason_phrase_e reason);
+
+APT_END_EXTERN_C
+
+#endif /*__RTSP_START_LINE_H__*/
diff --git a/libs/unimrcp/libs/uni-rtsp/include/rtsp_stream.h b/libs/unimrcp/libs/uni-rtsp/include/rtsp_stream.h
new file mode 100644 (file)
index 0000000..343c1f9
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __RTSP_STREAM_H__
+#define __RTSP_STREAM_H__
+
+/**
+ * @file rtsp_stream.h
+ * @brief RTSP Stream Parser and Generator
+ */ 
+
+#include "rtsp_message.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Result of RTSP stream processing (parse/generate) */
+typedef enum {
+       RTSP_STREAM_MESSAGE_COMPLETE,
+       RTSP_STREAM_MESSAGE_TRUNCATED,
+       RTSP_STREAM_MESSAGE_INVALID
+} rtsp_stream_result_e;
+
+/** Opaque RTSP parser declaration */
+typedef struct rtsp_parser_t rtsp_parser_t;
+/** Opaque RTSP generator declaration */
+typedef struct rtsp_generator_t rtsp_generator_t;
+
+/** RTSP message handler */
+typedef apt_bool_t (*rtsp_message_handler_f)(void *obj, rtsp_message_t *message, rtsp_stream_result_e result);
+
+/** Create RTSP stream parser */
+RTSP_DECLARE(rtsp_parser_t*) rtsp_parser_create(apr_pool_t *pool);
+
+/** Parse RTSP stream */
+RTSP_DECLARE(rtsp_stream_result_e) rtsp_parser_run(rtsp_parser_t *parser, apt_text_stream_t *stream);
+
+/** Get parsed RTSP message */
+RTSP_DECLARE(rtsp_message_t*) rtsp_parser_message_get(const rtsp_parser_t *parser);
+
+
+/** Create RTSP stream generator */
+RTSP_DECLARE(rtsp_generator_t*) rtsp_generator_create(apr_pool_t *pool);
+
+/** Set RTSP message to generate */
+RTSP_DECLARE(apt_bool_t) rtsp_generator_message_set(rtsp_generator_t *generator, rtsp_message_t *message);
+
+/** Generate RTSP stream */
+RTSP_DECLARE(rtsp_stream_result_e) rtsp_generator_run(rtsp_generator_t *generator, apt_text_stream_t *stream);
+
+
+/** Walk through RTSP stream and call message handler for each parsed message */
+RTSP_DECLARE(apt_bool_t) rtsp_stream_walk(rtsp_parser_t *parser, apt_text_stream_t *stream, rtsp_message_handler_f handler, void *obj);
+
+APT_END_EXTERN_C
+
+#endif /*__RTSP_STREAM_H__*/
diff --git a/libs/unimrcp/libs/uni-rtsp/src/rtsp_client.c b/libs/unimrcp/libs/uni-rtsp/src/rtsp_client.c
new file mode 100644 (file)
index 0000000..825e1f3
--- /dev/null
@@ -0,0 +1,824 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_hash.h>
+#include "rtsp_client.h"
+#include "rtsp_stream.h"
+#include "apt_net_client_task.h"
+#include "apt_text_stream.h"
+#include "apt_pool.h"
+#include "apt_obj_list.h"
+#include "apt_log.h"
+
+#define RTSP_STREAM_BUFFER_SIZE 1024
+
+typedef struct rtsp_client_connection_t rtsp_client_connection_t;
+
+typedef enum {
+       TERMINATION_STATE_NONE,
+       TERMINATION_STATE_REQUESTED,
+       TERMINATION_STATE_INPROGRESS
+} termination_state_e;
+
+/** RTSP client */
+struct rtsp_client_t {
+       apr_pool_t                 *pool;
+       apt_net_client_task_t      *task;
+
+       apr_pool_t                 *sub_pool;
+       apt_obj_list_t             *connection_list;
+
+       void                       *obj;
+       const rtsp_client_vtable_t *vtable;
+};
+
+/** RTSP connection */
+struct rtsp_client_connection_t {
+       /** Connection base */
+       apt_net_client_connection_t *base;
+       /** RTSP client, connection belongs to */
+       rtsp_client_t               *client;
+       /** Element of the connection list in agent */
+       apt_list_elem_t             *it;
+
+       /** Handle table (rtsp_client_session_t*) */
+       apr_hash_t                  *handle_table;
+       /** Session table (rtsp_client_session_t*) */
+       apr_hash_t                  *session_table;
+       
+       /** Inprogress request/session queue (rtsp_client_session_t*) */
+       apt_obj_list_t              *inprogress_request_queue;
+
+       /** Last CSeq sent */
+       apr_size_t                   last_cseq;
+
+       char                         rx_buffer[RTSP_STREAM_BUFFER_SIZE];
+       apt_text_stream_t            rx_stream;
+       rtsp_parser_t               *parser;
+
+       char                         tx_buffer[RTSP_STREAM_BUFFER_SIZE];
+       apt_text_stream_t            tx_stream;
+       rtsp_generator_t            *generator;
+};
+
+/** RTSP session */
+struct rtsp_client_session_t {
+       apr_pool_t               *pool;
+       void                     *obj;
+       
+       /** Connection */
+       rtsp_client_connection_t *connection;
+       /** Session identifier */
+       apt_str_t                 id;
+
+       apt_str_t                 server_ip;
+       apr_port_t                server_port;
+       apt_str_t                 resource_location;
+
+       /** In-progress request */
+       rtsp_message_t           *active_request;
+       /** Pending request queue (rtsp_message_t*) */
+       apt_obj_list_t           *pending_request_queue;
+
+       /** Resource table */
+       apr_hash_t               *resource_table;
+
+       /** termination state (none -> requested -> terminating) */
+       termination_state_e       term_state;
+};
+
+typedef enum {
+       TASK_MSG_SEND_MESSAGE,
+       TASK_MSG_TERMINATE_SESSION
+} task_msg_data_type_e;
+
+typedef struct task_msg_data_t task_msg_data_t;
+
+struct task_msg_data_t {
+       task_msg_data_type_e   type;
+       rtsp_client_t         *client;
+       rtsp_client_session_t *session;
+       rtsp_message_t        *message;
+};
+
+static apt_bool_t rtsp_client_task_msg_process(apt_task_t *task, apt_task_msg_t *msg);
+
+static apt_bool_t rtsp_client_message_receive(apt_net_client_task_t *task, apt_net_client_connection_t *connection);
+
+static const apt_net_client_vtable_t client_vtable = {
+       rtsp_client_message_receive
+};
+
+static apt_bool_t rtsp_client_message_send(rtsp_client_t *client, apt_net_client_connection_t *connection, rtsp_message_t *message);
+static apt_bool_t rtsp_client_session_message_process(rtsp_client_t *client, rtsp_client_session_t *session, rtsp_message_t *message);
+static apt_bool_t rtsp_client_session_request_process(rtsp_client_t *client, rtsp_client_session_t *session, rtsp_message_t *message);
+static apt_bool_t rtsp_client_session_response_process(rtsp_client_t *client, rtsp_client_session_t *session, rtsp_message_t *request, rtsp_message_t *response);
+
+/** Create RTSP client */
+RTSP_DECLARE(rtsp_client_t*) rtsp_client_create(
+                                                                               apr_size_t max_connection_count,
+                                                                               void *obj,
+                                                                               const rtsp_client_vtable_t *handler,
+                                                                               apr_pool_t *pool)
+{
+       apt_task_vtable_t *vtable;
+       apt_task_msg_pool_t *msg_pool;
+       rtsp_client_t *client;
+       
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Create RTSP Client [%d]",max_connection_count);
+       client = apr_palloc(pool,sizeof(rtsp_client_t));
+       client->pool = pool;
+       client->obj = obj;
+       client->vtable = handler;
+
+       msg_pool = apt_task_msg_pool_create_dynamic(sizeof(task_msg_data_t),pool);
+
+       client->task = apt_net_client_task_create(max_connection_count,client,&client_vtable,msg_pool,pool);
+       if(!client->task) {
+               return NULL;
+       }
+
+       vtable = apt_net_client_task_vtable_get(client->task);
+       if(vtable) {
+               vtable->process_msg = rtsp_client_task_msg_process;
+       }
+
+       client->sub_pool = apt_subpool_create(pool);
+       client->connection_list = NULL;
+       return client;
+}
+
+/** Destroy RTSP client */
+RTSP_DECLARE(apt_bool_t) rtsp_client_destroy(rtsp_client_t *client)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Destroy RTSP Client");
+       return apt_net_client_task_destroy(client->task);
+}
+
+/** Start connection agent */
+RTSP_DECLARE(apt_bool_t) rtsp_client_start(rtsp_client_t *client)
+{
+       return apt_net_client_task_start(client->task);
+}
+
+/** Terminate connection agent */
+RTSP_DECLARE(apt_bool_t) rtsp_client_terminate(rtsp_client_t *client)
+{
+       return apt_net_client_task_terminate(client->task);
+}
+
+/** Get task */
+RTSP_DECLARE(apt_task_t*) rtsp_client_task_get(rtsp_client_t *client)
+{
+       return apt_net_client_task_base_get(client->task);
+}
+
+/** Get external object */
+RTSP_DECLARE(void*) rtsp_client_object_get(rtsp_client_t *client)
+{
+       return client->obj;
+}
+
+/** Get object associated with the session */
+RTSP_DECLARE(void*) rtsp_client_session_object_get(const rtsp_client_session_t *session)
+{
+       return session->obj;
+}
+
+/** Set object associated with the session */
+RTSP_DECLARE(void) rtsp_client_session_object_set(rtsp_client_session_t *session, void *obj)
+{
+       session->obj = obj;
+}
+
+/** Get the session identifier */
+RTSP_DECLARE(const apt_str_t*) rtsp_client_session_id_get(const rtsp_client_session_t *session)
+{
+       return &session->id;
+}
+
+/** Signal task message */
+static apt_bool_t rtsp_client_control_message_signal(
+                                                               task_msg_data_type_e type,
+                                                               rtsp_client_t *client,
+                                                               rtsp_client_session_t *session,
+                                                               rtsp_message_t *message)
+{
+       apt_task_t *task = apt_net_client_task_base_get(client->task);
+       apt_task_msg_t *task_msg = apt_task_msg_get(task);
+       if(task_msg) {
+               task_msg_data_t *data = (task_msg_data_t*)task_msg->data;
+               data->type = type;
+               data->client = client;
+               data->session = session;
+               data->message = message;
+               apt_task_msg_signal(task,task_msg);
+       }
+       return TRUE;
+}
+
+/** Create RTSP session handle */
+RTSP_DECLARE(rtsp_client_session_t*) rtsp_client_session_create(
+                                                                                       rtsp_client_t *client,
+                                                                                       const char *server_ip, 
+                                                                                       apr_port_t server_port,
+                                                                                       const char *resource_location)
+{
+       rtsp_client_session_t *session;
+       apr_pool_t *pool = apt_pool_create();
+       session = apr_palloc(pool,sizeof(rtsp_client_session_t));
+       session->pool = pool;
+       session->obj = NULL;
+       session->connection = NULL;
+       session->active_request = NULL;
+       session->pending_request_queue = apt_list_create(pool);
+       session->resource_table = apr_hash_make(pool);
+       session->term_state = TERMINATION_STATE_NONE;
+
+       apt_string_assign(&session->server_ip,server_ip,pool);
+       session->server_port = server_port;
+       apt_string_assign(&session->resource_location,resource_location,pool);
+       apt_string_reset(&session->id);
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create RTSP Handle "APT_PTR_FMT,session);
+       return session;
+}
+
+/** Destroy RTSP session handle */
+RTSP_DECLARE(void) rtsp_client_session_destroy(rtsp_client_session_t *session)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy RTSP Handle "APT_PTR_FMT,session);
+       if(session && session->pool) {
+               apr_pool_destroy(session->pool);
+       }
+}
+
+/** Signal terminate request */
+RTSP_DECLARE(apt_bool_t) rtsp_client_session_terminate(rtsp_client_t *client, rtsp_client_session_t *session)
+{
+       return rtsp_client_control_message_signal(TASK_MSG_TERMINATE_SESSION,client,session,NULL);
+}
+
+/** Signal RTSP message */
+RTSP_DECLARE(apt_bool_t) rtsp_client_session_request(rtsp_client_t *client, rtsp_client_session_t *session, rtsp_message_t *message)
+{
+       return rtsp_client_control_message_signal(TASK_MSG_SEND_MESSAGE,client,session,message);
+}
+
+/* Create RTSP connection */
+static apt_bool_t rtsp_client_connection_create(rtsp_client_t *client, rtsp_client_session_t *session)
+{
+       rtsp_client_connection_t *rtsp_connection;
+       apt_net_client_connection_t *connection = apt_net_client_connect(client->task,session->server_ip.buf,session->server_port);
+       if(!connection) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Connect to RTSP Server %s:%d",session->server_ip.buf,session->server_port);
+               return FALSE;
+       }
+       rtsp_connection = apr_palloc(connection->pool,sizeof(rtsp_client_connection_t));
+       rtsp_connection->handle_table = apr_hash_make(connection->pool);
+       rtsp_connection->session_table = apr_hash_make(connection->pool);
+       rtsp_connection->inprogress_request_queue = apt_list_create(connection->pool);
+       apt_text_stream_init(&rtsp_connection->rx_stream,rtsp_connection->rx_buffer,sizeof(rtsp_connection->rx_buffer)-1);
+       apt_text_stream_init(&rtsp_connection->tx_stream,rtsp_connection->tx_buffer,sizeof(rtsp_connection->tx_buffer)-1);
+       rtsp_connection->parser = rtsp_parser_create(connection->pool);
+       rtsp_connection->generator = rtsp_generator_create(connection->pool);
+       rtsp_connection->last_cseq = 0;
+       rtsp_connection->base = connection;
+       connection->obj = rtsp_connection;
+       if(!client->connection_list) {
+               client->connection_list = apt_list_create(client->sub_pool);
+       }
+       rtsp_connection->client = client;
+       rtsp_connection->it = apt_list_push_back(client->connection_list,rtsp_connection,connection->pool);
+       session->connection = rtsp_connection;
+       return TRUE;
+}
+
+/* Destroy RTSP connection */
+static apt_bool_t rtsp_client_connection_destroy(rtsp_client_t *client, rtsp_client_connection_t *rtsp_connection)
+{
+       apt_list_elem_remove(client->connection_list,rtsp_connection->it);
+       apt_net_client_disconnect(client->task,rtsp_connection->base);
+
+       if(apt_list_is_empty(client->connection_list) == TRUE) {
+               apr_pool_clear(client->sub_pool);
+               client->connection_list = NULL;
+       }
+       return TRUE;
+}
+
+/* Respond to session termination request */
+static apt_bool_t rtsp_client_session_terminate_respond(rtsp_client_t *client, rtsp_client_session_t *session)
+{
+       rtsp_client_connection_t *rtsp_connection = session->connection;
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remove RTSP Handle "APT_PTR_FMT,session);
+       apr_hash_set(rtsp_connection->handle_table,session,sizeof(session),NULL);
+
+       session->term_state = TERMINATION_STATE_NONE;
+       client->vtable->on_session_terminate_response(client,session);
+       
+       if(apr_hash_count(rtsp_connection->handle_table) == 0) {
+               rtsp_client_connection_destroy(client,rtsp_connection);
+       }
+       return TRUE;
+}
+
+/* Teardown session resources */
+static apt_bool_t rtsp_client_session_resources_teardown(rtsp_client_t *client, rtsp_client_session_t *session)
+{
+       void *val;
+       rtsp_message_t *setup_request;
+       rtsp_message_t *teardown_request;
+       apr_hash_index_t *it;
+
+       /* set termination state to in-progress and teardown remaining resources */
+       session->term_state = TERMINATION_STATE_INPROGRESS;
+       it = apr_hash_first(session->pool,session->resource_table);
+       for(; it; it = apr_hash_next(it)) {
+               apr_hash_this(it,NULL,NULL,&val);
+               setup_request = val;
+               if(!setup_request) continue;
+
+               teardown_request = rtsp_request_create(session->pool);
+               teardown_request->start_line.common.request_line.resource_name = setup_request->start_line.common.request_line.resource_name;
+               teardown_request->start_line.common.request_line.method_id = RTSP_METHOD_TEARDOWN;
+               rtsp_client_session_message_process(client,session,teardown_request);
+       }
+       return TRUE;
+}
+
+/* Process session termination request */
+static apt_bool_t rtsp_client_session_terminate_process(rtsp_client_t *client, rtsp_client_session_t *session)
+{
+       rtsp_client_connection_t *rtsp_connection = session->connection;
+       if(!rtsp_connection) {
+               client->vtable->on_session_terminate_response(client,session);
+               return FALSE;
+       }
+
+       if(session->active_request) {
+               /* set termination state to requested */
+               session->term_state = TERMINATION_STATE_REQUESTED;
+       }
+       else {
+               rtsp_client_session_resources_teardown(client,session);
+               
+               /* respond immediately if no resources left */
+               if(apr_hash_count(session->resource_table) == 0) {
+                       rtsp_client_session_terminate_respond(client,session);
+               }
+       }
+
+       return TRUE;
+}
+
+static apt_bool_t rtsp_client_session_url_generate(rtsp_client_session_t *session, rtsp_message_t *message)
+{
+       apt_str_t *url = &message->start_line.common.request_line.url;
+       if(session->resource_location.length) {
+               url->buf = apr_psprintf(message->pool,"rtsp://%s:%d/%s/%s",
+                                               session->server_ip.buf,
+                                               session->server_port,
+                                               session->resource_location.buf,
+                                               message->start_line.common.request_line.resource_name);
+       }
+       else {
+               url->buf = apr_psprintf(message->pool,"rtsp://%s:%d/%s",
+                                               session->server_ip.buf,
+                                               session->server_port,
+                                               message->start_line.common.request_line.resource_name);
+       }
+       url->length = strlen(url->buf);
+       return TRUE;
+}
+
+static apt_bool_t rtsp_client_request_push(rtsp_client_connection_t *rtsp_connection, rtsp_client_session_t *session, rtsp_message_t *message)
+{
+       /* add request to inprogress request queue */
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Push RTSP Request to In-Progress Queue "APT_PTRSID_FMT" CSeq:%d",
+               session,
+               message->header.session_id.buf ? message->header.session_id.buf : "new",
+               message->header.cseq);
+       apt_list_push_back(rtsp_connection->inprogress_request_queue,session,session->pool);
+       session->active_request = message;
+       return TRUE;
+}
+
+static apt_bool_t rtsp_client_request_pop(rtsp_client_connection_t *rtsp_connection, rtsp_message_t *response, rtsp_message_t **ret_request, rtsp_client_session_t **ret_session)
+{
+       rtsp_client_session_t *session;
+       apt_list_elem_t *elem = apt_list_first_elem_get(rtsp_connection->inprogress_request_queue);
+       while(elem) {
+               session = apt_list_elem_object_get(elem);
+               if(session->active_request && session->active_request->header.cseq == response->header.cseq) {
+                       if(ret_session) {
+                               *ret_session = session;
+                       }
+                       if(ret_request) {
+                               *ret_request = session->active_request;
+                       }
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Pop In-Progress RTSP Request "APT_PTR_FMT" CSeq:%d", 
+                               session, 
+                               response->header.cseq);
+                       apt_list_elem_remove(rtsp_connection->inprogress_request_queue,elem);
+                       session->active_request = NULL;
+                       return TRUE;
+               }
+               elem = apt_list_next_elem_get(rtsp_connection->inprogress_request_queue,elem);
+       }
+       return FALSE;
+}
+
+/* Process outgoing RTSP request */
+static apt_bool_t rtsp_client_session_request_process(rtsp_client_t *client, rtsp_client_session_t *session, rtsp_message_t *message)
+{
+       if(!session->connection) {
+               /* create RTSP connection */
+               if(rtsp_client_connection_create(client,session) == FALSE) {
+                       /* respond with error */
+                       return FALSE;
+               }
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Add RTSP Handle "APT_PTR_FMT,session);
+               apr_hash_set(session->connection->handle_table,session,sizeof(session),session);
+       }
+
+       rtsp_client_session_url_generate(session,message);
+
+       if(session->id.length) {
+               message->header.session_id = session->id;
+               rtsp_header_property_add(&message->header.property_set,RTSP_HEADER_FIELD_SESSION_ID);
+       }
+       
+       message->header.cseq = ++session->connection->last_cseq;
+       rtsp_header_property_add(&message->header.property_set,RTSP_HEADER_FIELD_CSEQ);
+
+       if(rtsp_client_message_send(client,session->connection->base,message) == FALSE) {
+               /* respond with error */
+               return FALSE;
+       }
+
+       return rtsp_client_request_push(session->connection,session,message);
+}
+
+/* Process pending RTSP requests */
+static apt_bool_t rtsp_client_session_pending_requests_process(rtsp_client_t *client, rtsp_client_session_t *session)
+{
+       rtsp_message_t *request = apt_list_pop_front(session->pending_request_queue);
+       if(!request) {
+               /* pending queue is empty, no in-progress request */
+               return FALSE;
+       }
+
+       /* process pending request; get the next one, if current is failed */
+       do {
+               rtsp_message_t *response;
+               if(rtsp_client_session_request_process(client,session,request) == TRUE) {
+                       return TRUE;
+               }
+                       
+               /* respond with error */
+               response = rtsp_response_create(
+                                                       request,
+                                                       RTSP_STATUS_CODE_INTERNAL_SERVER_ERROR,
+                                                       RTSP_REASON_PHRASE_INTERNAL_SERVER_ERROR,
+                                                       session->pool);
+               rtsp_client_session_response_process(client,session,request,response);
+               
+               /* process the next pending request / if any */
+               request = apt_list_pop_front(session->pending_request_queue);
+       }
+       while(request);
+
+       /* no in-progress request */
+       return FALSE;
+}
+
+
+/* Process outgoing RTSP message */
+static apt_bool_t rtsp_client_session_message_process(rtsp_client_t *client, rtsp_client_session_t *session, rtsp_message_t *message)
+{
+       if(session->active_request) {
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Push RTSP Request to Pending Queue "APT_PTR_FMT,session);
+               apt_list_push_back(session->pending_request_queue,message,message->pool);
+               return TRUE;
+       }
+
+       if(rtsp_client_session_request_process(client,session,message) == FALSE) {
+               /* respond with error in case request cannot be processed */
+               rtsp_message_t *response = rtsp_response_create(
+                                                       message,
+                                                       RTSP_STATUS_CODE_INTERNAL_SERVER_ERROR,
+                                                       RTSP_REASON_PHRASE_INTERNAL_SERVER_ERROR,
+                                                       session->pool);
+               rtsp_client_session_response_process(client,session,message,response);
+       }
+       return TRUE;
+}
+
+/* Process incoming RTSP event (request) */
+static apt_bool_t rtsp_client_session_event_process(rtsp_client_t *client, rtsp_client_connection_t *rtsp_connection, rtsp_message_t *message)
+{
+       rtsp_message_t *response = NULL;
+       rtsp_client_session_t *session = NULL;
+       if(rtsp_header_property_check(&message->header.property_set,RTSP_HEADER_FIELD_SESSION_ID) == TRUE) {
+               /* find existing session */
+               session = apr_hash_get(
+                                       rtsp_connection->session_table,
+                                       message->header.session_id.buf,
+                                       message->header.session_id.length);
+       }
+
+       if(session) {
+               response = rtsp_response_create(message,RTSP_STATUS_CODE_OK,RTSP_REASON_PHRASE_OK,message->pool);
+               if(rtsp_header_property_check(&message->header.property_set,RTSP_HEADER_FIELD_SESSION_ID) == TRUE) {
+                       response->header.session_id = message->header.session_id;
+                       rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_SESSION_ID);
+               }
+               client->vtable->on_session_event(client,session,message);
+       }
+       else {
+               response = rtsp_response_create(message,RTSP_STATUS_CODE_NOT_FOUND,RTSP_REASON_PHRASE_NOT_FOUND,message->pool);
+       }
+
+       return rtsp_client_message_send(client,rtsp_connection->base,response);
+}
+
+/* Process incoming RTSP response */
+static apt_bool_t rtsp_client_session_response_process(rtsp_client_t *client, rtsp_client_session_t *session, rtsp_message_t *request, rtsp_message_t *response)
+{
+       const char *resource_name;
+       if(request->start_line.common.request_line.method_id == RTSP_METHOD_SETUP &&
+               response->start_line.common.status_line.status_code == RTSP_STATUS_CODE_OK) {
+               
+               if(apr_hash_count(session->resource_table) == 0) {
+                       if(rtsp_header_property_check(&response->header.property_set,RTSP_HEADER_FIELD_SESSION_ID) == TRUE) {
+                               session->id = response->header.session_id;
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Add RTSP Session "APT_PTRSID_FMT,
+                                       session,
+                                       session->id.buf);
+                               apr_hash_set(session->connection->session_table,session->id.buf,session->id.length,session);
+                       }
+               }
+               
+               /* add resource */
+               resource_name = request->start_line.common.request_line.resource_name;
+               apr_hash_set(session->resource_table,resource_name,APR_HASH_KEY_STRING,request);
+       }
+       else if(request->start_line.common.request_line.method_id == RTSP_METHOD_TEARDOWN) {
+               /* remove resource */
+               resource_name = request->start_line.common.request_line.resource_name;
+               apr_hash_set(session->resource_table,resource_name,APR_HASH_KEY_STRING,NULL);
+
+               if(apr_hash_count(session->resource_table) == 0) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remove RTSP Session "APT_PTRSID_FMT,
+                               session,
+                               session->id.buf);
+                       apr_hash_set(session->connection->session_table,session->id.buf,session->id.length,NULL);
+               }
+       }
+
+       if(session->term_state != TERMINATION_STATE_INPROGRESS) {
+               client->vtable->on_session_response(client,session,request,response);
+       }
+
+       return TRUE;
+}
+
+/* Raise RTSP session terminate event */
+static apt_bool_t rtsp_client_session_terminate_raise(rtsp_client_t *client, rtsp_client_session_t *session)
+{
+       rtsp_message_t *request;
+       rtsp_message_t *response;
+
+       /* cancel pending requests */
+       do {
+               request = apt_list_pop_front(session->pending_request_queue);
+               if(request) {
+                       response = rtsp_response_create(
+                                                       session->active_request,
+                                                       RTSP_STATUS_CODE_INTERNAL_SERVER_ERROR,
+                                                       RTSP_REASON_PHRASE_INTERNAL_SERVER_ERROR,
+                                                       session->pool);
+                       rtsp_client_session_response_process(client,session,request,response);
+               }
+       }
+       while(request);
+
+       
+       if(session->term_state == TERMINATION_STATE_NONE) {
+               client->vtable->on_session_terminate_event(client,session);
+       }
+       else {
+               rtsp_client_session_terminate_respond(client,session);
+       }
+       return TRUE;
+}
+
+/* RTSP connection disconnected */
+static apt_bool_t rtsp_client_on_disconnect(rtsp_client_t *client, rtsp_client_connection_t *rtsp_connection)
+{
+       rtsp_client_session_t *session;
+       rtsp_message_t *request;
+       rtsp_message_t *response;
+       apr_size_t remaining_handles = 0;
+       apr_size_t cancelled_requests = 0;
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"TCP Peer Disconnected %s", rtsp_connection->base->id);
+       apt_net_client_connection_close(client->task,rtsp_connection->base);
+
+       /* Cancel in-progreess requests */
+       do {
+               session = apt_list_pop_front(rtsp_connection->inprogress_request_queue);
+               if(session && session->active_request) {
+                       request = session->active_request;
+                       session->active_request = NULL;
+                       cancelled_requests++;
+
+                       response = rtsp_response_create(
+                                                               request,
+                                                               RTSP_STATUS_CODE_INTERNAL_SERVER_ERROR,
+                                                               RTSP_REASON_PHRASE_INTERNAL_SERVER_ERROR,
+                                                               session->pool);
+                       rtsp_client_session_response_process(client,session,request,response);
+               }
+       }
+       while(session);
+
+       /* Walk through RTSP handles and raise termination event for them */
+       remaining_handles = apr_hash_count(rtsp_connection->handle_table);
+       if(remaining_handles) {
+               void *val;
+               apr_hash_index_t *it;
+               apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Terminate Remaining RTSP Handles [%d]",remaining_handles);
+               it = apr_hash_first(rtsp_connection->base->pool,rtsp_connection->session_table);
+               for(; it; it = apr_hash_next(it)) {
+                       apr_hash_this(it,NULL,NULL,&val);
+                       session = val;
+                       if(session) {
+                               rtsp_client_session_terminate_raise(client,session);
+                       }
+               }
+               remaining_handles = apr_hash_count(rtsp_connection->session_table);
+       }
+
+       if(!remaining_handles && !cancelled_requests) {
+               rtsp_client_connection_destroy(client,rtsp_connection);
+       }
+       return TRUE;
+}
+
+/* Send RTSP message through RTSP connection */
+static apt_bool_t rtsp_client_message_send(rtsp_client_t *client, apt_net_client_connection_t *connection, rtsp_message_t *message)
+{
+       apt_bool_t status = FALSE;
+       rtsp_client_connection_t *rtsp_connection;
+       apt_text_stream_t *stream;
+       rtsp_stream_result_e result;
+
+       if(!connection || !connection->sock) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No RTSP Connection");
+               return FALSE;
+       }
+       rtsp_connection = connection->obj;
+       stream = &rtsp_connection->tx_stream;
+               
+       rtsp_generator_message_set(rtsp_connection->generator,message);
+       do {
+               stream->text.length = sizeof(rtsp_connection->tx_buffer)-1;
+               stream->pos = stream->text.buf;
+               result = rtsp_generator_run(rtsp_connection->generator,stream);
+               if(result == RTSP_STREAM_MESSAGE_COMPLETE || result == RTSP_STREAM_MESSAGE_TRUNCATED) {
+                       stream->text.length = stream->pos - stream->text.buf;
+                       *stream->pos = '\0';
+
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Send RTSP Stream %s [%lu bytes]\n%s",
+                               connection->id,
+                               stream->text.length,
+                               stream->text.buf);
+                       if(apr_socket_send(connection->sock,stream->text.buf,&stream->text.length) == APR_SUCCESS) {
+                               status = TRUE;
+                       }
+                       else {
+                               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Send RTSP Stream");
+                       }
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Generate RTSP Stream");
+               }
+       }
+       while(result == RTSP_STREAM_MESSAGE_TRUNCATED);
+
+       return status;
+}
+
+static apt_bool_t rtsp_client_message_handler(void *obj, rtsp_message_t *message, rtsp_stream_result_e result)
+{
+       rtsp_client_connection_t *rtsp_connection = obj;
+       if(result != RTSP_STREAM_MESSAGE_COMPLETE) {
+               /* message is not completely parsed, nothing to do */
+               return TRUE;
+       }
+       /* process parsed message */
+       if(message->start_line.message_type == RTSP_MESSAGE_TYPE_RESPONSE) {
+               rtsp_message_t *request;
+               rtsp_client_session_t *session;
+               /* at first, pop in-progress request/session */
+               if(rtsp_client_request_pop(rtsp_connection,message,&request,&session) == FALSE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unexpected RTSP Response Received CSeq:%d",message->header.cseq);
+                       return FALSE;
+               }
+
+               /* next, process session response */
+               rtsp_client_session_response_process(rtsp_connection->client,session,request,message);
+
+               /* process session pending requests */
+               if(rtsp_client_session_pending_requests_process(rtsp_connection->client,session) == FALSE) {
+                       /* no in-progress request, check the termination state now */
+                       if(session->term_state != TERMINATION_STATE_NONE) {
+                               if(session->term_state == TERMINATION_STATE_REQUESTED) {
+                                       rtsp_client_session_resources_teardown(rtsp_connection->client,session);
+                               }
+                               
+                               /* respond if no resources left */
+                               if(apr_hash_count(session->resource_table) == 0) {
+                                       rtsp_client_session_terminate_respond(rtsp_connection->client,session);
+                               }
+                       }
+               }
+       }
+       else if(message->start_line.message_type == RTSP_MESSAGE_TYPE_REQUEST) {
+               rtsp_client_session_event_process(rtsp_connection->client,rtsp_connection,message);
+       }
+       return TRUE;
+}
+
+/* Receive RTSP message through RTSP connection */
+static apt_bool_t rtsp_client_message_receive(apt_net_client_task_t *task, apt_net_client_connection_t *connection)
+{
+       rtsp_client_t *client = apt_net_client_task_object_get(task);
+       rtsp_client_connection_t *rtsp_connection;
+       apr_status_t status;
+       apr_size_t offset;
+       apr_size_t length;
+       apt_text_stream_t *stream;
+
+       if(!connection || !connection->sock) {
+               return FALSE;
+       }
+       rtsp_connection = connection->obj;
+       stream = &rtsp_connection->rx_stream;
+
+       /* init length of the stream */
+       stream->text.length = sizeof(rtsp_connection->rx_buffer)-1;
+       /* calculate offset remaining from the previous receive / if any */
+       offset = stream->pos - stream->text.buf;
+       /* calculate available length */
+       length = stream->text.length - offset;
+       status = apr_socket_recv(connection->sock,stream->pos,&length);
+       if(status == APR_EOF || length == 0) {
+               return rtsp_client_on_disconnect(client,rtsp_connection);
+       }
+       /* calculate actual length of the stream */
+       stream->text.length = offset + length;
+       stream->pos[length] = '\0';
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive RTSP Stream %s [%lu bytes]\n%s",
+               connection->id,
+               length,
+               stream->pos);
+
+       /* reset pos */
+       stream->pos = stream->text.buf;
+       /* walk through the stream parsing RTSP messages */
+       return rtsp_stream_walk(rtsp_connection->parser,stream,rtsp_client_message_handler,rtsp_connection);
+}
+
+/* Process task message */
+static apt_bool_t rtsp_client_task_msg_process(apt_task_t *task, apt_task_msg_t *task_msg)
+{
+       apt_net_client_task_t *net_task = apt_task_object_get(task);
+       rtsp_client_t *client = apt_net_client_task_object_get(net_task);
+
+       task_msg_data_t *data = (task_msg_data_t*) task_msg->data;
+       switch(data->type) {
+               case TASK_MSG_SEND_MESSAGE:
+                       rtsp_client_session_message_process(client,data->session,data->message);
+                       break;
+               case TASK_MSG_TERMINATE_SESSION:
+                       rtsp_client_session_terminate_process(client,data->session);
+                       break;
+       }
+
+       return TRUE;
+}
diff --git a/libs/unimrcp/libs/uni-rtsp/src/rtsp_header.c b/libs/unimrcp/libs/uni-rtsp/src/rtsp_header.c
new file mode 100644 (file)
index 0000000..9d6e12c
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "rtsp_header.h"
+#include "apt_string_table.h"
+
+/** String table of RTSP header fields (rtsp_header_field_id) */
+static const apt_str_table_item_t rtsp_header_string_table[] = {
+       {{"CSeq",           4},1},
+       {{"Transport",      9},0},
+       {{"Session",        7},0},
+       {{"RTP-Info",       8},0},
+       {{"Content-Type",  12},8},
+       {{"Content-Length",14},8}
+};
+
+/** String table of RTSP content types (rtsp_content_type) */
+static const apt_str_table_item_t rtsp_content_type_string_table[] = {
+       {{"application/sdp", 15},12},
+       {{"application/mrcp",16},12}
+};
+
+/** String table of RTSP transport protocols (rtsp_transport_e) */
+static const apt_str_table_item_t rtsp_transport_string_table[] = {
+       {{"RTP", 3},0}
+};
+
+/** String table of RTSP lower transport protocols (rtsp_lower_transport_e) */
+static const apt_str_table_item_t rtsp_lower_transport_string_table[] = {
+       {{"UDP", 3},0},
+       {{"TCP", 3},0}
+};
+
+/** String table of RTSP transport profiles (rtsp_profile_e) */
+static const apt_str_table_item_t rtsp_profile_string_table[] = {
+       {{"AVP", 3},0},
+       {{"SAVP",4},0}
+};
+
+/** String table of RTSP transport attributes (rtsp_transport_attrib_e) */
+static const apt_str_table_item_t rtsp_transport_attrib_string_table[] = {
+       {{"client_port", 11},0},
+       {{"server_port", 11},1},
+       {{"source",      6}, 1},
+       {{"destination", 11},0},
+       {{"unicast",     7}, 0},
+       {{"multicast",   9}, 0}
+};
+
+/** Parse RTSP transport port range */
+static apt_bool_t rtsp_port_range_parse(rtsp_port_range_t *port_range, apt_text_stream_t *stream)
+{
+       apt_str_t value;
+       /* read min value */
+       if(apt_text_field_read(stream,'-',TRUE,&value) == FALSE) {
+               return FALSE;
+       }
+       port_range->min = (apr_port_t)apt_size_value_parse(&value);
+       
+       /* read optional max value */
+       if(apt_text_field_read(stream,';',TRUE,&value) == TRUE) {
+               port_range->max = (apr_port_t)apt_size_value_parse(&value);
+       }
+
+       return TRUE;
+}
+
+/** Generate RTSP transport port range */
+static apt_bool_t rtsp_port_range_generate(rtsp_transport_attrib_e attrib, const rtsp_port_range_t *port_range, apt_text_stream_t *text_stream)
+{
+       const apt_str_t *str;
+       str = apt_string_table_str_get(rtsp_transport_attrib_string_table,RTSP_TRANSPORT_ATTRIB_COUNT,attrib);
+       if(!str) {
+               return FALSE;
+       }
+       apt_string_value_generate(str,text_stream);
+       apt_text_char_insert(text_stream,'=');
+       apt_size_value_generate(port_range->min,text_stream);
+       if(port_range->max > port_range->min) {
+               apt_text_char_insert(text_stream,'-');
+               apt_size_value_generate(port_range->max,text_stream);
+       }
+       return TRUE;
+}
+
+/** Parse RTSP source/destination address */
+static apt_bool_t rtsp_address_parse(apt_str_t *address, apt_text_stream_t *stream, apr_pool_t *pool)
+{
+       apt_str_t value;
+       /* read min value */
+       if(apt_text_field_read(stream,';',TRUE,&value) == FALSE) {
+               return FALSE;
+       }
+       apt_string_copy(address,&value,pool);
+       return TRUE;
+}
+
+/** Parse RTSP transport */
+static apt_bool_t rtsp_transport_attrib_parse(rtsp_transport_t *transport, const apt_str_t *field, apr_pool_t *pool)
+{
+       rtsp_transport_attrib_e attrib;
+       apt_str_t name;
+       apt_text_stream_t stream;
+
+       stream.text = *field;
+       stream.pos = stream.text.buf;
+
+       /* read attrib name */
+       if(apt_text_field_read(&stream,'=',TRUE,&name) == FALSE) {
+               return FALSE;
+       }
+
+       attrib = apt_string_table_id_find(rtsp_transport_attrib_string_table,RTSP_TRANSPORT_ATTRIB_COUNT,&name);
+       switch(attrib) {
+               case RTSP_TRANSPORT_ATTRIB_CLIENT_PORT:
+                       rtsp_port_range_parse(&transport->client_port_range,&stream);
+                       break;
+               case RTSP_TRANSPORT_ATTRIB_SERVER_PORT:
+                       rtsp_port_range_parse(&transport->client_port_range,&stream);
+                       break;
+               case RTSP_TRANSPORT_ATTRIB_SOURCE:
+                       rtsp_address_parse(&transport->source,&stream,pool);
+                       break;
+               case RTSP_TRANSPORT_ATTRIB_DESTINATION:
+                       rtsp_address_parse(&transport->destination,&stream,pool);
+                       break;
+               case RTSP_TRANSPORT_ATTRIB_UNICAST:
+                       transport->delivery = RTSP_DELIVERY_UNICAST;
+                       break;
+               case RTSP_TRANSPORT_ATTRIB_MULTICAST:
+                       transport->delivery = RTSP_DELIVERY_MULTICAST;
+                       break;
+               default:
+                       break;
+       }
+       return TRUE;
+}
+
+/** Parse RTSP transport protocol (RTP/AVP[/UDP]) */
+static apt_bool_t rtsp_transport_protocol_parse(rtsp_transport_t *transport, const apt_str_t *value)
+{
+       apt_str_t field;
+       apt_text_stream_t stream;
+
+       stream.text = *value;
+       stream.pos = stream.text.buf;
+
+       /* set the defaults */
+       transport->protocol = RTSP_TRANSPORT_RTP;
+       transport->profile = RTSP_PROFILE_AVP;
+       transport->lower_protocol = RTSP_LOWER_TRANSPORT_UDP;
+
+       /* read transport protocol (RTP) */
+       if(apt_text_field_read(&stream,'/',TRUE,&field) == FALSE) {
+               return FALSE;
+       }
+       transport->protocol = apt_string_table_id_find(rtsp_transport_string_table,RTSP_TRANSPORT_COUNT,&field);
+       if(transport->protocol >= RTSP_TRANSPORT_COUNT) {
+               return FALSE;
+       }
+
+       /* read transport profile (AVP) */
+       if(apt_text_field_read(&stream,'/',TRUE,&field) == FALSE) {
+               return FALSE;
+       }
+       transport->profile = apt_string_table_id_find(rtsp_profile_string_table,RTSP_PROFILE_COUNT,&field);
+       if(transport->profile >= RTSP_PROFILE_COUNT) {
+               return FALSE;
+       }
+               
+       /* read optional lower transport protocol (UDP) */
+       if(apt_text_field_read(&stream,'/',TRUE,&field) == TRUE) {
+               transport->lower_protocol = apt_string_table_id_find(rtsp_lower_transport_string_table,RTSP_LOWER_TRANSPORT_COUNT,&field);
+               if(transport->lower_protocol >= RTSP_LOWER_TRANSPORT_COUNT) {
+                       return FALSE;
+               }
+       }
+
+       return TRUE;
+}
+
+/** Parse RTSP transport */
+static apt_bool_t rtsp_transport_parse(rtsp_transport_t *transport, const apt_str_t *line, apr_pool_t *pool)
+{
+       apt_str_t field;
+       apt_text_stream_t stream;
+
+       stream.text = *line;
+       stream.pos = stream.text.buf;
+       /* read transport protocol (RTP/AVP[/UDP]) */
+       if(apt_text_field_read(&stream,';',TRUE,&field) == FALSE) {
+               return FALSE;
+       }
+       
+       /* parse transport protocol (RTP/AVP[/UDP]) */
+       if(rtsp_transport_protocol_parse(transport,&field) == FALSE) {
+               return FALSE;
+       }
+
+       /* read transport attributes */
+       while(apt_text_field_read(&stream,';',TRUE,&field) == TRUE) {
+               rtsp_transport_attrib_parse(transport,&field,pool);
+       }
+
+       return TRUE;
+}
+
+/** Generate RTSP transport */
+static apt_bool_t rtsp_transport_generate(rtsp_transport_t *transport, apt_text_stream_t *text_stream)
+{
+       const apt_str_t *protocol = apt_string_table_str_get(rtsp_transport_string_table,RTSP_TRANSPORT_COUNT,transport->protocol);
+       const apt_str_t *profile = apt_string_table_str_get(rtsp_profile_string_table,RTSP_PROFILE_COUNT,transport->profile);
+       if(!protocol || !profile) {
+               return FALSE;
+       }
+       apt_string_value_generate(protocol,text_stream);
+       apt_text_char_insert(text_stream,'/');
+       apt_string_value_generate(profile,text_stream);
+
+       if(transport->delivery != RTSP_DELIVERY_NONE) {
+               const apt_str_t *delivery = NULL;
+               rtsp_transport_attrib_e attrib = RTSP_TRANSPORT_ATTRIB_NONE;
+               if(transport->delivery == RTSP_DELIVERY_UNICAST) {
+                       attrib = RTSP_TRANSPORT_ATTRIB_UNICAST;
+               }
+               else if(transport->delivery == RTSP_DELIVERY_MULTICAST) {
+                       attrib = RTSP_TRANSPORT_ATTRIB_MULTICAST;
+               }
+               delivery = apt_string_table_str_get(rtsp_transport_attrib_string_table,RTSP_TRANSPORT_ATTRIB_COUNT,attrib);
+               if(!delivery) {
+                       return FALSE;
+               }
+       
+               apt_text_char_insert(text_stream,';');
+               apt_string_value_generate(delivery,text_stream);
+       }
+
+       if(rtsp_port_range_is_valid(&transport->client_port_range) == TRUE) {
+               apt_text_char_insert(text_stream,';');
+               rtsp_port_range_generate(RTSP_TRANSPORT_ATTRIB_CLIENT_PORT,&transport->client_port_range,text_stream);
+       }
+       if(rtsp_port_range_is_valid(&transport->server_port_range) == TRUE) {
+               apt_text_char_insert(text_stream,';');
+               rtsp_port_range_generate(RTSP_TRANSPORT_ATTRIB_SERVER_PORT,&transport->server_port_range,text_stream);
+       }
+       return TRUE;
+}
+
+/** Parse RTSP transport */
+static apt_bool_t rtsp_session_id_parse(apt_str_t *session_id, const apt_str_t *value, apr_pool_t *pool)
+{
+       char *sep;
+       if(!value->buf) {
+               return FALSE;
+       }
+       apt_string_copy(session_id,value,pool);
+       sep = strchr(session_id->buf,';');
+       if(sep) {
+               session_id->length = sep - session_id->buf;
+               *sep = '\0';
+       }
+       return TRUE;
+}
+
+/** Parse RTSP header field */
+static apt_bool_t rtsp_header_field_parse(rtsp_header_t *header, rtsp_header_field_id id, const apt_str_t *value, apr_pool_t *pool)
+{
+       apt_bool_t status = TRUE;
+       switch(id) {
+               case RTSP_HEADER_FIELD_CSEQ:
+                       header->cseq = apt_size_value_parse(value);
+                       break;
+               case RTSP_HEADER_FIELD_TRANSPORT:
+                       status = rtsp_transport_parse(&header->transport,value,pool);
+                       break;
+               case RTSP_HEADER_FIELD_SESSION_ID:
+                       status = rtsp_session_id_parse(&header->session_id,value,pool);
+                       break;
+               case RTSP_HEADER_FIELD_RTP_INFO:
+                       apt_string_copy(&header->rtp_info,value,pool);
+                       break;
+               case RTSP_HEADER_FIELD_CONTENT_TYPE:
+                       header->content_type = apt_string_table_id_find(rtsp_content_type_string_table,RTSP_CONTENT_TYPE_COUNT,value);
+                       break;
+               case RTSP_HEADER_FIELD_CONTENT_LENGTH:
+                       header->content_length = apt_size_value_parse(value);
+                       break;
+               default:
+                       status = FALSE;
+       }
+       return status;
+}
+
+/** Generate RTSP header field */
+static apr_size_t rtsp_header_field_generate(rtsp_header_t *header, apr_size_t id, apt_text_stream_t *value)
+{
+       switch(id) {
+               case RTSP_HEADER_FIELD_CSEQ:
+                       apt_size_value_generate(header->cseq,value);
+                       break;
+               case RTSP_HEADER_FIELD_TRANSPORT:
+                       rtsp_transport_generate(&header->transport,value);
+                       break;
+               case RTSP_HEADER_FIELD_SESSION_ID:
+                       apt_string_value_generate(&header->session_id,value);
+                       break;
+               case RTSP_HEADER_FIELD_RTP_INFO:
+                       apt_string_value_generate(&header->rtp_info,value);
+                       break;
+               case RTSP_HEADER_FIELD_CONTENT_TYPE:
+               {
+                       const apt_str_t *name = apt_string_table_str_get(rtsp_content_type_string_table,RTSP_CONTENT_TYPE_COUNT,header->content_type);
+                       if(name) {
+                               apt_string_value_generate(name,value);
+                       }
+                       break;
+               }
+               case RTSP_HEADER_FIELD_CONTENT_LENGTH:
+                       apt_size_value_generate(header->content_length,value);
+                       break;
+               default:
+                       break;
+       }
+       return TRUE;
+}
+
+/** Parse RTSP header */
+RTSP_DECLARE(apt_bool_t) rtsp_header_parse(rtsp_header_t *header, apt_text_stream_t *text_stream, apr_pool_t *pool)
+{
+       apt_pair_t pair;
+       apt_bool_t result = FALSE;
+
+       do {
+               if(apt_text_header_read(text_stream,&pair) == TRUE) {
+                       if(pair.name.length) {
+                               /* parse header_field (name/value) */
+                               rtsp_header_field_id id = apt_string_table_id_find(rtsp_header_string_table,RTSP_HEADER_FIELD_COUNT,&pair.name);
+                               if(id < RTSP_HEADER_FIELD_COUNT) {
+                                       if(rtsp_header_field_parse(header,id,&pair.value,pool) == TRUE) {
+                                               rtsp_header_property_add(&header->property_set,id);
+                                       }
+                               }
+                       }
+                       else {
+                               /* empty header -> exit */
+                               result = TRUE;
+                               break;
+                       }
+               }
+       }
+       while(apt_text_is_eos(text_stream) == FALSE);
+
+       return result;
+}
+
+/** Generate RTSP header */
+RTSP_DECLARE(apt_bool_t) rtsp_header_generate(rtsp_header_t *header, apt_text_stream_t *text_stream)
+{
+       const apt_str_t *name;
+       apr_size_t i;
+       rtsp_header_property_t property_set;
+
+       property_set = header->property_set;
+       for(i=0; i<RTSP_HEADER_FIELD_COUNT && property_set != 0; i++) {
+               if(rtsp_header_property_check(&property_set,i) == TRUE) {
+                       name = apt_string_table_str_get(rtsp_header_string_table,RTSP_HEADER_FIELD_COUNT,i);
+                       if(!name) {
+                               continue;
+                       }
+                       
+                       apt_text_header_name_generate(name,text_stream);
+                       rtsp_header_field_generate(header,i,text_stream);
+                       apt_text_eol_insert(text_stream);
+                       
+                       rtsp_header_property_remove(&property_set,i);
+               }
+       }
+
+       apt_text_eol_insert(text_stream);
+       return TRUE;
+}
diff --git a/libs/unimrcp/libs/uni-rtsp/src/rtsp_message.c b/libs/unimrcp/libs/uni-rtsp/src/rtsp_message.c
new file mode 100644 (file)
index 0000000..2b44e70
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "rtsp_message.h"
+
+/** Initialize RTSP message */
+static APR_INLINE void rtsp_message_init(rtsp_message_t *message, rtsp_message_type_e message_type, apr_pool_t *pool)
+{
+       message->pool = pool;
+       rtsp_start_line_init(&message->start_line,message_type);
+       rtsp_header_init(&message->header);
+       apt_string_reset(&message->body);
+}
+
+/** Create RTSP message */
+RTSP_DECLARE(rtsp_message_t*) rtsp_message_create(rtsp_message_type_e message_type, apr_pool_t *pool)
+{
+       rtsp_message_t *message = apr_palloc(pool,sizeof(rtsp_message_t));
+       rtsp_message_init(message,message_type,pool);
+       return message;
+}
+
+/** Create RTSP request message */
+RTSP_DECLARE(rtsp_message_t*) rtsp_request_create(apr_pool_t *pool)
+{
+       rtsp_message_t *request = rtsp_message_create(RTSP_MESSAGE_TYPE_REQUEST,pool);
+       request->start_line.common.request_line.version = RTSP_VERSION_1;
+       return request;
+}
+
+/** Create RTSP response message */
+RTSP_DECLARE(rtsp_message_t*) rtsp_response_create(const rtsp_message_t *request, rtsp_status_code_e status_code, rtsp_reason_phrase_e reason, apr_pool_t *pool)
+{
+       const apt_str_t *reason_str;
+       rtsp_status_line_t *status_line;
+       rtsp_message_t *response = rtsp_message_create(RTSP_MESSAGE_TYPE_RESPONSE,request->pool);
+       status_line = &response->start_line.common.status_line;
+       status_line->version = request->start_line.common.request_line.version;
+       status_line->status_code = status_code;
+       reason_str = rtsp_reason_phrase_get(reason);
+       if(reason_str) {
+               apt_string_copy(&status_line->reason,reason_str,request->pool);
+       }
+
+       if(rtsp_header_property_check(&request->header.property_set,RTSP_HEADER_FIELD_CSEQ) == TRUE) {
+               response->header.cseq = request->header.cseq;
+               rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_CSEQ);
+       }
+
+       return response;
+}
+
+/** Destroy RTSP message */
+RTSP_DECLARE(void) rtsp_message_destroy(rtsp_message_t *message)
+{
+       /* nothing to do message is allocated from pool */
+}
diff --git a/libs/unimrcp/libs/uni-rtsp/src/rtsp_server.c b/libs/unimrcp/libs/uni-rtsp/src/rtsp_server.c
new file mode 100644 (file)
index 0000000..d568e97
--- /dev/null
@@ -0,0 +1,650 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_hash.h>
+#include "rtsp_server.h"
+#include "rtsp_stream.h"
+#include "apt_net_server_task.h"
+#include "apt_text_stream.h"
+#include "apt_pool.h"
+#include "apt_obj_list.h"
+#include "apt_log.h"
+
+#define RTSP_SESSION_ID_HEX_STRING_LENGTH 16
+#define RTSP_STREAM_BUFFER_SIZE 1024
+
+typedef struct rtsp_server_connection_t rtsp_server_connection_t;
+
+/** RTSP server */
+struct rtsp_server_t {
+       apr_pool_t                 *pool;
+       apt_net_server_task_t      *task;
+
+       apr_pool_t                 *sub_pool;
+       apt_obj_list_t             *connection_list;
+
+       void                       *obj;
+       const rtsp_server_vtable_t *vtable;
+};
+
+/** RTSP connection */
+struct rtsp_server_connection_t {
+       /** Connection base */
+       apt_net_server_connection_t *base;
+
+       /** RTSP server, connection belongs to */
+       rtsp_server_t               *server;
+       /** Element of the connection list in agent */
+       apt_list_elem_t             *it;
+
+       /** Session table (rtsp_server_session_t*) */
+       apr_hash_t                  *session_table;
+
+       char                         rx_buffer[RTSP_STREAM_BUFFER_SIZE];
+       apt_text_stream_t            rx_stream;
+       rtsp_parser_t               *parser;
+
+       char                         tx_buffer[RTSP_STREAM_BUFFER_SIZE];
+       apt_text_stream_t            tx_stream;
+       rtsp_generator_t            *generator;
+};
+
+/** RTSP session */
+struct rtsp_server_session_t {
+       apr_pool_t               *pool;
+       void                     *obj;
+       rtsp_server_connection_t *connection;
+
+       /** Session identifier */
+       apt_str_t                 id;
+       apt_str_t                 url;
+
+       /** Last cseq sent */
+       apr_size_t                last_cseq;
+
+       /** In-progress request */
+       rtsp_message_t           *active_request;
+       /** request queue */
+       apt_obj_list_t           *request_queue;
+
+       /** In-progress termination request */
+       apt_bool_t                terminating;
+};
+
+typedef enum {
+       TASK_MSG_SEND_MESSAGE,
+       TASK_MSG_TERMINATE_SESSION
+} task_msg_data_type_e;
+
+typedef struct task_msg_data_t task_msg_data_t;
+
+struct task_msg_data_t {
+       task_msg_data_type_e   type;
+       rtsp_server_t         *server;
+       rtsp_server_session_t *session;
+       rtsp_message_t        *message;
+};
+
+static apt_bool_t rtsp_server_task_msg_process(apt_task_t *task, apt_task_msg_t *msg);
+
+static apt_bool_t rtsp_server_on_connect(apt_net_server_task_t *task, apt_net_server_connection_t *connection);
+static apt_bool_t rtsp_server_on_disconnect(apt_net_server_task_t *task, apt_net_server_connection_t *connection);
+static apt_bool_t rtsp_server_message_receive(apt_net_server_task_t *task, apt_net_server_connection_t *connection);
+
+static const apt_net_server_vtable_t server_vtable = {
+       rtsp_server_on_connect,
+       rtsp_server_on_disconnect,
+       rtsp_server_message_receive
+};
+
+static apt_bool_t rtsp_server_message_send(rtsp_server_t *server, apt_net_server_connection_t *connection, rtsp_message_t *message);
+
+/** Create RTSP server */
+RTSP_DECLARE(rtsp_server_t*) rtsp_server_create(
+                                                                               const char *listen_ip,
+                                                                               apr_port_t listen_port,
+                                                                               apr_size_t max_connection_count,
+                                                                               void *obj,
+                                                                               const rtsp_server_vtable_t *handler,
+                                                                               apr_pool_t *pool)
+{
+       apt_task_vtable_t *vtable;
+       apt_task_msg_pool_t *msg_pool;
+       rtsp_server_t *server;
+
+       if(!listen_ip) {
+               return NULL;
+       }
+       
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Create RTSP Server %s:%hu [%d]",listen_ip,listen_port,max_connection_count);
+       server = apr_palloc(pool,sizeof(rtsp_server_t));
+       server->pool = pool;
+       server->obj = obj;
+       server->vtable = handler;
+
+       msg_pool = apt_task_msg_pool_create_dynamic(sizeof(task_msg_data_t),pool);
+
+       server->task = apt_net_server_task_create(
+                                               listen_ip,listen_port,max_connection_count,
+                                               server,&server_vtable,msg_pool,pool);
+       if(!server->task) {
+               return NULL;
+       }
+
+       vtable = apt_net_server_task_vtable_get(server->task);
+       if(vtable) {
+               vtable->process_msg = rtsp_server_task_msg_process;
+       }
+
+       server->sub_pool = apt_subpool_create(pool);
+       server->connection_list = NULL;
+       return server;
+}
+
+/** Destroy RTSP server */
+RTSP_DECLARE(apt_bool_t) rtsp_server_destroy(rtsp_server_t *server)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Destroy RTSP Server");
+       return apt_net_server_task_destroy(server->task);
+}
+
+/** Start connection agent. */
+RTSP_DECLARE(apt_bool_t) rtsp_server_start(rtsp_server_t *server)
+{
+       return apt_net_server_task_start(server->task);
+}
+
+/** Terminate connection agent. */
+RTSP_DECLARE(apt_bool_t) rtsp_server_terminate(rtsp_server_t *server)
+{
+       return apt_net_server_task_terminate(server->task);
+}
+
+/** Get task */
+RTSP_DECLARE(apt_task_t*) rtsp_server_task_get(rtsp_server_t *server)
+{
+       return apt_net_server_task_base_get(server->task);
+}
+
+/** Get external object */
+RTSP_DECLARE(void*) rtsp_server_object_get(rtsp_server_t *server)
+{
+       return server->obj;
+}
+
+/** Get object associated with the session */
+RTSP_DECLARE(void*) rtsp_server_session_object_get(const rtsp_server_session_t *session)
+{
+       return session->obj;
+}
+
+/** Set object associated with the session */
+RTSP_DECLARE(void) rtsp_server_session_object_set(rtsp_server_session_t *session, void *obj)
+{
+       session->obj = obj;
+}
+
+/** Get the session identifier */
+RTSP_DECLARE(const apt_str_t*) rtsp_server_session_id_get(const rtsp_server_session_t *session)
+{
+       return &session->id;
+}
+
+/** Get active request */
+RTSP_DECLARE(const rtsp_message_t*) rtsp_server_session_request_get(const rtsp_server_session_t *session)
+{
+       return session->active_request;
+}
+
+/** Get the session destination (client) ip address */
+RTSP_DECLARE(const char*) rtsp_server_session_destination_get(const rtsp_server_session_t *session)
+{
+       if(session->connection) {
+               return session->connection->base->client_ip;
+       }
+       return NULL;
+}
+
+/** Signal task message */
+static apt_bool_t rtsp_server_control_message_signal(
+                                                               task_msg_data_type_e type,
+                                                               rtsp_server_t *server,
+                                                               rtsp_server_session_t *session,
+                                                               rtsp_message_t *message)
+{
+       apt_task_t *task = apt_net_server_task_base_get(server->task);
+       apt_task_msg_t *task_msg = apt_task_msg_get(task);
+       if(task_msg) {
+               task_msg_data_t *data = (task_msg_data_t*)task_msg->data;
+               data->type = type;
+               data->server = server;
+               data->session = session;
+               data->message = message;
+               apt_task_msg_signal(task,task_msg);
+       }
+       return TRUE;
+}
+
+/** Signal RTSP message */
+RTSP_DECLARE(apt_bool_t) rtsp_server_session_respond(rtsp_server_t *server, rtsp_server_session_t *session, rtsp_message_t *message)
+{
+       return rtsp_server_control_message_signal(TASK_MSG_SEND_MESSAGE,server,session,message);
+}
+
+/** Signal terminate response */
+RTSP_DECLARE(apt_bool_t) rtsp_server_session_terminate(rtsp_server_t *server, rtsp_server_session_t *session)
+{
+       return rtsp_server_control_message_signal(TASK_MSG_TERMINATE_SESSION,server,session,NULL);
+}
+
+/* Create RTSP session */
+static rtsp_server_session_t* rtsp_server_session_create(rtsp_server_t *server)
+{
+       rtsp_server_session_t *session;
+       apr_pool_t *pool = apt_pool_create();
+       session = apr_palloc(pool,sizeof(rtsp_server_session_t));
+       session->pool = pool;
+       session->obj = NULL;
+       session->last_cseq = 0;
+       session->active_request = NULL;
+       session->request_queue = apt_list_create(pool);
+       session->terminating = FALSE;
+
+       apt_string_reset(&session->url);
+       apt_unique_id_generate(&session->id,RTSP_SESSION_ID_HEX_STRING_LENGTH,pool);
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create RTSP Session "APT_SID_FMT,session->id.buf);
+       if(server->vtable->create_session(server,session) != TRUE) {
+               apr_pool_destroy(pool);
+               return NULL;
+       }
+       return session;
+}
+
+/* Destroy RTSP session */
+static void rtsp_server_session_destroy(rtsp_server_session_t *session)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy RTSP Session "APT_SID_FMT,session->id.buf);
+       if(session && session->pool) {
+               apr_pool_destroy(session->pool);
+       }
+}
+
+/* Finally terminate RTSP session */
+static apt_bool_t rtsp_server_session_do_terminate(rtsp_server_t *server, rtsp_server_session_t *session)
+{              
+       rtsp_server_connection_t *rtsp_connection = session->connection;
+
+       if(session->active_request) {
+               rtsp_message_t *response = rtsp_response_create(session->active_request,
+                       RTSP_STATUS_CODE_OK,RTSP_REASON_PHRASE_OK,session->active_request->pool);
+               if(response) {
+                       if(session->id.buf) {
+                               response->header.session_id = session->id;
+                               rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_SESSION_ID);
+                       }
+
+                       if(rtsp_connection) {
+                               rtsp_server_message_send(server,rtsp_connection->base,response);
+                       }
+               }
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remove RTSP Session "APT_SID_FMT,session->id.buf);
+       apr_hash_set(rtsp_connection->session_table,session->id.buf,session->id.length,NULL);
+       rtsp_server_session_destroy(session);
+
+       if(rtsp_connection && !rtsp_connection->it) {
+               if(apr_hash_count(rtsp_connection->session_table) == 0) {
+                       apt_net_server_connection_destroy(rtsp_connection->base);
+               }
+       }
+       return TRUE;
+}
+
+static apt_bool_t rtsp_server_error_respond(rtsp_server_t *server, rtsp_server_connection_t *rtsp_connection, rtsp_message_t *request, 
+                                                                                       rtsp_status_code_e status_code, rtsp_reason_phrase_e reason)
+{
+       /* send error response to client */
+       rtsp_message_t *response = rtsp_response_create(request,status_code,reason,request->pool);
+       if(rtsp_server_message_send(server,rtsp_connection->base,response) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Send RTSP Response");
+               return FALSE;
+       }
+       return TRUE;
+}
+
+static apt_bool_t rtsp_server_session_terminate_request(rtsp_server_t *server, rtsp_server_session_t *session)
+{
+       session->terminating = TRUE;
+       return server->vtable->terminate_session(server,session);
+}
+
+static apt_bool_t rtsp_server_session_message_handle(rtsp_server_t *server, rtsp_server_session_t *session, rtsp_message_t *message)
+{
+       if(message->start_line.common.request_line.method_id == RTSP_METHOD_TEARDOWN) {
+               rtsp_server_session_terminate_request(server,session);
+               return TRUE;
+       }
+
+       if(server->vtable->handle_message(server,session,message) != TRUE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Handle Message "APT_SID_FMT,session->id.buf);
+               rtsp_server_error_respond(server,session->connection,message,
+                                                               RTSP_STATUS_CODE_INTERNAL_SERVER_ERROR,
+                                                               RTSP_REASON_PHRASE_INTERNAL_SERVER_ERROR);
+               return FALSE;
+       }
+       return TRUE;
+}
+
+/* Process incoming SETUP request */
+static rtsp_server_session_t* rtsp_server_session_setup_process(rtsp_server_t *server, rtsp_server_connection_t *rtsp_connection, rtsp_message_t *message)
+{
+       rtsp_server_session_t *session = NULL;
+       if(message->start_line.common.request_line.method_id == RTSP_METHOD_SETUP) {
+               /* create new session */
+               session = rtsp_server_session_create(server);
+               session->connection = rtsp_connection;
+               session->url = message->start_line.common.request_line.url;
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Add RTSP Session "APT_SID_FMT,session->id.buf);
+               apr_hash_set(rtsp_connection->session_table,session->id.buf,session->id.length,session);
+       }
+       else if(message->start_line.common.request_line.method_id == RTSP_METHOD_DESCRIBE) {
+               /* create new session as a communication object */
+               session = rtsp_server_session_create(server);
+               session->connection = rtsp_connection;
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Add RTSP Session "APT_SID_FMT,session->id.buf);
+               apr_hash_set(rtsp_connection->session_table,session->id.buf,session->id.length,session);
+       }
+       else {
+               /* error case */
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Missing RTSP Session-ID");
+               rtsp_server_error_respond(server,rtsp_connection,message,
+                                                               RTSP_STATUS_CODE_BAD_REQUEST,
+                                                               RTSP_REASON_PHRASE_BAD_REQUEST);
+       }
+       return session;
+}
+
+/* Process incoming RTSP request */
+static apt_bool_t rtsp_server_session_request_process(rtsp_server_t *server, rtsp_server_connection_t *rtsp_connection, rtsp_message_t *message)
+{
+       rtsp_server_session_t *session = NULL;
+       if(message->start_line.message_type != RTSP_MESSAGE_TYPE_REQUEST) {
+               /* received response to ANNOUNCE request/event */
+               return TRUE;
+       }
+
+       if(rtsp_header_property_check(&message->header.property_set,RTSP_HEADER_FIELD_SESSION_ID) != TRUE) {
+               /* no session-id specified */
+               session = rtsp_server_session_setup_process(server,rtsp_connection,message);
+               if(session) {
+                       session->active_request = message;
+                       if(rtsp_server_session_message_handle(server,session,message) != TRUE) {
+                               rtsp_server_session_destroy(session);
+                       }
+               }
+               return TRUE;
+       }
+
+       /* existing session */
+       session = apr_hash_get(
+                               rtsp_connection->session_table,
+                               message->header.session_id.buf,
+                               message->header.session_id.length);
+       if(!session) {
+               /* error case */
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Such RTSP Session "APT_SID_FMT,message->header.session_id.buf);
+               return rtsp_server_error_respond(server,rtsp_connection,message,
+                                                               RTSP_STATUS_CODE_NOT_FOUND,
+                                                               RTSP_REASON_PHRASE_NOT_FOUND);
+       }
+       
+       if(session->active_request) {
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Push RTSP Request to Queue "APT_SID_FMT,session->id.buf);
+               apt_list_push_back(session->request_queue,message,message->pool);
+               return TRUE;
+       }
+
+       /* handle the request */
+       session->active_request = message;
+       rtsp_server_session_message_handle(server,session,message);
+       return TRUE;
+}
+
+/* Process outgoing RTSP response */
+static apt_bool_t rtsp_server_session_response_process(rtsp_server_t *server, rtsp_server_session_t *session, rtsp_message_t *message)
+{
+       if(session->id.buf) {
+               message->header.session_id = session->id;
+               rtsp_header_property_add(&message->header.property_set,RTSP_HEADER_FIELD_SESSION_ID);
+       }
+
+       if(message->start_line.message_type == RTSP_MESSAGE_TYPE_REQUEST) {
+               /* RTSP ANNOUNCE request (asynch event) */
+               message->start_line.common.request_line.url = session->url;
+               message->header.cseq = session->last_cseq;
+               rtsp_header_property_add(&message->header.property_set,RTSP_HEADER_FIELD_CSEQ);
+               
+               rtsp_server_message_send(server,session->connection->base,message);
+               return TRUE;
+       }
+
+       session->last_cseq = message->header.cseq;
+       rtsp_server_message_send(server,session->connection->base,message);
+
+       if(session->active_request) {
+               rtsp_message_t *request = session->active_request;
+               if(request->start_line.common.request_line.method_id == RTSP_METHOD_SETUP) {
+                       if(message->start_line.common.status_line.status_code != RTSP_STATUS_CODE_OK) {
+                               rtsp_server_session_terminate_request(server,session);
+                       }
+               }
+               else if(request->start_line.common.request_line.method_id == RTSP_METHOD_DESCRIBE) {
+                       rtsp_server_session_terminate_request(server,session);
+               }
+       }
+
+       session->active_request = apt_list_pop_front(session->request_queue);
+       if(session->active_request) {
+               rtsp_server_session_message_handle(server,session,session->active_request);
+       }
+       return TRUE;
+}
+
+/* Send RTSP message through RTSP connection */
+static apt_bool_t rtsp_server_message_send(rtsp_server_t *server, apt_net_server_connection_t *connection, rtsp_message_t *message)
+{
+       apt_bool_t status = FALSE;
+       rtsp_server_connection_t *rtsp_connection;
+       apt_text_stream_t *stream;
+       rtsp_stream_result_e result;
+
+       if(!connection || !connection->sock) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No RTSP Connection");
+               return FALSE;
+       }
+       rtsp_connection = connection->obj;
+       stream = &rtsp_connection->tx_stream;
+               
+       rtsp_generator_message_set(rtsp_connection->generator,message);
+       do {
+               stream->text.length = sizeof(rtsp_connection->tx_buffer)-1;
+               stream->pos = stream->text.buf;
+               result = rtsp_generator_run(rtsp_connection->generator,stream);
+               if(result == RTSP_STREAM_MESSAGE_COMPLETE || result == RTSP_STREAM_MESSAGE_TRUNCATED) {
+                       stream->text.length = stream->pos - stream->text.buf;
+                       *stream->pos = '\0';
+
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Send RTSP Stream %s [%lu bytes]\n%s",
+                               connection->id,
+                               stream->text.length,
+                               stream->text.buf);
+                       if(apr_socket_send(connection->sock,stream->text.buf,&stream->text.length) == APR_SUCCESS) {
+                               status = TRUE;
+                       }
+                       else {
+                               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Send RTSP Stream");
+                       }
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Generate RTSP Stream");
+               }
+       }
+       while(result == RTSP_STREAM_MESSAGE_TRUNCATED);
+
+       return status;
+}
+
+static apt_bool_t rtsp_server_message_handler(void *obj, rtsp_message_t *message, rtsp_stream_result_e result)
+{
+       rtsp_server_connection_t *rtsp_connection = obj;
+       if(result == RTSP_STREAM_MESSAGE_COMPLETE) {
+               /* message is completely parsed */
+               apt_str_t *destination;
+               rtsp_message_t *message = rtsp_parser_message_get(rtsp_connection->parser);
+               destination = &message->header.transport.destination;
+               if(!destination->buf && rtsp_connection->base->client_ip) {
+                       apt_string_assign(destination,rtsp_connection->base->client_ip,rtsp_connection->base->pool);
+               }
+               rtsp_server_session_request_process(rtsp_connection->server,rtsp_connection,message);
+       }
+       else if(result == RTSP_STREAM_MESSAGE_INVALID) {
+               /* error case */
+               rtsp_message_t *response;
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse RTSP Stream");
+               if(message) {
+                       response = rtsp_response_create(message,RTSP_STATUS_CODE_BAD_REQUEST,
+                                                                       RTSP_REASON_PHRASE_BAD_REQUEST,message->pool);
+                       if(rtsp_server_message_send(rtsp_connection->server,rtsp_connection->base,response) == FALSE) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Send RTSP Response");
+                       }
+               }
+       }
+       return TRUE;
+}
+
+/* Receive RTSP message through RTSP connection */
+static apt_bool_t rtsp_server_message_receive(apt_net_server_task_t *task, apt_net_server_connection_t *connection)
+{
+       rtsp_server_connection_t *rtsp_connection;
+       apr_status_t status;
+       apr_size_t offset;
+       apr_size_t length;
+       apt_text_stream_t *stream;
+
+       if(!connection || !connection->sock) {
+               return FALSE;
+       }
+       rtsp_connection = connection->obj;
+       stream = &rtsp_connection->rx_stream;
+
+       /* init length of the stream */
+       stream->text.length = sizeof(rtsp_connection->rx_buffer)-1;
+       /* calculate offset remaining from the previous receive / if any */
+       offset = stream->pos - stream->text.buf;
+       /* calculate available length */
+       length = stream->text.length - offset;
+       status = apr_socket_recv(connection->sock,stream->pos,&length);
+       if(status == APR_EOF || length == 0) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"TCP Peer Disconnected %s",connection->id);
+               return apt_net_server_connection_close(task,connection);
+       }
+       /* calculate actual length of the stream */
+       stream->text.length = offset + length;
+       stream->pos[length] = '\0';
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive RTSP Stream %s [%lu bytes]\n%s",
+               connection->id,
+               length,
+               stream->pos);
+
+       /* reset pos */
+       stream->pos = stream->text.buf;
+       /* walk through the stream parsing RTSP messages */
+       return rtsp_stream_walk(rtsp_connection->parser,stream,rtsp_server_message_handler,rtsp_connection);
+}
+
+/* New RTSP connection accepted */
+static apt_bool_t rtsp_server_on_connect(apt_net_server_task_t *task, apt_net_server_connection_t *connection)
+{
+       rtsp_server_t *server = apt_net_server_task_object_get(task);
+       rtsp_server_connection_t *rtsp_connection = apr_palloc(connection->pool,sizeof(rtsp_server_connection_t));
+       rtsp_connection->session_table = apr_hash_make(connection->pool);
+       apt_text_stream_init(&rtsp_connection->rx_stream,rtsp_connection->rx_buffer,sizeof(rtsp_connection->rx_buffer)-1);
+       apt_text_stream_init(&rtsp_connection->tx_stream,rtsp_connection->tx_buffer,sizeof(rtsp_connection->tx_buffer)-1);
+       rtsp_connection->parser = rtsp_parser_create(connection->pool);
+       rtsp_connection->generator = rtsp_generator_create(connection->pool);
+       rtsp_connection->base = connection;
+       connection->obj = rtsp_connection;
+       if(!server->connection_list) {
+               server->connection_list = apt_list_create(server->sub_pool);
+       }
+       rtsp_connection->server = server;
+       rtsp_connection->it = apt_list_push_back(server->connection_list,rtsp_connection,connection->pool);
+       return TRUE;
+}
+
+/* RTSP connection disconnected */
+static apt_bool_t rtsp_server_on_disconnect(apt_net_server_task_t *task, apt_net_server_connection_t *connection)
+{
+       apr_size_t remaining_sessions = 0;
+       rtsp_server_t *server = apt_net_server_task_object_get(task);
+       rtsp_server_connection_t *rtsp_connection = connection->obj;
+       apt_list_elem_remove(server->connection_list,rtsp_connection->it);
+       rtsp_connection->it = NULL;
+       if(apt_list_is_empty(server->connection_list) == TRUE) {
+               apr_pool_clear(server->sub_pool);
+               server->connection_list = NULL;
+       }
+
+       remaining_sessions = apr_hash_count(rtsp_connection->session_table);
+       if(remaining_sessions) {
+               rtsp_server_session_t *session;
+               void *val;
+               apr_hash_index_t *it;
+               apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Terminate Remaining RTSP Sessions [%d]",remaining_sessions);
+               it = apr_hash_first(connection->pool,rtsp_connection->session_table);
+               for(; it; it = apr_hash_next(it)) {
+                       apr_hash_this(it,NULL,NULL,&val);
+                       session = val;
+                       if(session && session->terminating == FALSE) {
+                               rtsp_server_session_terminate_request(server,session);
+                       }
+               }
+       }
+       else {
+               apt_net_server_connection_destroy(connection);
+       }
+       return TRUE;
+}
+
+/* Process task message */
+static apt_bool_t rtsp_server_task_msg_process(apt_task_t *task, apt_task_msg_t *task_msg)
+{
+       apt_net_server_task_t *net_task = apt_task_object_get(task);
+       rtsp_server_t *server = apt_net_server_task_object_get(net_task);
+
+       task_msg_data_t *data = (task_msg_data_t*) task_msg->data;
+       switch(data->type) {
+               case TASK_MSG_SEND_MESSAGE:
+                       rtsp_server_session_response_process(server,data->session,data->message);
+                       break;
+               case TASK_MSG_TERMINATE_SESSION:
+                       rtsp_server_session_do_terminate(server,data->session);
+                       break;
+       }
+
+       return TRUE;
+}
diff --git a/libs/unimrcp/libs/uni-rtsp/src/rtsp_start_line.c b/libs/unimrcp/libs/uni-rtsp/src/rtsp_start_line.c
new file mode 100644 (file)
index 0000000..b6a3fb3
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "rtsp_start_line.h"
+#include "apt_string_table.h"
+#include "apt_log.h"
+
+/** Protocol name used in version string */
+#define RTSP_NAME "RTSP"
+#define RTSP_NAME_LENGTH        (sizeof(RTSP_NAME)-1)
+
+/** Separators used in RTSP version string parse/generate */
+#define RTSP_NAME_VERSION_SEPARATOR        '/'
+#define RTSP_VERSION_MAJOR_MINOR_SEPARATOR '.'
+
+/** String table of RTSP methods (rtsp_method_id) */
+static const apt_str_table_item_t rtsp_method_string_table[] = {
+       {{"SETUP",    5},0},
+       {{"ANNOUNCE", 8},0},
+       {{"TEARDOWN", 8},0},
+       {{"DESCRIBE", 8},0}
+};
+
+/** String table of RTSP reason phrases (rtsp_reason_phrase_e) */
+static const apt_str_table_item_t rtsp_reason_string_table[] = {
+       {{"OK",                     2},0},
+       {{"Created",                7},0},
+       {{"Bad Request",           11},0},
+       {{"Unauthorized",          12},0},
+       {{"Not Found",              9},4},
+       {{"Method Not Allowed",    18},0},
+       {{"Not Acceptable",        14},4},
+       {{"Session Not Found",     17},0},
+       {{"Internal Server Error", 21},0},
+       {{"Not Implemented",       15},4}
+};
+
+/** Parse RTSP URI */
+static apt_bool_t rtsp_resource_uri_parse(const apt_str_t *field, rtsp_request_line_t *request_line, apr_pool_t *pool)
+{
+       char *str;
+       apt_str_t *url = &request_line->url;
+       if(!field->length || !field->buf) {
+               return FALSE;
+       }
+
+       apt_string_copy(url,field,pool);
+       if(url->buf[url->length-1] == '/') {
+               url->length--;
+               url->buf[url->length] = '\0';
+       }
+
+       str = strrchr(url->buf,'/');
+       if(str) {
+               str++;
+       }
+       request_line->resource_name = str;
+       return TRUE;
+}
+
+/** Parse RTSP version */
+static rtsp_version_e rtsp_version_parse(const apt_str_t *field)
+{
+       rtsp_version_e version = RTSP_VERSION_UNKNOWN;
+       const char *pos;
+       if(field->length <= RTSP_NAME_LENGTH || strncasecmp(field->buf,RTSP_NAME,RTSP_NAME_LENGTH) != 0) {
+               /* unexpected protocol name */
+               return version;
+       }
+
+       pos = field->buf + RTSP_NAME_LENGTH;
+       if(*pos == RTSP_NAME_VERSION_SEPARATOR) {
+               pos++;
+               switch(*pos) {
+                       case '1': version = RTSP_VERSION_1; break;
+                       default: ;
+               }
+       }
+       return version;
+}
+
+/** Generate RTSP version */
+static apt_bool_t rtsp_version_generate(rtsp_version_e version, apt_text_stream_t *stream)
+{
+       memcpy(stream->pos,RTSP_NAME,RTSP_NAME_LENGTH);
+       stream->pos += RTSP_NAME_LENGTH;
+       *stream->pos++ = RTSP_NAME_VERSION_SEPARATOR;
+       apt_size_value_generate(version,stream);
+       *stream->pos++ = RTSP_VERSION_MAJOR_MINOR_SEPARATOR;
+       *stream->pos++ = '0';
+       return TRUE;
+}
+
+/** Parse RTSP status-code */
+static APR_INLINE rtsp_status_code_e rtsp_status_code_parse(const apt_str_t *field)
+{
+       return apt_size_value_parse(field);
+}
+
+/** Generate RTSP status-code */
+static APR_INLINE apt_bool_t rtsp_status_code_generate(rtsp_status_code_e status_code, apt_text_stream_t *stream)
+{
+       return apt_size_value_generate(status_code,stream);
+}
+
+/** Generate RTSP request-line */
+static apt_bool_t rtsp_request_line_generate(rtsp_request_line_t *start_line, apt_text_stream_t *stream)
+{
+       const apt_str_t *method_name = apt_string_table_str_get(rtsp_method_string_table,RTSP_METHOD_COUNT,start_line->method_id);
+       if(!method_name) {
+               return FALSE;
+       }
+       start_line->method_name = *method_name;
+       apt_string_value_generate(&start_line->method_name,stream);
+       apt_text_space_insert(stream);
+
+       apt_string_value_generate(&start_line->url,stream);
+       apt_text_space_insert(stream);
+
+       rtsp_version_generate(start_line->version,stream);
+       return TRUE;
+}
+
+/** Generate RTSP status-line */
+static apt_bool_t rtsp_status_line_generate(rtsp_status_line_t *start_line, apt_text_stream_t *stream)
+{
+       rtsp_version_generate(start_line->version,stream);
+       apt_text_space_insert(stream);
+
+       rtsp_status_code_generate(start_line->status_code,stream);
+       apt_text_space_insert(stream);
+
+       apt_string_value_generate(&start_line->reason,stream);
+       return TRUE;
+}
+
+/** Parse RTSP start-line */
+RTSP_DECLARE(apt_bool_t) rtsp_start_line_parse(rtsp_start_line_t *start_line, apt_text_stream_t *stream, apr_pool_t *pool)
+{
+       apt_text_stream_t line;
+       apt_str_t field;
+       if(apt_text_line_read(stream,&line.text) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse RTSP start-line");
+               return FALSE;
+       }
+       line.pos = line.text.buf;
+
+       if(apt_text_field_read(&line,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot read the first field in start-line");
+               return FALSE;
+       }
+
+       if(field.buf == strstr(field.buf,RTSP_NAME)) {
+               /* parsing RTSP response */
+               rtsp_status_line_t  *status_line = &start_line->common.status_line;
+               start_line->message_type = RTSP_MESSAGE_TYPE_RESPONSE;
+               rtsp_status_line_init(status_line);
+
+               status_line->version = rtsp_version_parse(&field);
+
+               if(apt_text_field_read(&line,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse status-code in status-line");
+                       return FALSE;
+               }
+               status_line->status_code = rtsp_status_code_parse(&field);
+
+               if(apt_text_field_read(&line,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse reason phrase in status-line");
+                       return FALSE;
+               }
+               apt_string_copy(&status_line->reason,&field,pool);
+       }
+       else {
+               /* parsing RTSP request */
+               rtsp_request_line_t *request_line = &start_line->common.request_line;
+               start_line->message_type = RTSP_MESSAGE_TYPE_REQUEST;
+               rtsp_request_line_init(request_line);
+
+               apt_string_copy(&request_line->method_name,&field,pool);
+               request_line->method_id = apt_string_table_id_find(rtsp_method_string_table,RTSP_METHOD_COUNT,&field);
+
+               if(apt_text_field_read(&line,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse URL in request-line");
+                       return FALSE;
+               }
+               rtsp_resource_uri_parse(&field,request_line,pool);
+
+               if(apt_text_field_read(&line,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse version in request-line");
+                       return FALSE;
+               }
+               request_line->version = rtsp_version_parse(&field);
+       }
+
+       return TRUE;
+}
+
+/** Generate RTSP start-line */
+RTSP_DECLARE(apt_bool_t) rtsp_start_line_generate(rtsp_start_line_t *start_line, apt_text_stream_t *stream)
+{
+       apt_bool_t status = FALSE;
+       switch(start_line->message_type) {
+               case RTSP_MESSAGE_TYPE_REQUEST:
+                       status = rtsp_request_line_generate(&start_line->common.request_line,stream);
+                       break;
+               case RTSP_MESSAGE_TYPE_RESPONSE:
+                       status = rtsp_status_line_generate(&start_line->common.status_line,stream);
+                       break;
+               default:
+                       break;
+       }
+
+       if(status == TRUE) {
+               apt_text_eol_insert(stream);
+       }
+       
+       return status;
+}
+
+/** Get reason phrase by status code */
+RTSP_DECLARE(const apt_str_t*) rtsp_reason_phrase_get(rtsp_reason_phrase_e reason)
+{
+       return apt_string_table_str_get(rtsp_reason_string_table,RTSP_REASON_PHRASE_COUNT,reason);
+}
diff --git a/libs/unimrcp/libs/uni-rtsp/src/rtsp_stream.c b/libs/unimrcp/libs/uni-rtsp/src/rtsp_stream.c
new file mode 100644 (file)
index 0000000..51b7910
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "rtsp_stream.h"
+#include "apt_log.h"
+
+/** RTSP parser */
+struct rtsp_parser_t {
+       rtsp_stream_result_e result;
+       char                *pos;
+       apt_bool_t           skip_lf;
+       rtsp_message_t      *message;
+       apr_pool_t          *pool;
+};
+
+/** RTSP generator */
+struct rtsp_generator_t {
+       rtsp_stream_result_e result;
+       char                *pos;
+       rtsp_message_t      *message;
+       apr_pool_t          *pool;
+};
+
+/** Read RTSP message-body */
+static rtsp_stream_result_e rtsp_message_body_read(rtsp_message_t *message, apt_text_stream_t *stream)
+{
+       rtsp_stream_result_e result = RTSP_STREAM_MESSAGE_COMPLETE;
+       if(message->body.buf) {
+               /* stream length available to read */
+               apr_size_t stream_length = stream->text.length - (stream->pos - stream->text.buf);
+               /* required/remaining length to read */
+               apr_size_t required_length = message->header.content_length - message->body.length;
+               if(required_length > stream_length) {
+                       required_length = stream_length;
+                       /* not complete */
+                       result = RTSP_STREAM_MESSAGE_TRUNCATED;
+               }
+               memcpy(message->body.buf+message->body.length,stream->pos,required_length);
+               message->body.length += required_length;
+               stream->pos += required_length;
+               message->body.buf[message->body.length] = '\0';
+       }
+
+       return result;
+}
+
+/** Parse RTSP message-body */
+static rtsp_stream_result_e rtsp_message_body_parse(rtsp_message_t *message, apt_text_stream_t *stream, apr_pool_t *pool)
+{
+       if(rtsp_header_property_check(&message->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH) == TRUE) {
+               if(message->header.content_length) {
+                       apt_str_t *body = &message->body;
+                       body->buf = apr_palloc(pool,message->header.content_length+1);
+                       body->length = 0;
+                       return rtsp_message_body_read(message,stream);
+               }
+       }
+       return RTSP_STREAM_MESSAGE_COMPLETE;
+}
+
+/** Write RTSP message-body */
+static rtsp_stream_result_e rtsp_message_body_write(rtsp_message_t *message, apt_text_stream_t *stream)
+{
+       rtsp_stream_result_e result = RTSP_STREAM_MESSAGE_COMPLETE;
+       if(message->body.length < message->header.content_length) {
+               /* stream length available to write */
+               apr_size_t stream_length = stream->text.length - (stream->pos - stream->text.buf);
+               /* required/remaining length to write */
+               apr_size_t required_length = message->header.content_length - message->body.length;
+               if(required_length > stream_length) {
+                       required_length = stream_length;
+                       /* not complete */
+                       result = RTSP_STREAM_MESSAGE_TRUNCATED;
+               }
+
+               memcpy(stream->pos,message->body.buf+message->body.length,required_length);
+               message->body.length += required_length;
+               stream->pos += required_length;
+       }
+
+       return result;
+}
+
+/** Generate RTSP message-body */
+static rtsp_stream_result_e rtsp_message_body_generate(rtsp_message_t *message, apt_text_stream_t *stream, apr_pool_t *pool)
+{
+       if(rtsp_header_property_check(&message->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH) == TRUE) {
+               if(message->header.content_length) {
+                       apt_str_t *body = &message->body;
+                       body->length = 0;
+                       return rtsp_message_body_write(message,stream);
+               }
+       }
+       return RTSP_STREAM_MESSAGE_COMPLETE;
+}
+
+/** Create RTSP parser */
+RTSP_DECLARE(rtsp_parser_t*) rtsp_parser_create(apr_pool_t *pool)
+{
+       rtsp_parser_t *parser = apr_palloc(pool,sizeof(rtsp_parser_t));
+       parser->result = RTSP_STREAM_MESSAGE_INVALID;
+       parser->pos = NULL;
+       parser->skip_lf = FALSE;
+       parser->message = NULL;
+       parser->pool = pool;
+       return parser;
+}
+
+static rtsp_stream_result_e rtsp_parser_break(rtsp_parser_t *parser, apt_text_stream_t *stream)
+{
+       /* failed to parse either start-line or header */
+       if(apt_text_is_eos(stream) == TRUE) {
+               /* end of stream reached, rewind/restore stream */
+               stream->pos = parser->pos;
+               parser->result = RTSP_STREAM_MESSAGE_TRUNCATED;
+               parser->message = NULL;
+       }
+       else {
+               /* error case */
+               parser->result = RTSP_STREAM_MESSAGE_INVALID;
+       }
+       return parser->result;
+}
+
+/** Parse RTSP stream */
+RTSP_DECLARE(rtsp_stream_result_e) rtsp_parser_run(rtsp_parser_t *parser, apt_text_stream_t *stream)
+{
+       rtsp_message_t *message = parser->message;
+       if(message && parser->result == RTSP_STREAM_MESSAGE_TRUNCATED) {
+               /* process continuation data */
+               parser->result = rtsp_message_body_read(message,stream);
+               return parser->result;
+       }
+
+       /* create new RTSP message */
+       message = rtsp_message_create(RTSP_MESSAGE_TYPE_UNKNOWN,parser->pool);
+       parser->message = message;
+       /* store current position to be able to rewind/restore stream if needed */
+       parser->pos = stream->pos;
+       /* parse start-line */
+       if(rtsp_start_line_parse(&message->start_line,stream,message->pool) == FALSE) {
+               return rtsp_parser_break(parser,stream);
+       }
+       /* parse header */
+       if(rtsp_header_parse(&message->header,stream,message->pool) == FALSE) {
+               return rtsp_parser_break(parser,stream);
+       }
+       /* parse body */
+       parser->result = rtsp_message_body_parse(message,stream,message->pool);
+       
+       /* in the worst case message segmentation may occur between <CR> and <LF> 
+          of the final empty header */
+       if(!message->body.length && *(stream->pos-1)== APT_TOKEN_CR) {
+               /* if this is the case be prepared to skip <LF> */
+               parser->skip_lf = TRUE;
+       }
+       return parser->result;
+}
+
+/** Get parsed RTSP message */
+RTSP_DECLARE(rtsp_message_t*) rtsp_parser_message_get(const rtsp_parser_t *parser)
+{
+       return parser->message;
+}
+
+
+/** Create RTSP stream generator */
+RTSP_DECLARE(rtsp_generator_t*) rtsp_generator_create(apr_pool_t *pool)
+{
+       rtsp_generator_t *generator = apr_palloc(pool,sizeof(rtsp_generator_t));
+       generator->result = RTSP_STREAM_MESSAGE_INVALID;
+       generator->pos = NULL;
+       generator->message = NULL;
+       generator->pool = pool;
+       return generator;
+}
+
+/** Set RTSP message to generate */
+RTSP_DECLARE(apt_bool_t) rtsp_generator_message_set(rtsp_generator_t *generator, rtsp_message_t *message)
+{
+       if(!message) {
+               return FALSE;
+       }
+       generator->message = message;
+       return TRUE;
+}
+
+static rtsp_stream_result_e rtsp_generator_break(rtsp_generator_t *generator, apt_text_stream_t *stream)
+{
+       /* failed to generate either start-line or header */
+       if(apt_text_is_eos(stream) == TRUE) {
+               /* end of stream reached, rewind/restore stream */
+               stream->pos = generator->pos;
+               generator->result = RTSP_STREAM_MESSAGE_TRUNCATED;
+       }
+       else {
+               /* error case */
+               generator->result = RTSP_STREAM_MESSAGE_INVALID;
+       }
+       return generator->result;
+}
+
+/** Generate RTSP stream */
+RTSP_DECLARE(rtsp_stream_result_e) rtsp_generator_run(rtsp_generator_t *generator, apt_text_stream_t *stream)
+{
+       rtsp_message_t *message = generator->message;
+       if(!message) {
+               return RTSP_STREAM_MESSAGE_INVALID;
+       }
+
+       if(message && generator->result == RTSP_STREAM_MESSAGE_TRUNCATED) {
+               /* process continuation data */
+               generator->result = rtsp_message_body_write(message,stream);
+               return generator->result;
+       }
+
+       /* generate start-line */
+       if(rtsp_start_line_generate(&message->start_line,stream) == FALSE) {
+               return rtsp_generator_break(generator,stream);
+       }
+
+       /* generate header */
+       if(rtsp_header_generate(&message->header,stream) == FALSE) {
+               return rtsp_generator_break(generator,stream);
+       }
+
+       /* generate body */
+       generator->result = rtsp_message_body_generate(message,stream,message->pool);
+       return generator->result;
+}
+
+
+/** Walk through RTSP stream and invoke message handler for each parsed message */
+RTSP_DECLARE(apt_bool_t) rtsp_stream_walk(rtsp_parser_t *parser, apt_text_stream_t *stream, rtsp_message_handler_f handler, void *obj)
+{
+       rtsp_stream_result_e result;
+       if(parser->skip_lf == TRUE) {
+               /* skip <LF> occurred as a result of message segmentation between <CR> and <LF> */
+               apt_text_char_skip(stream,APT_TOKEN_LF);
+               parser->skip_lf = FALSE;
+       }
+       do {
+               result = rtsp_parser_run(parser,stream);
+               if(result == RTSP_STREAM_MESSAGE_COMPLETE) {
+                       /* message is completely parsed */
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Parsed RTSP Message [%lu]", stream->pos - stream->text.buf);
+                       /* invoke message handler */
+                       handler(obj,parser->message,result);
+               }
+               else if(result == RTSP_STREAM_MESSAGE_TRUNCATED) {
+                       /* message is partially parsed, to be continued */
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Truncated RTSP Message [%lu]", stream->pos - stream->text.buf);
+                       /* prepare stream for further processing */
+                       if(apt_text_stream_scroll(stream) == TRUE) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Scroll RTSP Stream", stream->text.buf);
+                       }
+                       return TRUE;
+               }
+               else if(result == RTSP_STREAM_MESSAGE_INVALID){
+                       /* error case */
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse RTSP Message");
+                       /* invoke message handler */
+                       handler(obj,parser->message,result);
+                       /* reset stream pos */
+                       stream->pos = stream->text.buf;
+                       return FALSE;
+               }
+       }
+       while(apt_text_is_eos(stream) == FALSE);
+
+       /* reset stream pos */
+       stream->pos = stream->text.buf;
+       return TRUE;
+}
diff --git a/libs/unimrcp/libs/uni-rtsp/unirtsp.vcproj b/libs/unimrcp/libs/uni-rtsp/unirtsp.vcproj
new file mode 100644 (file)
index 0000000..070bd0e
--- /dev/null
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="unirtsp"
+       ProjectGUID="{504B3154-7A4F-459D-9877-B951021C3F1F}"
+       RootNamespace="unirtsp"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\unirtsp.vsprops"
+                       CharacterSet="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="codecs"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\unirtsp.vsprops"
+                       CharacterSet="1"
+                       WholeProgramOptimization="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="codecs"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+                       <File
+                               RelativePath=".\include\rtsp.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\rtsp_client.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\rtsp_header.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\rtsp_message.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\rtsp_server.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\rtsp_start_line.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\rtsp_stream.h"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       >
+                       <File
+                               RelativePath=".\src\rtsp_client.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\rtsp_header.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\rtsp_message.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\rtsp_server.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\rtsp_start_line.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\rtsp_stream.c"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/modules/Makefile.am b/libs/unimrcp/modules/Makefile.am
new file mode 100644 (file)
index 0000000..7c5ba97
--- /dev/null
@@ -0,0 +1,3 @@
+MAINTAINERCLEANFILES   = Makefile.in
+
+SUBDIRS                = mrcp-sofiasip mrcp-unirtsp
diff --git a/libs/unimrcp/modules/mrcp-sofiasip/Makefile.am b/libs/unimrcp/modules/mrcp-sofiasip/Makefile.am
new file mode 100644 (file)
index 0000000..9bae7e3
--- /dev/null
@@ -0,0 +1,21 @@
+MAINTAINERCLEANFILES      = Makefile.in
+
+INCLUDES                   = -Iinclude \
+                             -I$(top_srcdir)/libs/mrcpv2-transport/include \
+                             -I$(top_srcdir)/libs/mrcp-signaling/include \
+                             -I$(top_srcdir)/libs/mrcp/include \
+                             -I$(top_srcdir)/libs/mrcp/message/include \
+                             -I$(top_srcdir)/libs/mrcp/control/include \
+                             -I$(top_srcdir)/libs/mrcp/resources/include \
+                             -I$(top_srcdir)/libs/mpf/include \
+                             -I$(top_srcdir)/libs/apr-toolkit/include \
+                             $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES) $(UNIMRCP_SOFIA_INCLUDES)
+
+noinst_LTLIBRARIES         = libmrcpsofiasip.la
+
+include_HEADERS            = include/mrcp_sdp.h \
+                             include/mrcp_sofiasip_server_agent.h \
+                             include/mrcp_sofiasip_client_agent.h
+libmrcpsofiasip_la_SOURCES = src/mrcp_sdp.c \
+                             src/mrcp_sofiasip_server_agent.c \
+                             src/mrcp_sofiasip_client_agent.c
diff --git a/libs/unimrcp/modules/mrcp-sofiasip/include/mrcp_sdp.h b/libs/unimrcp/modules/mrcp-sofiasip/include/mrcp_sdp.h
new file mode 100644 (file)
index 0000000..a7938c8
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_SDP_H__
+#define __MRCP_SDP_H__
+
+/**
+ * @file mrcp_sdp.h
+ * @brief MRCP SDP Transformations
+ */ 
+
+#include "mrcp_sig_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Generate SDP string by MRCP descriptor */
+MRCP_DECLARE(apr_size_t) sdp_string_generate_by_mrcp_descriptor(char *buffer, apr_size_t size, const mrcp_session_descriptor_t *descriptor, apt_bool_t offer);
+
+/** Generate MRCP descriptor by SDP session */
+MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_descriptor_generate_by_sdp_session(const sdp_session_t *sdp, const char *force_destination_ip, apr_pool_t *pool);
+
+/** Generate SDP resource discovery string */
+MRCP_DECLARE(apr_size_t) sdp_resource_discovery_string_generate(const char *ip, const char *origin, char *buffer, apr_size_t size);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_SDP_H__*/
diff --git a/libs/unimrcp/modules/mrcp-sofiasip/include/mrcp_sofiasip_client_agent.h b/libs/unimrcp/modules/mrcp-sofiasip/include/mrcp_sofiasip_client_agent.h
new file mode 100644 (file)
index 0000000..6505c76
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_SOFIASIP_CLIENT_AGENT_H__
+#define __MRCP_SOFIASIP_CLIENT_AGENT_H__
+
+/**
+ * @file mrcp_sofiasip_client_agent.h
+ * @brief Implementation of MRCP Signaling Interface using Sofia-SIP
+ */ 
+
+#include <apr_network_io.h>
+#include "mrcp_sig_agent.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Sofia-SIP config declaration */
+typedef struct mrcp_sofia_client_config_t mrcp_sofia_client_config_t;
+
+/** Sofia-SIP config */
+struct mrcp_sofia_client_config_t {
+       /** Local IP address */
+       char      *local_ip;
+       /** External (NAT) IP address */
+       char      *ext_ip;
+       /** Local SIP port */
+       apr_port_t local_port;
+       /** Local SIP user name */
+       char      *local_user_name;
+       
+       /** Remote IP address */
+       char      *remote_ip;
+       /** Remote SIP port */
+       apr_port_t remote_port;
+       /** Remote SIP user name */
+       char      *remote_user_name;
+
+       /** Force destination ip address. Should be used only in case 
+       SDP contains incorrect connection address (local IP address behind NAT) */
+       apt_bool_t force_destination;
+
+       /** User agent name */
+       char      *user_agent_name;
+       /** SDP origin */
+       char      *origin;
+       /** SIP transport */
+       char      *transport;
+};
+
+/**
+ * Create Sofia-SIP signaling agent.
+ */
+MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_sofiasip_client_agent_create(mrcp_sofia_client_config_t *config, apr_pool_t *pool);
+
+/**
+ * Allocate Sofia-SIP config.
+ */
+MRCP_DECLARE(mrcp_sofia_client_config_t*) mrcp_sofiasip_client_config_alloc(apr_pool_t *pool);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_SOFIASIP_CLIENT_AGENT_H__*/
diff --git a/libs/unimrcp/modules/mrcp-sofiasip/include/mrcp_sofiasip_server_agent.h b/libs/unimrcp/modules/mrcp-sofiasip/include/mrcp_sofiasip_server_agent.h
new file mode 100644 (file)
index 0000000..85bdea4
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_SOFIASIP_SERVER_AGENT_H__
+#define __MRCP_SOFIASIP_SERVER_AGENT_H__
+
+/**
+ * @file mrcp_sofiasip_server_agent.h
+ * @brief Implementation of MRCP Signaling Interface using Sofia-SIP
+ */ 
+
+#include <apr_network_io.h>
+#include "mrcp_sig_agent.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Sofia-SIP config declaration */
+typedef struct mrcp_sofia_server_config_t mrcp_sofia_server_config_t;
+
+/** Sofia-SIP config */
+struct mrcp_sofia_server_config_t {
+       /** Local IP address to bind to */
+       char      *local_ip;
+       /** External (NAT) IP address */
+       char      *ext_ip;
+       /** Local port to bind to */
+       apr_port_t local_port;
+
+       /** SIP user name */
+       char      *user_name;
+       /** User agent name */
+       char      *user_agent_name;
+       /** SDP origin */
+       char      *origin;
+       /** SIP transport */
+       char      *transport;
+
+       /** Force destination ip address. Should be used only in case 
+       SDP contains incorrect connection address (local IP address behind NAT) */
+       apt_bool_t force_destination;
+};
+
+/**
+ * Create Sofia-SIP signaling agent.
+ */
+MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_sofiasip_server_agent_create(mrcp_sofia_server_config_t *config, apr_pool_t *pool);
+
+/**
+ * Allocate Sofia-SIP config.
+ */
+MRCP_DECLARE(mrcp_sofia_server_config_t*) mrcp_sofiasip_server_config_alloc(apr_pool_t *pool);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_SOFIASIP_SERVER_AGENT_H__*/
diff --git a/libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.vcproj b/libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.vcproj
new file mode 100644 (file)
index 0000000..46c247f
--- /dev/null
@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="mrcpsofiasip"
+       ProjectGUID="{746F3632-5BB2-4570-9453-31D6D58A7D8E}"
+       RootNamespace="mrcpsofiasip"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\sofiasip.vsprops;$(SolutionDir)build\vsprops\mrcpv2transport.vsprops;$(SolutionDir)build\vsprops\mrcpsignaling.vsprops"
+                       CharacterSet="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="include"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\sofiasip.vsprops;$(SolutionDir)build\vsprops\mrcpv2transport.vsprops;$(SolutionDir)build\vsprops\mrcpsignaling.vsprops"
+                       CharacterSet="1"
+                       WholeProgramOptimization="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="include"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+                       <File
+                               RelativePath=".\include\mrcp_sdp.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_sofiasip_client_agent.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_sofiasip_server_agent.h"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       >
+                       <File
+                               RelativePath=".\src\mrcp_sdp.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\mrcp_sofiasip_client_agent.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\mrcp_sofiasip_server_agent.c"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/modules/mrcp-sofiasip/src/mrcp_sdp.c b/libs/unimrcp/modules/mrcp-sofiasip/src/mrcp_sdp.c
new file mode 100644 (file)
index 0000000..1cfed93
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <apr_general.h>
+#include <sofia-sip/sdp.h>
+#include "mrcp_sdp.h"
+#include "mrcp_session_descriptor.h"
+#include "mrcp_control_descriptor.h"
+#include "mpf_rtp_attribs.h"
+#include "apt_text_stream.h"
+#include "apt_log.h"
+
+static apr_size_t sdp_rtp_media_generate(char *buffer, apr_size_t size, const mrcp_session_descriptor_t *descriptor, const mpf_rtp_media_descriptor_t *audio_descriptor);
+static apr_size_t sdp_control_media_generate(char *buffer, apr_size_t size, const mrcp_session_descriptor_t *descriptor, const mrcp_control_descriptor_t *control_media, apt_bool_t offer);
+
+static apt_bool_t mpf_rtp_media_generate(mpf_rtp_media_descriptor_t *rtp_media, const sdp_media_t *sdp_media, const apt_str_t *ip, apr_pool_t *pool);
+static apt_bool_t mrcp_control_media_generate(mrcp_control_descriptor_t *mrcp_media, const sdp_media_t *sdp_media, const apt_str_t *ip, apr_pool_t *pool);
+
+/** Generate SDP string by MRCP descriptor */
+MRCP_DECLARE(apr_size_t) sdp_string_generate_by_mrcp_descriptor(char *buffer, apr_size_t size, const mrcp_session_descriptor_t *descriptor, apt_bool_t offer)
+{
+       apr_size_t i;
+       apr_size_t count;
+       apr_size_t audio_index = 0;
+       mpf_rtp_media_descriptor_t *audio_media;
+       apr_size_t video_index = 0;
+       mpf_rtp_media_descriptor_t *video_media;
+       apr_size_t control_index = 0;
+       mrcp_control_descriptor_t *control_media;
+       apr_size_t offset = 0;
+       const char *ip = descriptor->ext_ip.buf ? descriptor->ext_ip.buf : (descriptor->ip.buf ? descriptor->ip.buf : "0.0.0.0");
+       buffer[0] = '\0';
+       offset += snprintf(buffer+offset,size-offset,
+                       "v=0\r\n"
+                       "o=%s 0 0 IN IP4 %s\r\n"
+                       "s=-\r\n"
+                       "c=IN IP4 %s\r\n"
+                       "t=0 0\r\n",
+                       descriptor->origin.buf ? descriptor->origin.buf : "-",
+                       ip,
+                       ip);
+       count = mrcp_session_media_count_get(descriptor);
+       for(i=0; i<count; i++) {
+               audio_media = mrcp_session_audio_media_get(descriptor,audio_index);
+               if(audio_media && audio_media->base.id == i) {
+                       /* generate audio media */
+                       audio_index++;
+                       offset += sdp_rtp_media_generate(buffer+offset,size-offset,descriptor,audio_media);
+                       continue;
+               }
+               video_media = mrcp_session_video_media_get(descriptor,video_index);
+               if(video_media && video_media->base.id == i) {
+                       /* generate video media */
+                       video_index++;
+                       offset += sdp_rtp_media_generate(buffer+offset,size-offset,descriptor,video_media);
+                       continue;
+               }
+               control_media = mrcp_session_control_media_get(descriptor,control_index);
+               if(control_media && control_media->id == i) {
+                       /** generate mrcp control media */
+                       control_index++;
+                       offset += sdp_control_media_generate(buffer+offset,size-offset,descriptor,control_media,offer);
+                       continue;
+               }
+       }
+       return offset;
+}
+
+/** Generate MRCP descriptor by SDP session */
+MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_descriptor_generate_by_sdp_session(const sdp_session_t *sdp, const char *force_destination_ip, apr_pool_t *pool)
+{
+       sdp_media_t *sdp_media;
+       mrcp_session_descriptor_t *descriptor;
+
+       if(!sdp) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Invalid SDP Message");
+               return NULL;
+       }
+       
+       descriptor = mrcp_session_descriptor_create(pool);
+
+       if(force_destination_ip) {
+               apt_string_assign(&descriptor->ip,force_destination_ip,pool);
+       }
+       else if(sdp->sdp_connection) {
+               apt_string_assign(&descriptor->ip,sdp->sdp_connection->c_address,pool);
+       }
+
+       for(sdp_media=sdp->sdp_media; sdp_media; sdp_media=sdp_media->m_next) {
+               switch(sdp_media->m_type) {
+                       case sdp_media_audio:
+                       {
+                               mpf_rtp_media_descriptor_t *media = apr_palloc(pool,sizeof(mpf_rtp_media_descriptor_t));
+                               mpf_rtp_media_descriptor_init(media);
+                               media->base.id = mrcp_session_audio_media_add(descriptor,media);
+                               mpf_rtp_media_generate(media,sdp_media,&descriptor->ip,pool);
+                               break;
+                       }
+                       case sdp_media_video:
+                       {
+                               mpf_rtp_media_descriptor_t *media = apr_palloc(pool,sizeof(mpf_rtp_media_descriptor_t));
+                               mpf_rtp_media_descriptor_init(media);
+                               media->base.id = mrcp_session_video_media_add(descriptor,media);
+                               mpf_rtp_media_generate(media,sdp_media,&descriptor->ip,pool);
+                               break;
+                       }
+                       case sdp_media_application:
+                       {
+                               mrcp_control_descriptor_t *control_media = apr_palloc(pool,sizeof(mrcp_control_descriptor_t));
+                               mrcp_control_descriptor_init(control_media);
+                               control_media->id = mrcp_session_control_media_add(descriptor,control_media);
+                               mrcp_control_media_generate(control_media,sdp_media,&descriptor->ip,pool);
+                               break;
+                       }
+                       default:
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Not Supported SDP Media [%s]", sdp_media->m_type_name);
+                               break;
+               }
+       }
+       return descriptor;
+}
+
+
+/** Generate SDP media by RTP media descriptor */
+static apr_size_t sdp_rtp_media_generate(char *buffer, apr_size_t size, const mrcp_session_descriptor_t *descriptor, const mpf_rtp_media_descriptor_t *audio_media)
+{
+       apr_size_t offset = 0;
+       int i;
+       mpf_codec_descriptor_t *codec_descriptor;
+       apr_array_header_t *descriptor_arr = audio_media->codec_list.descriptor_arr;
+       if(!descriptor_arr) {
+               return 0;
+       }
+       offset += snprintf(buffer+offset,size-offset,
+               "m=audio %d RTP/AVP", 
+               audio_media->base.state == MPF_MEDIA_ENABLED ? audio_media->base.port : 0);
+       for(i=0; i<descriptor_arr->nelts; i++) {
+               codec_descriptor = (mpf_codec_descriptor_t*)descriptor_arr->elts + i;
+               if(codec_descriptor->enabled == TRUE) {
+                       offset += snprintf(buffer+offset,size-offset," %d", codec_descriptor->payload_type);
+               }
+       }
+       offset += snprintf(buffer+offset,size-offset,"\r\n");
+       if(descriptor->ip.length && audio_media->base.ip.length && 
+               apt_string_compare(&descriptor->ip,&audio_media->base.ip) != TRUE) {
+               const char *media_ip = audio_media->base.ext_ip.buf ? audio_media->base.ext_ip.buf : audio_media->base.ip.buf;
+               offset += sprintf(buffer+offset,"c=IN IP4 %s\r\n",media_ip);
+       }
+       if(audio_media->base.state == MPF_MEDIA_ENABLED) {
+               const apt_str_t *mode_str = mpf_stream_mode_str_get(audio_media->mode);
+               for(i=0; i<descriptor_arr->nelts; i++) {
+                       codec_descriptor = (mpf_codec_descriptor_t*)descriptor_arr->elts + i;
+                       if(codec_descriptor->enabled == TRUE && codec_descriptor->name.buf) {
+                               offset += snprintf(buffer+offset,size-offset,"a=rtpmap:%d %s/%d\r\n",
+                                       codec_descriptor->payload_type,
+                                       codec_descriptor->name.buf,
+                                       codec_descriptor->sampling_rate);
+                       }
+               }
+               offset += snprintf(buffer+offset,size-offset,"a=%s\r\n",mode_str ? mode_str->buf : "");
+               
+               if(audio_media->ptime) {
+                       offset += snprintf(buffer+offset,size-offset,"a=ptime:%hu\r\n",audio_media->ptime);
+               }
+       }
+       offset += snprintf(buffer+offset,size-offset,"a=mid:%d\r\n",audio_media->mid);
+       return offset;
+}
+
+/** Generate SDP media by MRCP control media descriptor */
+static apr_size_t sdp_control_media_generate(char *buffer, apr_size_t size, const mrcp_session_descriptor_t *descriptor, const mrcp_control_descriptor_t *control_media, apt_bool_t offer)
+{
+       apr_size_t offset = 0;
+       const apt_str_t *proto;
+       const apt_str_t *setup_type;
+       const apt_str_t *connection_type;
+       proto = mrcp_proto_get(control_media->proto);
+       setup_type = mrcp_setup_type_get(control_media->setup_type);
+       connection_type = mrcp_connection_type_get(control_media->connection_type);
+       if(offer == TRUE) { /* offer */
+               if(control_media->port) {
+                       offset += snprintf(buffer+offset,size-offset,
+                               "m=application %d %s 1\r\n"
+                               "a=setup:%s\r\n"
+                               "a=connection:%s\r\n"
+                               "a=resource:%s\r\n"
+                               "a=cmid:%d\r\n",
+                               control_media->port,
+                               proto ? proto->buf : "",
+                               setup_type ? setup_type->buf : "",
+                               connection_type ? connection_type->buf : "",
+                               control_media->resource_name.buf,
+                               control_media->cmid);
+               }
+               else {
+                       offset += snprintf(buffer+offset,size-offset,
+                               "m=application %d %s 1\r\n"
+                               "a=resource:%s\r\n"
+                               "a=cmid:%d\r\n",
+                               control_media->port,
+                               proto ? proto->buf : "",
+                               control_media->resource_name.buf,
+                               control_media->cmid);
+               }
+       }
+       else { /* answer */
+               if(control_media->port) {
+                       offset += sprintf(buffer+offset,
+                               "m=application %d %s 1\r\n"
+                               "a=setup:%s\r\n"
+                               "a=connection:%s\r\n"
+                               "a=channel:%s@%s\r\n"
+                               "a=cmid:%d\r\n",
+                               control_media->port,
+                               proto ? proto->buf : "",
+                               setup_type ? setup_type->buf : "",
+                               connection_type ? connection_type->buf : "",
+                               control_media->session_id.buf,
+                               control_media->resource_name.buf,
+                               control_media->cmid);
+               }
+               else {
+                       offset += sprintf(buffer+offset,
+                               "m=application %d %s 1\r\n"
+                               "a=channel:%s@%s\r\n"
+                               "a=cmid:%d\r\n",
+                               control_media->port,
+                               proto ? proto->buf : "",
+                               control_media->session_id.buf,
+                               control_media->resource_name.buf,
+                               control_media->cmid);
+               }
+       }
+
+       return offset;
+}
+
+/** Generate RTP media descriptor by SDP media */
+static apt_bool_t mpf_rtp_media_generate(mpf_rtp_media_descriptor_t *rtp_media, const sdp_media_t *sdp_media, const apt_str_t *ip, apr_pool_t *pool)
+{
+       mpf_rtp_attrib_e id;
+       apt_str_t name;
+       sdp_attribute_t *attrib = NULL;
+       sdp_rtpmap_t *map;
+       mpf_codec_descriptor_t *codec;
+       for(attrib = sdp_media->m_attributes; attrib; attrib=attrib->a_next) {
+               apt_string_set(&name,attrib->a_name);
+               id = mpf_rtp_attrib_id_find(&name);
+               switch(id) {
+                       case RTP_ATTRIB_MID:
+                               rtp_media->mid = atoi(attrib->a_value);
+                               break;
+                       case RTP_ATTRIB_PTIME:
+                               rtp_media->ptime = (apr_uint16_t)atoi(attrib->a_value);
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       mpf_codec_list_init(&rtp_media->codec_list,5,pool);
+       for(map = sdp_media->m_rtpmaps; map; map = map->rm_next) {
+               codec = mpf_codec_list_add(&rtp_media->codec_list);
+               if(codec) {
+                       codec->payload_type = (apr_byte_t)map->rm_pt;
+                       apt_string_assign(&codec->name,map->rm_encoding,pool);
+                       codec->sampling_rate = (apr_uint16_t)map->rm_rate;
+                       codec->channel_count = 1;
+               }
+       }
+
+       switch(sdp_media->m_mode) {
+               case sdp_inactive:
+                       rtp_media->mode = STREAM_MODE_NONE;
+                       break;
+               case sdp_sendonly:
+                       rtp_media->mode = STREAM_MODE_SEND;
+                       break;
+               case sdp_recvonly:
+                       rtp_media->mode = STREAM_MODE_RECEIVE;
+                       break;
+               case sdp_sendrecv:
+                       rtp_media->mode = STREAM_MODE_SEND_RECEIVE;
+                       break;
+       }
+
+       if(sdp_media->m_connections) {
+               apt_string_assign(&rtp_media->base.ip,sdp_media->m_connections->c_address,pool);
+       }
+       else {
+               rtp_media->base.ip = *ip;
+       }
+       if(sdp_media->m_port) {
+               rtp_media->base.port = (apr_port_t)sdp_media->m_port;
+               rtp_media->base.state = MPF_MEDIA_ENABLED;
+       }
+       else {
+               rtp_media->base.state = MPF_MEDIA_DISABLED;
+       }
+       return TRUE;
+}
+
+/** Generate MRCP control media by SDP media */
+static apt_bool_t mrcp_control_media_generate(mrcp_control_descriptor_t *control_media, const sdp_media_t *sdp_media, const apt_str_t *ip, apr_pool_t *pool)
+{
+       mrcp_attrib_e id;
+       apt_str_t name;
+       apt_str_t value;
+       sdp_attribute_t *attrib = NULL;
+       apt_string_set(&name,sdp_media->m_proto_name);
+       control_media->proto = mrcp_proto_find(&name);
+       if(control_media->proto != MRCP_PROTO_TCP) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Not supported SDP Proto [%s], expected [%s]",sdp_media->m_proto_name,mrcp_proto_get(MRCP_PROTO_TCP));
+               return FALSE;
+       }
+       
+       for(attrib = sdp_media->m_attributes; attrib; attrib=attrib->a_next) {
+               apt_string_set(&name,attrib->a_name);
+               id = mrcp_attrib_id_find(&name);
+               switch(id) {
+                       case MRCP_ATTRIB_SETUP:
+                               apt_string_set(&value,attrib->a_value);
+                               control_media->setup_type = mrcp_setup_type_find(&value);
+                               break;
+                       case MRCP_ATTRIB_CONNECTION:
+                               apt_string_set(&value,attrib->a_value);
+                               control_media->connection_type = mrcp_connection_type_find(&value);
+                               break;
+                       case MRCP_ATTRIB_RESOURCE:
+                               apt_string_assign(&control_media->resource_name,attrib->a_value,pool);
+                               break;
+                       case MRCP_ATTRIB_CHANNEL:
+                               apt_string_set(&value,attrib->a_value);
+                               apt_id_resource_parse(&value,'@',&control_media->session_id,&control_media->resource_name,pool);
+                               break;
+                       case MRCP_ATTRIB_CMID:
+                               control_media->cmid = atoi(attrib->a_value);
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       if(sdp_media->m_connections) {
+               apt_string_assign(&control_media->ip,sdp_media->m_connections->c_address,pool);
+       }
+       else {
+               control_media->ip = *ip;
+       }
+       control_media->port = (apr_port_t)sdp_media->m_port;
+       return TRUE;
+}
+
+/** Generate SDP resource discovery string */
+MRCP_DECLARE(apr_size_t) sdp_resource_discovery_string_generate(const char *ip, const char *origin, char *buffer, apr_size_t size)
+{
+       apr_size_t offset = 0;
+       if(!ip) {
+               ip = "0.0.0.0";
+       }
+       if(!origin) {
+               origin = "-";
+       }
+       buffer[0] = '\0';
+       offset += snprintf(buffer+offset,size-offset,
+                       "v=0\r\n"
+                       "o=%s 0 0 IN IP4 %s\r\n"
+                       "s=-\r\n"
+                       "c=IN IP4 %s\r\n"
+                       "t=0 0\r\n"
+                       "m=application 0 TCP/MRCPv2 1\r\n"
+                       "a=resource:speechsynth\r\n"
+                       "a=resource:speechrecog\r\n"
+                       "m=audio 0 RTP/AVP 0 8\r\n"
+                       "a=rtpmap:0 PCMU/8000\r\n"
+                       "a=rtpmap:8 PCMA/8000\r\n",
+                       origin,
+                       ip,
+                       ip);
+       return offset;
+}
diff --git a/libs/unimrcp/modules/mrcp-sofiasip/src/mrcp_sofiasip_client_agent.c b/libs/unimrcp/modules/mrcp-sofiasip/src/mrcp_sofiasip_client_agent.c
new file mode 100644 (file)
index 0000000..f193b0d
--- /dev/null
@@ -0,0 +1,528 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+typedef struct mrcp_sofia_agent_t mrcp_sofia_agent_t;
+#define NUA_MAGIC_T mrcp_sofia_agent_t
+
+typedef struct mrcp_sofia_session_t mrcp_sofia_session_t;
+#define NUA_HMAGIC_T mrcp_sofia_session_t
+
+#include <apr_general.h>
+#include <sofia-sip/su.h>
+#include <sofia-sip/nua.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/sdp.h>
+#include <sofia-sip/sofia_features.h>
+
+#include "mrcp_sofiasip_client_agent.h"
+#include "mrcp_session.h"
+#include "mrcp_session_descriptor.h"
+#include "mrcp_sdp.h"
+#include "apt_log.h"
+
+#define SOFIA_TASK_NAME "SofiaSIP Agent"
+
+struct mrcp_sofia_agent_t {
+       mrcp_sig_agent_t           *sig_agent;
+
+       mrcp_sofia_client_config_t *config;
+       char                       *sip_contact_str;
+       char                       *sip_to_str;
+       char                       *sip_from_str;
+       char                       *sip_bind_str;
+
+       su_root_t                  *root;
+       nua_t                      *nua;
+};
+
+struct mrcp_sofia_session_t {
+       mrcp_session_t     *session;
+       su_home_t          *home;
+       nua_handle_t       *nh;
+
+       apt_bool_t          terminate_requested;
+       apr_thread_mutex_t *mutex;
+};
+
+/* Task Interface */
+static void mrcp_sofia_task_initialize(apt_task_t *task);
+static apt_bool_t mrcp_sofia_task_run(apt_task_t *task);
+static apt_bool_t mrcp_sofia_task_terminate(apt_task_t *task);
+
+/* MRCP Signaling Interface */
+static apt_bool_t mrcp_sofia_session_offer(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor);
+static apt_bool_t mrcp_sofia_session_terminate_request(mrcp_session_t *session);
+static apt_bool_t mrcp_sofia_session_discover_request(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor);
+
+static const mrcp_session_request_vtable_t session_request_vtable = {
+       mrcp_sofia_session_offer,
+       mrcp_sofia_session_terminate_request,
+       NULL,
+       mrcp_sofia_session_discover_request
+};
+
+static apt_bool_t mrcp_sofia_config_validate(mrcp_sofia_agent_t *sofia_agent, mrcp_sofia_client_config_t *config, apr_pool_t *pool);
+static apt_bool_t mrcp_sofia_session_create(mrcp_session_t *session);
+
+static void mrcp_sofia_event_callback( nua_event_t           nua_event,
+                                                                          int                   status,
+                                                                          char const           *phrase,
+                                                                          nua_t                *nua,
+                                                                          mrcp_sofia_agent_t   *sofia_agent,
+                                                                          nua_handle_t         *nh,
+                                                                          mrcp_sofia_session_t *sofia_session,
+                                                                          sip_t const          *sip,
+                                                                          tagi_t                tags[]);
+
+
+/** Create Sofia-SIP Signaling Agent */
+MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_sofiasip_client_agent_create(mrcp_sofia_client_config_t *config, apr_pool_t *pool)
+{
+       apt_task_t *task;
+       apt_task_vtable_t *vtable;
+       mrcp_sofia_agent_t *sofia_agent;
+       sofia_agent = apr_palloc(pool,sizeof(mrcp_sofia_agent_t));
+       sofia_agent->sig_agent = mrcp_signaling_agent_create(sofia_agent,MRCP_VERSION_2,pool);
+       sofia_agent->sig_agent->create_client_session = mrcp_sofia_session_create;
+       sofia_agent->root = NULL;
+       sofia_agent->nua = NULL;
+
+       if(mrcp_sofia_config_validate(sofia_agent,config,pool) == FALSE) {
+               return NULL;
+       }
+
+       task = apt_task_create(sofia_agent,NULL,pool);
+       if(!task) {
+               return NULL;
+       }
+       apt_task_name_set(task,SOFIA_TASK_NAME);
+       vtable = apt_task_vtable_get(task);
+       if(vtable) {
+               vtable->on_pre_run = mrcp_sofia_task_initialize;
+               vtable->run = mrcp_sofia_task_run;
+               vtable->terminate = mrcp_sofia_task_terminate;
+       }
+       sofia_agent->sig_agent->task = task;
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create "SOFIA_TASK_NAME" ["SOFIA_SIP_VERSION"] %s:%hu -> %s:%hu %s",
+                       config->local_ip,config->local_port,
+                       config->remote_ip,config->remote_port,
+                       config->transport ? config->transport : "");
+       return sofia_agent->sig_agent;
+}
+
+/** Allocate Sofia-SIP config */
+MRCP_DECLARE(mrcp_sofia_client_config_t*) mrcp_sofiasip_client_config_alloc(apr_pool_t *pool)
+{
+       mrcp_sofia_client_config_t *config = apr_palloc(pool,sizeof(mrcp_sofia_client_config_t));
+       config->local_ip = NULL;
+       config->ext_ip = NULL;
+       config->local_port = 0;
+       config->local_user_name = NULL;
+       config->remote_ip = NULL;
+       config->remote_port = 0;
+       config->remote_user_name = NULL;
+
+       config->force_destination = FALSE;
+       
+       config->user_agent_name = NULL;
+       config->origin = NULL;
+       config->transport = NULL;
+       return config;
+}
+
+static apt_bool_t mrcp_sofia_config_validate(mrcp_sofia_agent_t *sofia_agent, mrcp_sofia_client_config_t *config, apr_pool_t *pool)
+{
+       const char *local_ip = config->ext_ip ? config->ext_ip : config->local_ip;
+       if(!config->local_ip || !config->remote_ip) {
+               return FALSE;
+       }
+
+       sofia_agent->config = config;
+       sofia_agent->sip_contact_str = apr_psprintf(pool,"sip:%s:%d", local_ip, config->local_port);
+       sofia_agent->sip_from_str = apr_psprintf(pool,"sip:%s:%d", local_ip, config->local_port);
+
+       if(config->remote_user_name && config->remote_user_name != '\0') {
+               sofia_agent->sip_to_str = apr_psprintf(pool,"sip:%s@%s:%d",
+                                                                               config->remote_user_name,
+                                                                               config->remote_ip,
+                                                                               config->remote_port);
+       }
+       else {
+               sofia_agent->sip_to_str = apr_psprintf(pool,"sip:%s:%d",
+                                                                               config->remote_ip,
+                                                                               config->remote_port);
+       }
+       if(config->transport) {
+               sofia_agent->sip_bind_str = apr_psprintf(pool,"sip:%s:%d;transport=%s",
+                                                                               config->local_ip,
+                                                                               config->local_port,
+                                                                               config->transport);
+       }
+       else {
+               sofia_agent->sip_bind_str = apr_psprintf(pool,"sip:%s:%d",
+                                                                               config->local_ip,
+                                                                               config->local_port);
+       }
+       return TRUE;
+}
+
+static void mrcp_sofia_task_initialize(apt_task_t *task)
+{
+       mrcp_sofia_agent_t *sofia_agent = apt_task_object_get(task);
+
+       /* Initialize Sofia-SIP library and create event loop */
+       su_init();
+       sofia_agent->root = su_root_create(NULL);
+
+       /* Create a user agent instance. The stack will call the 'event_callback()' 
+        * callback when events such as succesful registration to network, 
+        * an incoming call, etc, occur. 
+        */
+       sofia_agent->nua = nua_create(
+                                       sofia_agent->root,         /* Event loop */
+                                       mrcp_sofia_event_callback, /* Callback for processing events */
+                                       sofia_agent,               /* Additional data to pass to callback */
+                                       NUTAG_URL(sofia_agent->sip_bind_str), /* Address to bind to */
+                                       TAG_END());                /* Last tag should always finish the sequence */
+       if(sofia_agent->nua) {
+               nua_set_params(
+                                       sofia_agent->nua,
+                                       NUTAG_AUTOANSWER(0),
+                                       NUTAG_APPL_METHOD("OPTIONS"),
+                                       SIPTAG_USER_AGENT_STR(sofia_agent->config->user_agent_name),
+                                       TAG_END());
+       }
+}
+
+static apt_bool_t mrcp_sofia_task_run(apt_task_t *task)
+{
+       mrcp_sofia_agent_t *sofia_agent = apt_task_object_get(task);
+
+       if(sofia_agent->nua) {
+               /* Run event loop */
+               su_root_run(sofia_agent->root);
+               
+               /* Destroy allocated resources */
+               nua_destroy(sofia_agent->nua);
+               sofia_agent->nua = NULL;
+       }
+       su_root_destroy(sofia_agent->root);
+       sofia_agent->root = NULL;
+       su_deinit();
+
+       apt_task_child_terminate(task);
+       return TRUE;
+}
+
+static apt_bool_t mrcp_sofia_task_terminate(apt_task_t *task)
+{
+       mrcp_sofia_agent_t *sofia_agent = apt_task_object_get(task);
+       if(sofia_agent->nua) {
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Send Shutdown Signal to NUA");
+               nua_shutdown(sofia_agent->nua);
+       }
+       return TRUE;
+}
+
+static APR_INLINE mrcp_sofia_agent_t* mrcp_sofia_agent_get(mrcp_session_t *session)
+{
+       return session->signaling_agent->obj;
+}
+
+static apt_bool_t mrcp_sofia_session_create(mrcp_session_t *session)
+{
+       mrcp_sofia_agent_t *sofia_agent = mrcp_sofia_agent_get(session);
+       mrcp_sofia_session_t *sofia_session;
+       session->request_vtable = &session_request_vtable;
+
+       sofia_session = apr_palloc(session->pool,sizeof(mrcp_sofia_session_t));
+       sofia_session->mutex = NULL;
+       sofia_session->home = su_home_new(sizeof(*sofia_session->home));
+       sofia_session->session = session;
+       sofia_session->terminate_requested = FALSE;
+       session->obj = sofia_session;
+       
+       sofia_session->nh = nua_handle(
+                               sofia_agent->nua,
+                               sofia_session,
+                               SIPTAG_TO_STR(sofia_agent->sip_to_str),
+                               SIPTAG_FROM_STR(sofia_agent->sip_from_str),
+                               SIPTAG_CONTACT_STR(sofia_agent->sip_contact_str),
+                               TAG_END());
+
+       apr_thread_mutex_create(&sofia_session->mutex,APR_THREAD_MUTEX_DEFAULT,session->pool);
+       return TRUE;
+}
+
+static apt_bool_t mrcp_sofia_session_destroy(mrcp_sofia_session_t *sofia_session)
+{
+       if(sofia_session->mutex) {
+               apr_thread_mutex_destroy(sofia_session->mutex);
+               sofia_session->mutex = NULL;
+       }
+       if(sofia_session->home) {
+               su_home_unref(sofia_session->home);
+               sofia_session->home = NULL;
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_sofia_session_unref(mrcp_sofia_session_t *sofia_session)
+{
+       if(sofia_session->nh) {
+               nua_handle_bind(sofia_session->nh, NULL);
+               nua_handle_destroy(sofia_session->nh);
+               sofia_session->nh = NULL;
+       }
+       sofia_session->session = NULL;
+       return TRUE;
+}
+
+static apt_bool_t mrcp_sofia_session_offer(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor)
+{
+       char sdp_str[2048];
+       char *local_sdp_str = NULL;
+       apt_bool_t res = FALSE;
+       mrcp_sofia_session_t *sofia_session = session->obj;
+       if(!sofia_session) {
+               return FALSE;
+       }
+
+       if(session->signaling_agent) {
+               mrcp_sofia_agent_t *sofia_agent = mrcp_sofia_agent_get(session);
+               if(sofia_agent) {
+                       if(sofia_agent->config->origin) {
+                               apt_string_set(&descriptor->origin,sofia_agent->config->origin);
+                       }
+               }
+       }
+       if(sdp_string_generate_by_mrcp_descriptor(sdp_str,sizeof(sdp_str),descriptor,TRUE) > 0) {
+               local_sdp_str = sdp_str;
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Local SDP "APT_PTRSID_FMT"\n%s", 
+                       MRCP_SESSION_PTRSID(session), 
+                       local_sdp_str);
+       }
+
+       apr_thread_mutex_lock(sofia_session->mutex);
+
+       if(sofia_session->nh) {
+               res = TRUE;
+               nua_invite(sofia_session->nh,
+                               TAG_IF(local_sdp_str,SOATAG_USER_SDP_STR(local_sdp_str)),
+                               TAG_END());
+       }
+
+       apr_thread_mutex_unlock(sofia_session->mutex);
+       return res;
+}
+
+static apt_bool_t mrcp_sofia_session_terminate_request(mrcp_session_t *session)
+{
+       mrcp_sofia_session_t *sofia_session = session->obj;
+       if(!sofia_session) {
+               return FALSE;
+       }
+
+       sofia_session->terminate_requested = FALSE;
+       apr_thread_mutex_lock(sofia_session->mutex);
+       if(sofia_session->nh) {
+               sofia_session->terminate_requested = TRUE;
+               nua_bye(sofia_session->nh,TAG_END());
+       }
+       apr_thread_mutex_unlock(sofia_session->mutex);
+
+       if(sofia_session->terminate_requested == FALSE) {
+               mrcp_sofia_session_destroy(sofia_session);
+               mrcp_session_terminate_response(session);
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_sofia_session_discover_request(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor)
+{
+       apt_bool_t res = FALSE;
+       mrcp_sofia_session_t *sofia_session = session->obj;
+       if(!sofia_session) {
+               return FALSE;
+       }
+       
+       apr_thread_mutex_lock(sofia_session->mutex);
+       if(sofia_session->nh) {
+               res = TRUE;
+               nua_options(sofia_session->nh,TAG_END());
+       }
+       apr_thread_mutex_unlock(sofia_session->mutex);
+       return res;
+}
+
+static void mrcp_sofia_on_session_ready(
+                                               int                   status,
+                                               mrcp_sofia_agent_t   *sofia_agent,
+                                               nua_handle_t         *nh,
+                                               mrcp_sofia_session_t *sofia_session,
+                                               sip_t const          *sip,
+                                               tagi_t                tags[])
+{
+       mrcp_session_t *session = sofia_session->session;
+       if(session) {
+               const char *local_sdp_str = NULL, *remote_sdp_str = NULL;
+               mrcp_session_descriptor_t *descriptor = NULL;
+
+               tl_gets(tags, 
+                               SOATAG_LOCAL_SDP_STR_REF(local_sdp_str),
+                               SOATAG_REMOTE_SDP_STR_REF(remote_sdp_str),
+                               TAG_END());
+
+               if(remote_sdp_str) {
+                       sdp_parser_t *parser = NULL;
+                       sdp_session_t *sdp = NULL;
+                       const char *force_destination_ip = NULL;
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remote SDP "APT_PTRSID_FMT"\n%s",
+                               MRCP_SESSION_PTRSID(session),
+                               remote_sdp_str);
+
+                       parser = sdp_parse(sofia_session->home,remote_sdp_str,(int)strlen(remote_sdp_str),0);
+                       sdp = sdp_session(parser);
+                       if(sofia_agent && sofia_agent->config->force_destination == TRUE) {
+                               force_destination_ip = sofia_agent->config->remote_ip;
+                       }
+                       descriptor = mrcp_descriptor_generate_by_sdp_session(sdp,force_destination_ip,session->pool);
+                       sdp_parser_free(parser);
+               }
+
+               mrcp_session_answer(session,descriptor);
+       }
+}
+
+static void mrcp_sofia_on_session_terminate(
+                                               int                   status,
+                                               mrcp_sofia_agent_t   *sofia_agent,
+                                               nua_handle_t         *nh,
+                                               mrcp_sofia_session_t *sofia_session,
+                                               sip_t const          *sip,
+                                               tagi_t                tags[])
+{
+       mrcp_session_t *session = sofia_session->session;
+       if(session) {
+               apt_bool_t terminate_requested;
+       
+               apr_thread_mutex_lock(sofia_session->mutex);
+               terminate_requested = sofia_session->terminate_requested;
+               session = sofia_session->session;
+               mrcp_sofia_session_unref(sofia_session);
+               apr_thread_mutex_unlock(sofia_session->mutex);
+
+               if(terminate_requested == TRUE) {
+                       mrcp_sofia_session_destroy(sofia_session);
+                       mrcp_session_terminate_response(session);
+               }
+               else {
+                       mrcp_session_terminate_event(session);
+               }
+       }
+}
+
+static void mrcp_sofia_on_state_change(
+                                               int                   status,
+                                               mrcp_sofia_agent_t   *sofia_agent,
+                                               nua_handle_t         *nh,
+                                               mrcp_sofia_session_t *sofia_session,
+                                               sip_t const          *sip,
+                                               tagi_t                tags[])
+{
+       int ss_state = nua_callstate_init;
+       tl_gets(tags,
+                       NUTAG_CALLSTATE_REF(ss_state),
+                       TAG_END());
+       
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"SIP Call State "APT_PTR_FMT" [%s]",
+               sofia_session ? MRCP_SESSION_PTR(sofia_session->session) : NULL,
+               nua_callstate_name(ss_state));
+
+       switch(ss_state) {
+               case nua_callstate_ready:
+                       mrcp_sofia_on_session_ready(status,sofia_agent,nh,sofia_session,sip,tags);
+                       break;
+               case nua_callstate_terminated:
+                       mrcp_sofia_on_session_terminate(status,sofia_agent,nh,sofia_session,sip,tags);
+                       break;
+       }
+}
+
+static void mrcp_sofia_on_resource_discover(
+                                               int                   status,
+                                               mrcp_sofia_agent_t   *sofia_agent,
+                                               nua_handle_t         *nh,
+                                               mrcp_sofia_session_t *sofia_session,
+                                               sip_t const          *sip,
+                                               tagi_t                tags[])
+{
+       mrcp_session_t *session = sofia_session->session;
+       if(session) {
+               const char *remote_sdp_str = NULL;
+               mrcp_session_descriptor_t *descriptor = NULL;
+
+               tl_gets(tags, 
+                               SOATAG_REMOTE_SDP_STR_REF(remote_sdp_str),
+                               TAG_END());
+
+               if(remote_sdp_str) {
+                       sdp_parser_t *parser = NULL;
+                       sdp_session_t *sdp = NULL;
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Resource Discovery SDP "APT_PTR_FMT"\n%s", 
+                               MRCP_SESSION_PTR(session),
+                               remote_sdp_str);
+
+                       parser = sdp_parse(sofia_session->home,remote_sdp_str,(int)strlen(remote_sdp_str),0);
+                       sdp = sdp_session(parser);
+                       descriptor = mrcp_descriptor_generate_by_sdp_session(sdp,NULL,session->pool);
+                       sdp_parser_free(parser);
+               }
+
+               mrcp_session_discover_response(session,descriptor);
+       }
+}
+
+/** This callback will be called by SIP stack to process incoming events */
+static void mrcp_sofia_event_callback( 
+                                               nua_event_t           nua_event,
+                                               int                   status,
+                                               char const           *phrase,
+                                               nua_t                *nua,
+                                               mrcp_sofia_agent_t   *sofia_agent,
+                                               nua_handle_t         *nh,
+                                               mrcp_sofia_session_t *sofia_session,
+                                               sip_t const          *sip,
+                                               tagi_t                tags[])
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive SIP Event [%s] Status %d %s",
+               nua_event_name(nua_event),status,phrase);
+
+       switch(nua_event) {
+               case nua_i_state:
+                       mrcp_sofia_on_state_change(status,sofia_agent,nh,sofia_session,sip,tags);
+                       break;
+               case nua_r_options:
+                       mrcp_sofia_on_resource_discover(status,sofia_agent,nh,sofia_session,sip,tags);
+                       break;
+               case nua_r_shutdown:
+                       /* break main loop of sofia thread */
+                       su_root_break(sofia_agent->root);
+                       break;
+               default: 
+                       break;
+       }
+}
diff --git a/libs/unimrcp/modules/mrcp-sofiasip/src/mrcp_sofiasip_server_agent.c b/libs/unimrcp/modules/mrcp-sofiasip/src/mrcp_sofiasip_server_agent.c
new file mode 100644 (file)
index 0000000..0d0c16a
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+typedef struct mrcp_sofia_agent_t mrcp_sofia_agent_t;
+#define NUA_MAGIC_T mrcp_sofia_agent_t
+
+typedef struct mrcp_sofia_session_t mrcp_sofia_session_t;
+#define NUA_HMAGIC_T mrcp_sofia_session_t
+
+#include <apr_general.h>
+#include <sofia-sip/su.h>
+#include <sofia-sip/nua.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/sdp.h>
+#include <sofia-sip/sofia_features.h>
+
+#include "mrcp_sofiasip_server_agent.h"
+#include "mrcp_session.h"
+#include "mrcp_session_descriptor.h"
+#include "mrcp_sdp.h"
+#include "apt_log.h"
+
+#define SOFIA_TASK_NAME "SofiaSIP Agent"
+
+struct mrcp_sofia_agent_t {
+       mrcp_sig_agent_t           *sig_agent;
+
+       mrcp_sofia_server_config_t *config;
+       char                       *sip_contact_str;
+       char                       *sip_bind_str;
+
+       su_root_t                  *root;
+       nua_t                      *nua;
+};
+
+struct mrcp_sofia_session_t {
+       mrcp_session_t *session;
+       su_home_t      *home;
+       nua_handle_t   *nh;
+};
+
+/* Task Interface */
+static void mrcp_sofia_task_initialize(apt_task_t *task);
+static apt_bool_t mrcp_sofia_task_run(apt_task_t *task);
+static apt_bool_t mrcp_sofia_task_terminate(apt_task_t *task);
+
+/* MRCP Signaling Interface */
+static apt_bool_t mrcp_sofia_on_session_answer(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor);
+static apt_bool_t mrcp_sofia_on_session_terminate(mrcp_session_t *session);
+
+static const mrcp_session_response_vtable_t session_response_vtable = {
+       mrcp_sofia_on_session_answer,
+       mrcp_sofia_on_session_terminate
+};
+
+static apt_bool_t mrcp_sofia_config_validate(mrcp_sofia_agent_t *sofia_agent, mrcp_sofia_server_config_t *config, apr_pool_t *pool);
+
+static void mrcp_sofia_event_callback( nua_event_t           nua_event,
+                                                                          int                   status,
+                                                                          char const           *phrase,
+                                                                          nua_t                *nua,
+                                                                          mrcp_sofia_agent_t   *sofia_agent,
+                                                                          nua_handle_t         *nh,
+                                                                          mrcp_sofia_session_t *sofia_session,
+                                                                          sip_t const          *sip,
+                                                                          tagi_t                tags[]);
+
+
+/** Create Sofia-SIP Signaling Agent */
+MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_sofiasip_server_agent_create(mrcp_sofia_server_config_t *config, apr_pool_t *pool)
+{
+       apt_task_t *task;
+       apt_task_vtable_t *vtable;
+       mrcp_sofia_agent_t *sofia_agent;
+       sofia_agent = apr_palloc(pool,sizeof(mrcp_sofia_agent_t));
+       sofia_agent->sig_agent = mrcp_signaling_agent_create(sofia_agent,MRCP_VERSION_2,pool);
+       sofia_agent->config = config;
+       sofia_agent->root = NULL;
+       sofia_agent->nua = NULL;
+
+       if(mrcp_sofia_config_validate(sofia_agent,config,pool) == FALSE) {
+               return NULL;
+       }
+
+       task = apt_task_create(sofia_agent,NULL,pool);
+       if(!task) {
+               return NULL;
+       }
+       apt_task_name_set(task,SOFIA_TASK_NAME);
+       vtable = apt_task_vtable_get(task);
+       if(vtable) {
+               vtable->on_pre_run = mrcp_sofia_task_initialize;
+               vtable->run = mrcp_sofia_task_run;
+               vtable->terminate = mrcp_sofia_task_terminate;
+       }
+       sofia_agent->sig_agent->task = task;
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create "SOFIA_TASK_NAME" ["SOFIA_SIP_VERSION"] %s:%hu %s",
+                                                               config->local_ip,
+                                                               config->local_port,
+                                                               config->transport ? config->transport : "");
+       return sofia_agent->sig_agent;
+}
+
+/** Allocate Sofia-SIP config */
+MRCP_DECLARE(mrcp_sofia_server_config_t*) mrcp_sofiasip_server_config_alloc(apr_pool_t *pool)
+{
+       mrcp_sofia_server_config_t *config = apr_palloc(pool,sizeof(mrcp_sofia_server_config_t));
+       config->local_ip = NULL;
+       config->ext_ip = NULL;
+       config->local_port = 0;
+       config->user_name = NULL;
+       config->user_agent_name = NULL;
+       config->origin = NULL;
+       config->transport = NULL;
+       config->force_destination = FALSE;
+       return config;
+}
+
+static apt_bool_t mrcp_sofia_config_validate(mrcp_sofia_agent_t *sofia_agent, mrcp_sofia_server_config_t *config, apr_pool_t *pool)
+{
+       const char *local_ip = config->ext_ip ? config->ext_ip : config->local_ip;
+       sofia_agent->config = config;
+       sofia_agent->sip_contact_str = apr_psprintf(pool,"sip:%s:%d",local_ip,config->local_port);
+       if(config->transport) {
+               sofia_agent->sip_bind_str = apr_psprintf(pool,"sip:%s:%d;transport=%s",
+                                                                                       config->local_ip,
+                                                                                       config->local_port,
+                                                                                       config->transport);
+       }
+       else {
+               sofia_agent->sip_bind_str = apr_psprintf(pool,"sip:%s:%d",
+                                                                                       config->local_ip,
+                                                                                       config->local_port);
+       }
+       return TRUE;
+}
+
+static void mrcp_sofia_task_initialize(apt_task_t *task)
+{
+       mrcp_sofia_agent_t *sofia_agent = apt_task_object_get(task);
+
+       /* Initialize Sofia-SIP library and create event loop */
+       su_init();
+       sofia_agent->root = su_root_create(NULL);
+
+       /* Create a user agent instance. The stack will call the 'event_callback()' 
+        * callback when events such as succesful registration to network, 
+        * an incoming call, etc, occur. 
+        */
+       sofia_agent->nua = nua_create(
+                                       sofia_agent->root,         /* Event loop */
+                                       mrcp_sofia_event_callback, /* Callback for processing events */
+                                       sofia_agent,               /* Additional data to pass to callback */
+                                       NUTAG_URL(sofia_agent->sip_bind_str), /* Address to bind to */
+                                       TAG_END());                /* Last tag should always finish the sequence */
+       if(sofia_agent->nua) {
+               nua_set_params(
+                                       sofia_agent->nua,
+                                       NUTAG_AUTOANSWER(0),
+                                       NUTAG_APPL_METHOD("OPTIONS"),
+                                       SIPTAG_USER_AGENT_STR(sofia_agent->config->user_agent_name),
+                                       TAG_END());
+       }
+}
+
+static apt_bool_t mrcp_sofia_task_run(apt_task_t *task)
+{
+       mrcp_sofia_agent_t *sofia_agent = apt_task_object_get(task);
+
+       if(sofia_agent->nua) {
+               /* Run event loop */
+               su_root_run(sofia_agent->root);
+               
+               /* Destroy allocated resources */
+               nua_destroy(sofia_agent->nua);
+               sofia_agent->nua = NULL;
+       }
+       su_root_destroy(sofia_agent->root);
+       sofia_agent->root = NULL;
+       su_deinit();
+
+       apt_task_child_terminate(task);
+       return TRUE;
+}
+
+static apt_bool_t mrcp_sofia_task_terminate(apt_task_t *task)
+{
+       mrcp_sofia_agent_t *sofia_agent = apt_task_object_get(task);
+       if(sofia_agent->nua) {
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Send Shutdown Signal to NUA");
+               nua_shutdown(sofia_agent->nua);
+       }
+       return TRUE;
+}
+
+static mrcp_sofia_session_t* mrcp_sofia_session_create(mrcp_sofia_agent_t *sofia_agent, nua_handle_t *nh)
+{
+       mrcp_sofia_session_t *sofia_session;
+       mrcp_session_t* session = sofia_agent->sig_agent->create_server_session(sofia_agent->sig_agent);
+       if(!session) {
+               return NULL;
+       }
+       session->response_vtable = &session_response_vtable;
+       session->event_vtable = NULL;
+
+       sofia_session = apr_palloc(session->pool,sizeof(mrcp_sofia_session_t));
+       sofia_session->home = su_home_new(sizeof(*sofia_session->home));
+       sofia_session->session = session;
+       session->obj = sofia_session;
+       
+       nua_handle_bind(nh, sofia_session);
+       sofia_session->nh = nh;
+       return sofia_session;
+}
+
+static int sip_status_get(mrcp_session_status_e status)
+{
+       switch (status) {
+               case MRCP_SESSION_STATUS_OK:
+                       return 200;
+               case MRCP_SESSION_STATUS_NO_SUCH_RESOURCE:
+                       return 404;
+               case MRCP_SESSION_STATUS_UNACCEPTABLE_RESOURCE:
+                       return 406;
+               case MRCP_SESSION_STATUS_UNAVAILABLE_RESOURCE:
+                       return 480;
+               case MRCP_SESSION_STATUS_ERROR:
+                       return 500;
+       }
+       return 200;
+}
+
+static apt_bool_t mrcp_sofia_on_session_answer(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor)
+{
+       mrcp_sofia_session_t *sofia_session = session->obj;
+       mrcp_sofia_agent_t *sofia_agent = session->signaling_agent->obj;
+       const char *local_sdp_str = NULL;
+       char sdp_str[2048];
+
+       if(!sofia_agent || !sofia_session || !sofia_session->nh) {
+               return FALSE;
+       }
+
+       if(descriptor->status != MRCP_SESSION_STATUS_OK) {
+               int status = sip_status_get(descriptor->status);
+               nua_respond(sofia_session->nh, status, sip_status_phrase(status),
+                                       SIPTAG_CONTACT_STR(sofia_agent->sip_contact_str),
+                                       TAG_END());
+               return TRUE;
+       }
+
+       if(sofia_agent->config->origin) {
+               apt_string_set(&descriptor->origin,sofia_agent->config->origin);
+       }
+
+       if(sdp_string_generate_by_mrcp_descriptor(sdp_str,sizeof(sdp_str),descriptor,FALSE) > 0) {
+               local_sdp_str = sdp_str;
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Local SDP\n%s", local_sdp_str);
+       }
+
+       nua_respond(sofia_session->nh, SIP_200_OK, 
+                               SIPTAG_CONTACT_STR(sofia_agent->sip_contact_str),
+                               TAG_IF(local_sdp_str,SOATAG_USER_SDP_STR(local_sdp_str)),
+                           NUTAG_AUTOANSWER(0),
+                               TAG_END());
+       
+       return TRUE;
+}
+
+static apt_bool_t mrcp_sofia_on_session_terminate(mrcp_session_t *session)
+{
+       mrcp_sofia_session_t *sofia_session = session->obj;
+       if(sofia_session) {
+               if(sofia_session->nh) {
+                       nua_handle_bind(sofia_session->nh, NULL);
+                       nua_handle_destroy(sofia_session->nh);
+               }
+               if(sofia_session->home) {
+                       su_home_unref(sofia_session->home);
+                       sofia_session->home = NULL;
+               }
+               sofia_session->session = NULL;
+       }
+       
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy Session "APT_SID_FMT, MRCP_SESSION_SID(session));
+       mrcp_session_destroy(session);
+       return TRUE;
+}
+
+static void mrcp_sofia_on_call_receive(mrcp_sofia_agent_t   *sofia_agent,
+                                                                          nua_handle_t         *nh,
+                                                                          mrcp_sofia_session_t *sofia_session,
+                                                                          sip_t const          *sip,
+                                                                          tagi_t                tags[])
+{
+       int offer_recv = 0, answer_recv = 0, offer_sent = 0, answer_sent = 0;
+       const char *local_sdp_str = NULL, *remote_sdp_str = NULL;
+       mrcp_session_descriptor_t *descriptor = NULL;
+
+       tl_gets(tags, 
+                       NUTAG_OFFER_RECV_REF(offer_recv),
+                       NUTAG_ANSWER_RECV_REF(answer_recv),
+                       NUTAG_OFFER_SENT_REF(offer_sent),
+                       NUTAG_ANSWER_SENT_REF(answer_sent),
+                       SOATAG_LOCAL_SDP_STR_REF(local_sdp_str),
+                       SOATAG_REMOTE_SDP_STR_REF(remote_sdp_str),
+                       TAG_END());
+       
+       if(!sofia_session) {
+               sofia_session = mrcp_sofia_session_create(sofia_agent,nh);
+               if(!sofia_session) {
+                       nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
+                       return;
+               }
+       }
+
+       if(remote_sdp_str) {
+               sdp_parser_t *parser = NULL;
+               sdp_session_t *sdp = NULL;
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remote SDP\n%s", remote_sdp_str);
+
+               parser = sdp_parse(sofia_session->home,remote_sdp_str,(int)strlen(remote_sdp_str),0);
+               sdp = sdp_session(parser);              
+               descriptor = mrcp_descriptor_generate_by_sdp_session(sdp,NULL,sofia_session->session->pool);
+               sdp_parser_free(parser);
+       }
+
+       if(!descriptor) {
+               nua_respond(nh, SIP_400_BAD_REQUEST, TAG_END());
+               return;
+       }
+
+       mrcp_session_offer(sofia_session->session,descriptor);
+}
+
+static void mrcp_sofia_on_call_terminate(mrcp_sofia_agent_t          *sofia_agent,
+                                                                            nua_handle_t                *nh,
+                                                                            mrcp_sofia_session_t        *sofia_session,
+                                                                            sip_t const                 *sip,
+                                                                            tagi_t                       tags[])
+{
+       if(sofia_session) {
+               mrcp_session_terminate_request(sofia_session->session);
+       }
+}
+
+static void mrcp_sofia_on_state_change(mrcp_sofia_agent_t   *sofia_agent,
+                                                                          nua_handle_t         *nh,
+                                                                          mrcp_sofia_session_t *sofia_session,
+                                                                          sip_t const          *sip,
+                                                                          tagi_t                tags[])
+{
+       int ss_state = nua_callstate_init;
+       tl_gets(tags, 
+                       NUTAG_CALLSTATE_REF(ss_state),
+                       TAG_END()); 
+       
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"SIP Call State [%s]", nua_callstate_name(ss_state));
+
+       switch(ss_state) {
+               case nua_callstate_received:
+                       mrcp_sofia_on_call_receive(sofia_agent,nh,sofia_session,sip,tags);
+                       break;
+               case nua_callstate_terminated:
+                       mrcp_sofia_on_call_terminate(sofia_agent,nh,sofia_session,sip,tags);
+                       break;
+       }
+}
+
+static void mrcp_sofia_on_resource_discover(mrcp_sofia_agent_t   *sofia_agent,
+                                                                               nua_handle_t         *nh,
+                                                                               mrcp_sofia_session_t *sofia_session,
+                                                                               sip_t const          *sip,
+                                                                               tagi_t                tags[])
+{
+       char sdp_str[2048];
+       char *local_sdp_str = NULL;
+
+       const char *ip = sofia_agent->config->ext_ip ? 
+               sofia_agent->config->ext_ip : sofia_agent->config->local_ip;
+
+       if(sdp_resource_discovery_string_generate(ip,sofia_agent->config->origin,sdp_str,sizeof(sdp_str)) > 0) {
+               local_sdp_str = sdp_str;
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Resource Discovery SDP\n[%s]\n", local_sdp_str);
+       }
+
+       nua_respond(nh, SIP_200_OK, 
+                               NUTAG_WITH_CURRENT(sofia_agent->nua),
+                               SIPTAG_CONTACT_STR(sofia_agent->sip_contact_str),
+                               TAG_IF(local_sdp_str,SOATAG_USER_SDP_STR(local_sdp_str)),
+                               TAG_END());
+}
+
+/** This callback will be called by SIP stack to process incoming events */
+static void mrcp_sofia_event_callback( nua_event_t           nua_event,
+                                                                          int                   status,
+                                                                          char const           *phrase,
+                                                                          nua_t                *nua,
+                                                                          mrcp_sofia_agent_t   *sofia_agent,
+                                                                          nua_handle_t         *nh,
+                                                                          mrcp_sofia_session_t *sofia_session,
+                                                                          sip_t const          *sip,
+                                                                          tagi_t                tags[])
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive SIP Event [%s] Status %d %s",nua_event_name(nua_event),status,phrase);
+
+       switch(nua_event) {
+               case nua_i_state:
+                       mrcp_sofia_on_state_change(sofia_agent,nh,sofia_session,sip,tags);
+                       break;
+               case nua_i_options:
+                       mrcp_sofia_on_resource_discover(sofia_agent,nh,sofia_session,sip,tags);
+                       break;
+               case nua_r_shutdown:
+                       /* break main loop of sofia thread */
+                       su_root_break(sofia_agent->root);
+                       break;
+               default: 
+                       break;
+       }
+}
diff --git a/libs/unimrcp/modules/mrcp-unirtsp/Makefile.am b/libs/unimrcp/modules/mrcp-unirtsp/Makefile.am
new file mode 100644 (file)
index 0000000..ad7d54a
--- /dev/null
@@ -0,0 +1,22 @@
+MAINTAINERCLEANFILES      = Makefile.in
+
+INCLUDES                   = -Iinclude \
+                             -I$(top_srcdir)/libs/mrcp-signaling/include \
+                             -I$(top_srcdir)/libs/mrcp/include \
+                             -I$(top_srcdir)/libs/mrcp/message/include \
+                             -I$(top_srcdir)/libs/mrcp/control/include \
+                             -I$(top_srcdir)/libs/mrcp/resources/include \
+                             -I$(top_srcdir)/libs/mpf/include \
+                             -I$(top_srcdir)/libs/uni-rtsp/include \
+                             -I$(top_srcdir)/libs/apr-toolkit/include \
+                             $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES) $(UNIMRCP_SOFIA_INCLUDES)
+
+noinst_LTLIBRARIES         = libmrcpunirtsp.la
+
+include_HEADERS            = include/mrcp_unirtsp_sdp.h \
+                             include/mrcp_unirtsp_server_agent.h \
+                             include/mrcp_unirtsp_client_agent.h
+libmrcpunirtsp_la_SOURCES  = src/mrcp_unirtsp_sdp.c \
+                             src/mrcp_unirtsp_server_agent.c \
+                             src/mrcp_unirtsp_client_agent.c
+libmrcpunirtsp_la_LIBADD   = $(top_builddir)/libs/uni-rtsp/libunirtsp.la
diff --git a/libs/unimrcp/modules/mrcp-unirtsp/include/mrcp_unirtsp_client_agent.h b/libs/unimrcp/modules/mrcp-unirtsp/include/mrcp_unirtsp_client_agent.h
new file mode 100644 (file)
index 0000000..fc26929
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_UNIRTSP_CLIENT_AGENT_H__
+#define __MRCP_UNIRTSP_CLIENT_AGENT_H__
+
+/**
+ * @file mrcp_unirtsp_client_agent.h
+ * @brief Implementation of MRCP Signaling Interface using UniRTSP
+ */ 
+
+#include <apr_network_io.h>
+#include "apt_string.h"
+#include "mrcp_sig_agent.h"
+
+APT_BEGIN_EXTERN_C
+
+/** UniRTSP config declaration */
+typedef struct rtsp_client_config_t rtsp_client_config_t;
+
+/** UniRTSP config */
+struct rtsp_client_config_t {
+       /** Server IP address */
+       char        *server_ip;
+       /** Server port */
+       apr_port_t   server_port;
+       /** Resource location */
+       char        *resource_location;
+       /** SDP origin */
+       char        *origin;
+
+       /** Map of the MRCP resource names */
+       apr_table_t *resource_map;
+
+       /** Number of max RTSP connections */
+       apr_size_t   max_connection_count;
+
+       /** Force destination ip address. Should be used only in case 
+       SDP contains incorrect connection address (local IP address behind NAT) */
+       apt_bool_t force_destination;
+};
+
+/**
+ * Create UniRTSP signaling agent.
+ */
+MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_unirtsp_client_agent_create(rtsp_client_config_t *config, apr_pool_t *pool);
+
+/**
+ * Allocate UniRTSP config.
+ */
+MRCP_DECLARE(rtsp_client_config_t*) mrcp_unirtsp_client_config_alloc(apr_pool_t *pool);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_UNIRTSP_CLIENT_AGENT_H__*/
diff --git a/libs/unimrcp/modules/mrcp-unirtsp/include/mrcp_unirtsp_sdp.h b/libs/unimrcp/modules/mrcp-unirtsp/include/mrcp_unirtsp_sdp.h
new file mode 100644 (file)
index 0000000..59fbf64
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_UNIRTSP_SDP_H__
+#define __MRCP_UNIRTSP_SDP_H__
+
+/**
+ * @file mrcp_unirtsp_sdp.h
+ * @brief MRCP RTSP SDP Transformations
+ */ 
+
+#include "mrcp_session_descriptor.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Generate MRCP descriptor by RTSP request */
+MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_descriptor_generate_by_rtsp_request(
+                                                                                       const rtsp_message_t *request,
+                                                                                       const char *force_destination_ip,
+                                                                                       const apr_table_t *resource_map,
+                                                                                       apr_pool_t *pool,
+                                                                                       su_home_t *home);
+
+/** Generate MRCP descriptor by RTSP response */
+MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_descriptor_generate_by_rtsp_response(
+                                                                                       const rtsp_message_t *request,
+                                                                                       const rtsp_message_t *response,
+                                                                                       const char *force_destination_ip,
+                                                                                       const apr_table_t *resource_map,
+                                                                                       apr_pool_t *pool,
+                                                                                       su_home_t *home);
+
+/** Generate RTSP request by MRCP descriptor */
+MRCP_DECLARE(rtsp_message_t*) rtsp_request_generate_by_mrcp_descriptor(
+                                                                                       const mrcp_session_descriptor_t *descriptor, 
+                                                                                       const apr_table_t *resource_map, 
+                                                                                       apr_pool_t *pool);
+/** Generate RTSP response by MRCP descriptor */
+MRCP_DECLARE(rtsp_message_t*) rtsp_response_generate_by_mrcp_descriptor(
+                                                                                       const rtsp_message_t *request, 
+                                                                                       const mrcp_session_descriptor_t *descriptor, 
+                                                                                       const apr_table_t *resource_map, 
+                                                                                       apr_pool_t *pool);
+
+/** Generate RTSP resource discovery request */
+MRCP_DECLARE(rtsp_message_t*) rtsp_resource_discovery_request_generate(
+                                                                                       const char *resource_name,
+                                                                                       const apr_table_t *resource_map,
+                                                                                       apr_pool_t *pool);
+
+/** Generate resource descovery descriptor by RTSP response */
+MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_resource_discovery_response_generate(
+                                                                                       const rtsp_message_t *request, 
+                                                                                       const rtsp_message_t *response,
+                                                                                       const apr_table_t *resource_map,
+                                                                                       apr_pool_t *pool,
+                                                                                       su_home_t *home);
+
+/** Generate RTSP resource discovery response */
+MRCP_DECLARE(rtsp_message_t*) rtsp_resource_discovery_response_generate(
+                                                                                       const rtsp_message_t *request,
+                                                                                       const char *ip,
+                                                                                       const char *origin,
+                                                                                       apr_pool_t *pool);
+
+
+/** Get MRCP resource name by RTSP resource name */
+MRCP_DECLARE(const char*) mrcp_name_get_by_rtsp_name(const apr_table_t *resource_map, const char *rtsp_name);
+/** Get RTSP resource name by MRCP resource name */
+MRCP_DECLARE(const char*) rtsp_name_get_by_mrcp_name(const apr_table_t *resource_map, const char *mrcp_name);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_UNIRTSP_SDP_H__*/
diff --git a/libs/unimrcp/modules/mrcp-unirtsp/include/mrcp_unirtsp_server_agent.h b/libs/unimrcp/modules/mrcp-unirtsp/include/mrcp_unirtsp_server_agent.h
new file mode 100644 (file)
index 0000000..e117f2a
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MRCP_UNIRTSP_SERVER_AGENT_H__
+#define __MRCP_UNIRTSP_SERVER_AGENT_H__
+
+/**
+ * @file mrcp_unirtsp_server_agent.h
+ * @brief Implementation of MRCP Signaling Interface using UniRTSP
+ */ 
+
+#include <apr_network_io.h>
+#include "mrcp_sig_agent.h"
+
+APT_BEGIN_EXTERN_C
+
+/** UniRTSP config declaration */
+typedef struct rtsp_server_config_t rtsp_server_config_t;
+
+/** UniRTSP config */
+struct rtsp_server_config_t {
+       /** Local IP address to bind to */
+       char        *local_ip;
+       /** Local port to bind to */
+       apr_port_t   local_port;
+
+       /** Resource location */
+       char        *resource_location;
+       /** SDP origin */
+       char        *origin;
+
+       /** Map of the MRCP resource names */
+       apr_table_t *resource_map;
+
+       /** Number of max RTSP connections */
+       apr_size_t   max_connection_count;
+
+       /** Force destination ip address. Should be used only in case 
+       SDP contains incorrect connection address (local IP address behind NAT) */
+       apt_bool_t   force_destination;
+};
+
+/**
+ * Create UniRTSP signaling agent.
+ */
+MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_unirtsp_server_agent_create(rtsp_server_config_t *config, apr_pool_t *pool);
+
+/**
+ * Allocate UniRTSP config.
+ */
+MRCP_DECLARE(rtsp_server_config_t*) mrcp_unirtsp_server_config_alloc(apr_pool_t *pool);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_UNIRTSP_SERVER_AGENT_H__*/
diff --git a/libs/unimrcp/modules/mrcp-unirtsp/mrcpunirtsp.vcproj b/libs/unimrcp/modules/mrcp-unirtsp/mrcpunirtsp.vcproj
new file mode 100644 (file)
index 0000000..1d25d5a
--- /dev/null
@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="mrcpunirtsp"
+       ProjectGUID="{DEB01ACB-D65F-4A62-AED9-58C1054499E9}"
+       RootNamespace="mrcpunirtsp"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\mrcpsignaling.vsprops;$(SolutionDir)build\vsprops\unirtsp.vsprops;$(SolutionDir)build\vsprops\sofiasip.vsprops"
+                       CharacterSet="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="include"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\mrcpsignaling.vsprops;$(SolutionDir)build\vsprops\unirtsp.vsprops;$(SolutionDir)build\vsprops\sofiasip.vsprops"
+                       CharacterSet="1"
+                       WholeProgramOptimization="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="include"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+                       <File
+                               RelativePath=".\include\mrcp_unirtsp_client_agent.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_unirtsp_sdp.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_unirtsp_server_agent.h"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       >
+                       <File
+                               RelativePath=".\src\mrcp_unirtsp_client_agent.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\mrcp_unirtsp_sdp.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\mrcp_unirtsp_server_agent.c"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/modules/mrcp-unirtsp/src/mrcp_unirtsp_client_agent.c b/libs/unimrcp/modules/mrcp-unirtsp/src/mrcp_unirtsp_client_agent.c
new file mode 100644 (file)
index 0000000..85876f7
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_general.h>
+#include <sofia-sip/sdp.h>
+
+#include "mrcp_unirtsp_client_agent.h"
+#include "mrcp_session.h"
+#include "mrcp_session_descriptor.h"
+#include "mrcp_message.h"
+#include "mrcp_stream.h"
+#include "mrcp_resource_factory.h"
+#include "rtsp_client.h"
+#include "mrcp_unirtsp_sdp.h"
+#include "apt_consumer_task.h"
+#include "apt_log.h"
+
+#define UNIRTSP_TASK_NAME "UniRTSP Agent"
+
+typedef struct mrcp_unirtsp_agent_t mrcp_unirtsp_agent_t;
+typedef struct mrcp_unirtsp_session_t mrcp_unirtsp_session_t;
+
+struct mrcp_unirtsp_agent_t {
+       mrcp_sig_agent_t     *sig_agent;
+       rtsp_client_t        *rtsp_client;
+
+       rtsp_client_config_t *config;
+};
+
+struct mrcp_unirtsp_session_t {
+       mrcp_message_t        *mrcp_message;
+       mrcp_session_t        *mrcp_session;
+       rtsp_client_session_t *rtsp_session;
+       su_home_t             *home;
+};
+
+
+static apt_bool_t mrcp_unirtsp_session_offer(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor);
+static apt_bool_t mrcp_unirtsp_session_terminate(mrcp_session_t *session);
+static apt_bool_t mrcp_unirtsp_session_control(mrcp_session_t *session, mrcp_message_t *message);
+static apt_bool_t mrcp_unirtsp_resource_discover(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor);
+
+static const mrcp_session_request_vtable_t session_request_vtable = {
+       mrcp_unirtsp_session_offer,
+       mrcp_unirtsp_session_terminate,
+       mrcp_unirtsp_session_control,
+       mrcp_unirtsp_resource_discover
+};
+
+static apt_bool_t mrcp_unirtsp_on_session_terminate_response(rtsp_client_t *client, rtsp_client_session_t *session);
+static apt_bool_t mrcp_unirtsp_on_session_terminate_event(rtsp_client_t *client, rtsp_client_session_t *session);
+static apt_bool_t mrcp_unirtsp_on_session_response(rtsp_client_t *client, rtsp_client_session_t *session, rtsp_message_t *request, rtsp_message_t *response);
+static apt_bool_t mrcp_unirtsp_on_session_event(rtsp_client_t *client, rtsp_client_session_t *session, rtsp_message_t *message);
+
+static const rtsp_client_vtable_t session_response_vtable = {
+       mrcp_unirtsp_on_session_terminate_response,
+       mrcp_unirtsp_on_session_terminate_event,
+       mrcp_unirtsp_on_session_response,
+       mrcp_unirtsp_on_session_event
+};
+
+static apt_bool_t mrcp_unirtsp_session_create(mrcp_session_t *session);
+static apt_bool_t rtsp_config_validate(mrcp_unirtsp_agent_t *agent, rtsp_client_config_t *config, apr_pool_t *pool);
+static apt_bool_t mrcp_unirtsp_on_resource_discover(mrcp_unirtsp_agent_t *agent, mrcp_unirtsp_session_t *session, rtsp_message_t *request, rtsp_message_t *response);
+
+
+/** Create UniRTSP Signaling Agent */
+MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_unirtsp_client_agent_create(rtsp_client_config_t *config, apr_pool_t *pool)
+{
+       apt_task_t *task;
+       mrcp_unirtsp_agent_t *agent;
+       agent = apr_palloc(pool,sizeof(mrcp_unirtsp_agent_t));
+       agent->sig_agent = mrcp_signaling_agent_create(agent,MRCP_VERSION_1,pool);
+       agent->sig_agent->create_client_session = mrcp_unirtsp_session_create;
+       agent->config = config;
+
+       if(rtsp_config_validate(agent,config,pool) == FALSE) {
+               return NULL;
+       }
+
+       agent->rtsp_client = rtsp_client_create(config->max_connection_count,
+                                                                               agent,&session_response_vtable,pool);
+       if(!agent->rtsp_client) {
+               return NULL;
+       }
+
+       task = rtsp_client_task_get(agent->rtsp_client);
+       apt_task_name_set(task,UNIRTSP_TASK_NAME);
+       agent->sig_agent->task = task;
+
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create "UNIRTSP_TASK_NAME" %s:%hu [%d]",
+                                                               config->server_ip,
+                                                               config->server_port,
+                                                               config->max_connection_count);
+       return agent->sig_agent;
+}
+
+/** Allocate UniRTSP config */
+MRCP_DECLARE(rtsp_client_config_t*) mrcp_unirtsp_client_config_alloc(apr_pool_t *pool)
+{
+       rtsp_client_config_t *config = apr_palloc(pool,sizeof(rtsp_client_config_t));
+       config->server_ip = NULL;
+       config->server_port = 0;
+       config->resource_location = NULL;
+       config->origin = NULL;
+       config->resource_map = apr_table_make(pool,2);
+       config->max_connection_count = 100;
+       config->force_destination = FALSE;
+       return config;
+}
+
+
+static apt_bool_t rtsp_config_validate(mrcp_unirtsp_agent_t *agent, rtsp_client_config_t *config, apr_pool_t *pool)
+{
+       if(!config->server_ip) {
+               return FALSE;
+       }
+       agent->config = config;
+       return TRUE;
+}
+
+static APR_INLINE mrcp_unirtsp_agent_t* client_agent_get(apt_task_t *task)
+{
+       apt_consumer_task_t *consumer_task = apt_task_object_get(task);
+       mrcp_unirtsp_agent_t *agent = apt_consumer_task_object_get(consumer_task);
+       return agent;
+}
+
+static apt_bool_t mrcp_unirtsp_session_create(mrcp_session_t *mrcp_session)
+{
+       mrcp_unirtsp_agent_t *agent = mrcp_session->signaling_agent->obj;
+       mrcp_unirtsp_session_t *session;
+       mrcp_session->request_vtable = &session_request_vtable;
+
+       session = apr_palloc(mrcp_session->pool,sizeof(mrcp_unirtsp_session_t));
+       session->home = su_home_new(sizeof(*session->home));
+       session->mrcp_message = NULL;
+       session->mrcp_session = mrcp_session;
+       mrcp_session->obj = session;
+       
+       session->rtsp_session = rtsp_client_session_create(
+                                                                       agent->rtsp_client,
+                                                                       agent->config->server_ip,
+                                                                       agent->config->server_port,
+                                                                       agent->config->resource_location);
+       if(!session->rtsp_session) {
+               su_home_unref(session->home);
+               return FALSE;
+       }
+       rtsp_client_session_object_set(session->rtsp_session,session);
+       return TRUE;
+}
+
+static void mrcp_unirtsp_session_destroy(mrcp_unirtsp_session_t *session)
+{
+       if(session->home) {
+               su_home_unref(session->home);
+               session->home = NULL;
+       }
+       rtsp_client_session_object_set(session->rtsp_session,NULL);
+       rtsp_client_session_destroy(session->rtsp_session);
+}
+
+static apt_bool_t mrcp_unirtsp_on_session_terminate_response(rtsp_client_t *rtsp_client, rtsp_client_session_t *rtsp_session)
+{
+       mrcp_unirtsp_session_t *session = rtsp_client_session_object_get(rtsp_session);
+
+       mrcp_unirtsp_session_destroy(session);
+       mrcp_session_terminate_response(session->mrcp_session);
+       return TRUE;
+}
+
+static apt_bool_t mrcp_unirtsp_on_session_terminate_event(rtsp_client_t *rtsp_client, rtsp_client_session_t *rtsp_session)
+{
+       mrcp_unirtsp_session_t *session = rtsp_client_session_object_get(rtsp_session);
+       mrcp_session_terminate_event(session->mrcp_session);
+       return TRUE;
+}
+
+static apt_bool_t mrcp_unirtsp_on_announce_response(mrcp_unirtsp_agent_t *agent, mrcp_unirtsp_session_t *session, rtsp_message_t *message, const char *resource_name)
+{
+       mrcp_message_t *mrcp_message = NULL;
+
+       if(!session || !resource_name) {
+               return FALSE;
+       }
+       
+       if(rtsp_header_property_check(&message->header.property_set,RTSP_HEADER_FIELD_CONTENT_TYPE) == TRUE &&
+               message->header.content_type == RTSP_CONTENT_TYPE_MRCP &&
+               rtsp_header_property_check(&message->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH) == TRUE &&
+               message->header.content_length > 0) {
+
+               apt_text_stream_t text_stream;
+               mrcp_parser_t *parser;
+               apt_str_t resource_name_str;
+
+               text_stream.text = message->body;
+               text_stream.pos = text_stream.text.buf;
+               apt_string_set(&resource_name_str,resource_name);
+
+               parser = mrcp_parser_create(agent->sig_agent->resource_factory,session->mrcp_session->pool);
+               mrcp_parser_resource_name_set(parser,&resource_name_str);
+               if(mrcp_parser_run(parser,&text_stream) == MRCP_STREAM_MESSAGE_COMPLETE) {
+                       mrcp_message = mrcp_parser_message_get(parser);
+                       mrcp_message->channel_id.session_id = message->header.session_id;
+               }
+               else {
+                       /* error case */
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse MRCPv1 Message");
+               }
+       }
+       else {
+               /* error case */
+       }
+
+       if(!mrcp_message) {
+               if(!session->mrcp_message) {
+                       return FALSE;
+               }
+               mrcp_message = mrcp_response_create(session->mrcp_message,session->mrcp_session->pool);
+               mrcp_message->start_line.status_code = MRCP_STATUS_CODE_METHOD_FAILED;
+       }
+
+       session->mrcp_message = NULL;
+       mrcp_session_control_response(session->mrcp_session,mrcp_message);
+       return TRUE;
+}
+
+static apt_bool_t mrcp_unirtsp_on_session_response(rtsp_client_t *rtsp_client, rtsp_client_session_t *rtsp_session, rtsp_message_t *request, rtsp_message_t *response)
+{
+       apt_bool_t status = FALSE;
+       mrcp_unirtsp_agent_t *agent = rtsp_client_object_get(rtsp_client);
+       mrcp_unirtsp_session_t *session = rtsp_client_session_object_get(rtsp_session);
+       if(!agent || !session) {
+               return FALSE;
+       }
+
+       switch(request->start_line.common.request_line.method_id) {
+               case RTSP_METHOD_SETUP:
+               {
+                       const apt_str_t *session_id;
+                       const char *force_destination_ip = NULL;
+                       mrcp_session_descriptor_t *descriptor;
+
+                       if(agent->config->force_destination == TRUE) {
+                               force_destination_ip = agent->config->server_ip;
+                       }
+
+                       descriptor = mrcp_descriptor_generate_by_rtsp_response(
+                                                       request,
+                                                       response,
+                                                       force_destination_ip,
+                                                       agent->config->resource_map,
+                                                       session->mrcp_session->pool,
+                                                       session->home);
+                       if(!descriptor) {
+                               return FALSE;
+                       }
+                       session_id = rtsp_client_session_id_get(session->rtsp_session);
+                       if(session_id) {
+                               apt_string_copy(
+                                       &session->mrcp_session->id,
+                                       session_id,
+                                       session->mrcp_session->pool);
+                       }
+                       status = mrcp_session_answer(session->mrcp_session,descriptor);
+                       break;
+               }
+               case RTSP_METHOD_TEARDOWN:
+               {
+                       mrcp_session_descriptor_t *descriptor;
+                       descriptor = mrcp_descriptor_generate_by_rtsp_response(
+                                                       request,
+                                                       response,
+                                                       NULL,
+                                                       agent->config->resource_map,
+                                                       session->mrcp_session->pool,
+                                                       session->home);
+                       if(!descriptor) {
+                               return FALSE;
+                       }
+                       status = mrcp_session_answer(session->mrcp_session,descriptor);
+                       break;
+               }
+               case RTSP_METHOD_ANNOUNCE:
+               {
+                       mrcp_unirtsp_agent_t *agent = rtsp_client_object_get(rtsp_client);
+                       const char *resource_name = mrcp_name_get_by_rtsp_name(
+                               agent->config->resource_map,
+                               request->start_line.common.request_line.resource_name);
+                       mrcp_unirtsp_on_announce_response(agent,session,response,resource_name);
+                       break;
+               }
+               case RTSP_METHOD_DESCRIBE:
+               {
+                       mrcp_unirtsp_agent_t *agent = rtsp_client_object_get(rtsp_client);
+                       mrcp_unirtsp_on_resource_discover(agent,session,request,response);
+                       break;
+               }
+               default:
+                       break;
+       }
+
+       return status;
+}
+
+static apt_bool_t mrcp_unirtsp_on_session_event(rtsp_client_t *rtsp_client, rtsp_client_session_t *rtsp_session, rtsp_message_t *message)
+{
+       mrcp_unirtsp_agent_t *agent = rtsp_client_object_get(rtsp_client);
+       mrcp_unirtsp_session_t *session = rtsp_client_session_object_get(rtsp_session);
+       const char *resource_name = mrcp_name_get_by_rtsp_name(
+               agent->config->resource_map,
+               message->start_line.common.request_line.resource_name);
+       if(!session || !resource_name) {
+               return FALSE;
+       }
+
+       mrcp_unirtsp_on_announce_response(agent,session,message,resource_name);
+       return TRUE;
+}
+
+static apt_bool_t mrcp_unirtsp_session_offer(mrcp_session_t *mrcp_session, mrcp_session_descriptor_t *descriptor)
+{
+       mrcp_unirtsp_session_t *session = mrcp_session->obj;
+       mrcp_unirtsp_agent_t *agent = mrcp_session->signaling_agent->obj;
+       rtsp_message_t *request;
+
+       if(agent->config->origin) {
+               apt_string_set(&descriptor->origin,agent->config->origin);
+       }
+
+       request = rtsp_request_generate_by_mrcp_descriptor(descriptor,agent->config->resource_map,mrcp_session->pool);
+       return rtsp_client_session_request(agent->rtsp_client,session->rtsp_session,request);
+}
+
+static apt_bool_t mrcp_unirtsp_session_terminate(mrcp_session_t *mrcp_session)
+{
+       mrcp_unirtsp_session_t *session = mrcp_session->obj;
+       mrcp_unirtsp_agent_t *agent = mrcp_session->signaling_agent->obj;
+
+       return rtsp_client_session_terminate(agent->rtsp_client,session->rtsp_session);
+}
+
+static apt_bool_t mrcp_unirtsp_session_control(mrcp_session_t *mrcp_session, mrcp_message_t *mrcp_message)
+{
+       mrcp_unirtsp_session_t *session = mrcp_session->obj;
+       mrcp_unirtsp_agent_t *agent = mrcp_session->signaling_agent->obj;
+
+       char buffer[500];
+       apt_text_stream_t stream;
+       rtsp_message_t *rtsp_message = NULL;
+       apt_str_t *body;
+
+       apt_text_stream_init(&stream,buffer,sizeof(buffer));
+
+       mrcp_message->start_line.version = MRCP_VERSION_1;
+       if(mrcp_message_generate(agent->sig_agent->resource_factory,mrcp_message,&stream) != TRUE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Generate MRCPv1 Message");
+               return FALSE;
+       }
+       stream.text.length = stream.pos - stream.text.buf;
+
+       rtsp_message = rtsp_request_create(mrcp_session->pool);
+       rtsp_message->start_line.common.request_line.resource_name = rtsp_name_get_by_mrcp_name(
+                                                                       agent->config->resource_map,
+                                                                       mrcp_message->channel_id.resource_name.buf);
+       rtsp_message->start_line.common.request_line.method_id = RTSP_METHOD_ANNOUNCE;
+
+       body = &rtsp_message->body;
+       body->length = mrcp_message->start_line.length;
+       body->buf = apr_palloc(rtsp_message->pool,body->length+1);
+       memcpy(body->buf,stream.text.buf,stream.text.length);
+       if(mrcp_message->body.length) {
+               memcpy(body->buf+stream.text.length,mrcp_message->body.buf,mrcp_message->body.length);
+       }
+       body->buf[body->length] = '\0';
+
+       rtsp_message->header.content_type = RTSP_CONTENT_TYPE_MRCP;
+       rtsp_header_property_add(&rtsp_message->header.property_set,RTSP_HEADER_FIELD_CONTENT_TYPE);
+       rtsp_message->header.content_length = body->length;
+       rtsp_header_property_add(&rtsp_message->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH);
+
+       session->mrcp_message = mrcp_message;
+       rtsp_client_session_request(agent->rtsp_client,session->rtsp_session,rtsp_message);
+       return TRUE;
+}
+
+static apt_bool_t mrcp_unirtsp_resource_discover(mrcp_session_t *mrcp_session, mrcp_session_descriptor_t *descriptor)
+{
+       mrcp_unirtsp_session_t *session = mrcp_session->obj;
+       mrcp_unirtsp_agent_t *agent = mrcp_session->signaling_agent->obj;
+       rtsp_message_t *request;
+
+       if(!descriptor) {
+               return FALSE;
+       }
+       request = rtsp_resource_discovery_request_generate(
+                                                       descriptor->resource_name.buf,
+                                                       agent->config->resource_map,
+                                                       mrcp_session->pool);
+       if(request) {
+               rtsp_client_session_request(agent->rtsp_client,session->rtsp_session,request);
+       }
+       return TRUE;
+}
+
+static apt_bool_t mrcp_unirtsp_on_resource_discover(mrcp_unirtsp_agent_t *agent, mrcp_unirtsp_session_t *session, rtsp_message_t *request, rtsp_message_t *response)
+{
+       mrcp_session_descriptor_t *descriptor;
+       if(!session) {
+               return FALSE;
+       }
+
+       descriptor = mrcp_resource_discovery_response_generate(
+                                                                       request,
+                                                                       response,
+                                                                       agent->config->resource_map,
+                                                                       session->mrcp_session->pool,
+                                                                       session->home);
+       if(descriptor) {
+               mrcp_session_discover_response(session->mrcp_session,descriptor);
+       }
+       return TRUE;
+}
diff --git a/libs/unimrcp/modules/mrcp-unirtsp/src/mrcp_unirtsp_sdp.c b/libs/unimrcp/modules/mrcp-unirtsp/src/mrcp_unirtsp_sdp.c
new file mode 100644 (file)
index 0000000..fc33c94
--- /dev/null
@@ -0,0 +1,576 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_general.h>
+#include <sofia-sip/sdp.h>
+#include "rtsp_message.h"
+#include "mrcp_unirtsp_sdp.h"
+#include "mpf_rtp_attribs.h"
+#include "apt_text_stream.h"
+#include "apt_log.h"
+
+
+/** Generate SDP media by RTP media descriptor */
+static apr_size_t sdp_rtp_media_generate(char *buffer, apr_size_t size, const mrcp_session_descriptor_t *descriptor, const mpf_rtp_media_descriptor_t *audio_media)
+{
+       apr_size_t offset = 0;
+       int i;
+       mpf_codec_descriptor_t *codec_descriptor;
+       apr_array_header_t *descriptor_arr = audio_media->codec_list.descriptor_arr;
+       if(!descriptor_arr) {
+               return 0;
+       }
+       offset += snprintf(buffer+offset,size-offset,
+               "m=audio %d RTP/AVP", 
+               audio_media->base.state == MPF_MEDIA_ENABLED ? audio_media->base.port : 0);
+       for(i=0; i<descriptor_arr->nelts; i++) {
+               codec_descriptor = (mpf_codec_descriptor_t*)descriptor_arr->elts + i;
+               if(codec_descriptor->enabled == TRUE) {
+                       offset += snprintf(buffer+offset,size-offset," %d", codec_descriptor->payload_type);
+               }
+       }
+       offset += snprintf(buffer+offset,size-offset,"\r\n");
+       if(audio_media->base.state == MPF_MEDIA_ENABLED) {
+               const apt_str_t *mode_str = mpf_stream_mode_str_get(audio_media->mode);
+               for(i=0; i<descriptor_arr->nelts; i++) {
+                       codec_descriptor = (mpf_codec_descriptor_t*)descriptor_arr->elts + i;
+                       if(codec_descriptor->enabled == TRUE && codec_descriptor->name.buf) {
+                               offset += snprintf(buffer+offset,size-offset,"a=rtpmap:%d %s/%d\r\n",
+                                       codec_descriptor->payload_type,
+                                       codec_descriptor->name.buf,
+                                       codec_descriptor->sampling_rate);
+                       }
+               }
+               offset += snprintf(buffer+offset,size-offset,"a=%s\r\n",mode_str ? mode_str->buf : "");
+               
+               if(audio_media->ptime) {
+                       offset += snprintf(buffer+offset,size-offset,"a=ptime:%hu\r\n",
+                               audio_media->ptime);
+               }
+       }
+       return offset;
+}
+
+/** Generate RTP media descriptor by SDP media */
+static apt_bool_t mpf_rtp_media_generate(mpf_rtp_media_descriptor_t *rtp_media, const sdp_media_t *sdp_media, const apt_str_t *ip, apr_pool_t *pool)
+{
+       mpf_rtp_attrib_e id;
+       apt_str_t name;
+       sdp_attribute_t *attrib = NULL;
+       sdp_rtpmap_t *map;
+       mpf_codec_descriptor_t *codec;
+       for(attrib = sdp_media->m_attributes; attrib; attrib=attrib->a_next) {
+               apt_string_set(&name,attrib->a_name);
+               id = mpf_rtp_attrib_id_find(&name);
+               switch(id) {
+                       case RTP_ATTRIB_PTIME:
+                               rtp_media->ptime = (apr_uint16_t)atoi(attrib->a_value);
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       mpf_codec_list_init(&rtp_media->codec_list,5,pool);
+       for(map = sdp_media->m_rtpmaps; map; map = map->rm_next) {
+               codec = mpf_codec_list_add(&rtp_media->codec_list);
+               if(codec) {
+                       codec->payload_type = (apr_byte_t)map->rm_pt;
+                       apt_string_assign(&codec->name,map->rm_encoding,pool);
+                       codec->sampling_rate = (apr_uint16_t)map->rm_rate;
+                       codec->channel_count = 1;
+               }
+       }
+
+       switch(sdp_media->m_mode) {
+               case sdp_inactive:
+                       rtp_media->mode = STREAM_MODE_NONE;
+                       break;
+               case sdp_sendonly:
+                       rtp_media->mode = STREAM_MODE_SEND;
+                       break;
+               case sdp_recvonly:
+                       rtp_media->mode = STREAM_MODE_RECEIVE;
+                       break;
+               case sdp_sendrecv:
+                       rtp_media->mode = STREAM_MODE_SEND_RECEIVE;
+                       break;
+       }
+
+       if(sdp_media->m_connections) {
+               apt_string_assign(&rtp_media->base.ip,sdp_media->m_connections->c_address,pool);
+       }
+       else {
+               rtp_media->base.ip = *ip;
+       }
+       if(sdp_media->m_port) {
+               rtp_media->base.port = (apr_port_t)sdp_media->m_port;
+               rtp_media->base.state = MPF_MEDIA_ENABLED;
+       }
+       else {
+               rtp_media->base.state = MPF_MEDIA_DISABLED;
+       }
+       return TRUE;
+}
+
+/** Generate MRCP descriptor by SDP session */
+static mrcp_session_descriptor_t* mrcp_descriptor_generate_by_sdp_session(mrcp_session_descriptor_t *descriptor, const sdp_session_t *sdp, const char *force_destination_ip, apr_pool_t *pool)
+{
+       sdp_media_t *sdp_media;
+
+       if(force_destination_ip) {
+               apt_string_assign(&descriptor->ip,force_destination_ip,pool);
+       }
+       else if(sdp->sdp_connection) {
+               apt_string_assign(&descriptor->ip,sdp->sdp_connection->c_address,pool);
+       }
+
+       for(sdp_media=sdp->sdp_media; sdp_media; sdp_media=sdp_media->m_next) {
+               switch(sdp_media->m_type) {
+                       case sdp_media_audio:
+                       {
+                               mpf_rtp_media_descriptor_t *media = apr_palloc(pool,sizeof(mpf_rtp_media_descriptor_t));
+                               mpf_rtp_media_descriptor_init(media);
+                               media->base.id = mrcp_session_audio_media_add(descriptor,media);
+                               mpf_rtp_media_generate(media,sdp_media,&descriptor->ip,pool);
+                               break;
+                       }
+                       case sdp_media_video:
+                       {
+                               mpf_rtp_media_descriptor_t *media = apr_palloc(pool,sizeof(mpf_rtp_media_descriptor_t));
+                               mpf_rtp_media_descriptor_init(media);
+                               media->base.id = mrcp_session_video_media_add(descriptor,media);
+                               mpf_rtp_media_generate(media,sdp_media,&descriptor->ip,pool);
+                               break;
+                       }
+                       default:
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Not Supported SDP Media [%s]", sdp_media->m_type_name);
+                               break;
+               }
+       }
+       return descriptor;
+}
+
+
+/** Generate MRCP descriptor by RTSP request */
+MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_descriptor_generate_by_rtsp_request(
+                                                                                       const rtsp_message_t *request,
+                                                                                       const char *force_destination_ip,
+                                                                                       const apr_table_t *resource_map,
+                                                                                       apr_pool_t *pool,
+                                                                                       su_home_t *home)
+{
+       mrcp_session_descriptor_t *descriptor = NULL;
+       const char *resource_name = mrcp_name_get_by_rtsp_name(
+               resource_map,
+               request->start_line.common.request_line.resource_name);
+       if(!resource_name) {
+               return NULL;
+       }
+       
+       if(request->start_line.common.request_line.method_id == RTSP_METHOD_SETUP) {
+               if(rtsp_header_property_check(&request->header.property_set,RTSP_HEADER_FIELD_CONTENT_TYPE) == TRUE &&
+                       rtsp_header_property_check(&request->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH) == TRUE &&
+                       request->body.buf) {
+                       
+                       sdp_parser_t *parser;
+                       sdp_session_t *sdp;
+
+                       parser = sdp_parse(home,request->body.buf,request->body.length,0);
+                       sdp = sdp_session(parser);
+                       if(sdp) {
+                               descriptor = mrcp_session_descriptor_create(pool);
+                               mrcp_descriptor_generate_by_sdp_session(descriptor,sdp,force_destination_ip,pool);
+                       }
+                       else {
+                               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse SDP Message");
+                       }
+                       sdp_parser_free(parser);
+               }
+               else {
+                       /* create default descriptor in case RTSP SETUP contains no SDP */
+                       mpf_rtp_media_descriptor_t *media;
+                       descriptor = mrcp_session_descriptor_create(pool);
+                       media = apr_palloc(pool,sizeof(mpf_rtp_media_descriptor_t));
+                       mpf_rtp_media_descriptor_init(media);
+                       media->base.state = MPF_MEDIA_ENABLED;
+                       media->base.id = mrcp_session_audio_media_add(descriptor,media);
+                       if(rtsp_header_property_check(&request->header.property_set,RTSP_HEADER_FIELD_TRANSPORT) == TRUE) {
+                               media->base.port = request->header.transport.client_port_range.min;
+                               media->base.ip = request->header.transport.destination;
+                       }
+               }
+
+               if(descriptor) {
+                       apt_string_assign(&descriptor->resource_name,resource_name,pool);
+                       descriptor->resource_state = TRUE;
+               }
+       }
+       else if(request->start_line.common.request_line.method_id == RTSP_METHOD_TEARDOWN) {
+               descriptor = mrcp_session_descriptor_create(pool);
+               apt_string_assign(&descriptor->resource_name,resource_name,pool);
+               descriptor->resource_state = FALSE;
+       }
+       return descriptor;
+}
+
+/** Generate MRCP descriptor by RTSP response */
+MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_descriptor_generate_by_rtsp_response(
+                                                                                       const rtsp_message_t *request, 
+                                                                                       const rtsp_message_t *response, 
+                                                                                       const char *force_destination_ip,
+                                                                                       const apr_table_t *resource_map, 
+                                                                                       apr_pool_t *pool, 
+                                                                                       su_home_t *home)
+{
+       mrcp_session_descriptor_t *descriptor = NULL;
+       const char *resource_name = mrcp_name_get_by_rtsp_name(
+               resource_map,
+               request->start_line.common.request_line.resource_name);
+       if(!resource_name) {
+               return NULL;
+       }
+       
+       if(request->start_line.common.request_line.method_id == RTSP_METHOD_SETUP) {
+               if(rtsp_header_property_check(&response->header.property_set,RTSP_HEADER_FIELD_CONTENT_TYPE) == TRUE &&
+                       rtsp_header_property_check(&response->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH) == TRUE &&
+                       response->body.buf) {
+                       
+                       sdp_parser_t *parser;
+                       sdp_session_t *sdp;
+
+                       parser = sdp_parse(home,response->body.buf,response->body.length,0);
+                       sdp = sdp_session(parser);
+                       if(sdp) {
+                               descriptor = mrcp_session_descriptor_create(pool);
+                               mrcp_descriptor_generate_by_sdp_session(descriptor,sdp,force_destination_ip,pool);
+
+                               apt_string_assign(&descriptor->resource_name,resource_name,pool);
+                               descriptor->resource_state = TRUE;
+                       }
+                       else {
+                               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse SDP Message");
+                       }
+                       
+                       sdp_parser_free(parser);
+               }
+               else {
+                       descriptor = mrcp_session_descriptor_create(pool);
+                       apt_string_assign(&descriptor->resource_name,resource_name,pool);
+                       descriptor->resource_state = FALSE;
+               }
+       }
+       else if(request->start_line.common.request_line.method_id == RTSP_METHOD_TEARDOWN) {
+               descriptor = mrcp_session_descriptor_create(pool);
+               apt_string_assign(&descriptor->resource_name,resource_name,pool);
+               descriptor->resource_state = FALSE;
+       }
+       return descriptor;
+}
+
+/** Generate RTSP request by MRCP descriptor */
+MRCP_DECLARE(rtsp_message_t*) rtsp_request_generate_by_mrcp_descriptor(const mrcp_session_descriptor_t *descriptor, const apr_table_t *resource_map, apr_pool_t *pool)
+{
+       apr_size_t i;
+       apr_size_t count;
+       apr_size_t audio_index = 0;
+       mpf_rtp_media_descriptor_t *audio_media;
+       apr_size_t video_index = 0;
+       mpf_rtp_media_descriptor_t *video_media;
+       apr_size_t offset = 0;
+       char buffer[2048];
+       apr_size_t size = sizeof(buffer);
+       rtsp_message_t *request;
+       const char *ip = descriptor->ext_ip.buf ? descriptor->ext_ip.buf : (descriptor->ip.buf ? descriptor->ip.buf : "0.0.0.0");
+
+       request = rtsp_request_create(pool);
+       request->start_line.common.request_line.resource_name = rtsp_name_get_by_mrcp_name(
+               resource_map,
+               descriptor->resource_name.buf);
+       if(descriptor->resource_state != TRUE) {
+               request->start_line.common.request_line.method_id = RTSP_METHOD_TEARDOWN;
+               return request;
+       }
+
+       request->start_line.common.request_line.method_id = RTSP_METHOD_SETUP;
+
+       buffer[0] = '\0';
+       offset += snprintf(buffer+offset,size-offset,
+                       "v=0\r\n"
+                       "o=%s 0 0 IN IP4 %s\r\n"
+                       "s=-\r\n"
+                       "c=IN IP4 %s\r\n"
+                       "t=0 0\r\n",
+                       descriptor->origin.buf ? descriptor->origin.buf : "-",
+                       ip,
+                       ip);
+       count = mrcp_session_media_count_get(descriptor);
+       for(i=0; i<count; i++) {
+               audio_media = mrcp_session_audio_media_get(descriptor,audio_index);
+               if(audio_media && audio_media->base.id == i) {
+                       /* generate audio media */
+                       audio_index++;
+                       offset += sdp_rtp_media_generate(buffer+offset,size-offset,descriptor,audio_media);
+                       request->header.transport.client_port_range.min = audio_media->base.port;
+                       request->header.transport.client_port_range.max = audio_media->base.port+1;
+                       continue;
+               }
+               video_media = mrcp_session_video_media_get(descriptor,video_index);
+               if(video_media && video_media->base.id == i) {
+                       /* generate video media */
+                       video_index++;
+                       offset += sdp_rtp_media_generate(buffer+offset,size-offset,descriptor,video_media);
+                       continue;
+               }
+       }
+
+       request->header.transport.protocol = RTSP_TRANSPORT_RTP;
+       request->header.transport.profile = RTSP_PROFILE_AVP;
+       request->header.transport.delivery = RTSP_DELIVERY_UNICAST;
+       rtsp_header_property_add(&request->header.property_set,RTSP_HEADER_FIELD_TRANSPORT);
+
+       if(offset) {
+               apt_string_assign_n(&request->body,buffer,offset,pool);
+               request->header.content_type = RTSP_CONTENT_TYPE_SDP;
+               rtsp_header_property_add(&request->header.property_set,RTSP_HEADER_FIELD_CONTENT_TYPE);
+               request->header.content_length = offset;
+               rtsp_header_property_add(&request->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH);
+       }
+       return request;
+}
+
+/** Generate RTSP response by MRCP descriptor */
+MRCP_DECLARE(rtsp_message_t*) rtsp_response_generate_by_mrcp_descriptor(const rtsp_message_t *request, const mrcp_session_descriptor_t *descriptor, const apr_table_t *resource_map, apr_pool_t *pool)
+{
+       rtsp_message_t *response = NULL;
+
+       switch(descriptor->status) {
+               case MRCP_SESSION_STATUS_OK:
+                       response = rtsp_response_create(request,RTSP_STATUS_CODE_OK,RTSP_REASON_PHRASE_OK,pool);
+                       break;
+               case MRCP_SESSION_STATUS_NO_SUCH_RESOURCE:
+                       response = rtsp_response_create(request,RTSP_STATUS_CODE_NOT_FOUND,RTSP_REASON_PHRASE_NOT_FOUND,pool);
+                       break;
+               case MRCP_SESSION_STATUS_UNACCEPTABLE_RESOURCE:
+               case MRCP_SESSION_STATUS_UNAVAILABLE_RESOURCE:
+                       response = rtsp_response_create(request,RTSP_STATUS_CODE_NOT_ACCEPTABLE,RTSP_REASON_PHRASE_NOT_ACCEPTABLE,pool);
+                       break;
+               case MRCP_SESSION_STATUS_ERROR:
+                       response = rtsp_response_create(request,RTSP_STATUS_CODE_INTERNAL_SERVER_ERROR,RTSP_REASON_PHRASE_INTERNAL_SERVER_ERROR,pool);
+                       break;
+       }
+
+       if(!response) {
+               return NULL;
+       }
+
+       if(descriptor->status == MRCP_SESSION_STATUS_OK) {
+               apr_size_t i;
+               apr_size_t count;
+               apr_size_t audio_index = 0;
+               mpf_rtp_media_descriptor_t *audio_media;
+               apr_size_t video_index = 0;
+               mpf_rtp_media_descriptor_t *video_media;
+               apr_size_t offset = 0;
+               char buffer[2048];
+               apr_size_t size = sizeof(buffer);
+               const char *ip = descriptor->ext_ip.buf ? descriptor->ext_ip.buf : (descriptor->ip.buf ? descriptor->ip.buf : "0.0.0.0");
+
+               buffer[0] = '\0';
+               offset += snprintf(buffer+offset,size-offset,
+                               "v=0\r\n"
+                               "o=%s 0 0 IN IP4 %s\r\n"
+                               "s=-\r\n"
+                               "c=IN IP4 %s\r\n"
+                               "t=0 0\r\n",
+                               descriptor->origin.buf ? descriptor->origin.buf : "-",
+                               ip,
+                               ip);
+               count = mrcp_session_media_count_get(descriptor);
+               for(i=0; i<count; i++) {
+                       audio_media = mrcp_session_audio_media_get(descriptor,audio_index);
+                       if(audio_media && audio_media->base.id == i) {
+                               /* generate audio media */
+                               audio_index++;
+                               offset += sdp_rtp_media_generate(buffer+offset,size-offset,descriptor,audio_media);
+                               response->header.transport.server_port_range.min = audio_media->base.port;
+                               response->header.transport.server_port_range.max = audio_media->base.port+1;
+                               response->header.transport.client_port_range = request->header.transport.client_port_range;
+                               continue;
+                       }
+                       video_media = mrcp_session_video_media_get(descriptor,video_index);
+                       if(video_media && video_media->base.id == i) {
+                               /* generate video media */
+                               video_index++;
+                               offset += sdp_rtp_media_generate(buffer+offset,size-offset,descriptor,video_media);
+                               continue;
+                       }
+               }
+
+               /* ok */
+               response->header.transport.protocol = RTSP_TRANSPORT_RTP;
+               response->header.transport.profile = RTSP_PROFILE_AVP;
+               response->header.transport.delivery = RTSP_DELIVERY_UNICAST;
+               rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_TRANSPORT);
+
+               if(offset) {
+                       apt_string_assign_n(&response->body,buffer,offset,pool);
+                       response->header.content_type = RTSP_CONTENT_TYPE_SDP;
+                       rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_CONTENT_TYPE);
+                       response->header.content_length = offset;
+                       rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH);
+               }
+       }
+       return response;
+}
+
+/** Generate RTSP resource discovery request */
+MRCP_DECLARE(rtsp_message_t*) rtsp_resource_discovery_request_generate(
+                                                                                       const char *resource_name,
+                                                                                       const apr_table_t *resource_map,
+                                                                                       apr_pool_t *pool)
+{
+       rtsp_message_t *request = rtsp_request_create(pool);
+       request->start_line.common.request_line.resource_name = rtsp_name_get_by_mrcp_name(
+               resource_map,
+               resource_name);
+       
+       request->start_line.common.request_line.method_id = RTSP_METHOD_DESCRIBE;
+       return request;
+}
+
+/** Generate resource descovery descriptor by RTSP response */
+MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_resource_discovery_response_generate(
+                                                                                       const rtsp_message_t *request, 
+                                                                                       const rtsp_message_t *response,
+                                                                                       const apr_table_t *resource_map,
+                                                                                       apr_pool_t *pool,
+                                                                                       su_home_t *home)
+{
+       mrcp_session_descriptor_t *descriptor = NULL;
+       const char *resource_name = mrcp_name_get_by_rtsp_name(
+                                       resource_map,
+                                       request->start_line.common.request_line.resource_name);
+       if(!resource_name) {
+               return NULL;
+       }
+       
+       descriptor = mrcp_session_descriptor_create(pool);
+       apt_string_assign(&descriptor->resource_name,resource_name,pool);
+       
+       if(rtsp_header_property_check(&response->header.property_set,RTSP_HEADER_FIELD_CONTENT_TYPE) == TRUE &&
+               rtsp_header_property_check(&response->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH) == TRUE &&
+               response->body.buf) {
+                       
+               sdp_parser_t *parser;
+               sdp_session_t *sdp;
+
+               parser = sdp_parse(home,response->body.buf,response->body.length,0);
+               sdp = sdp_session(parser);
+               if(sdp) {
+                       mrcp_descriptor_generate_by_sdp_session(descriptor,sdp,0,pool);
+                       descriptor->resource_state = TRUE;
+               }
+               else {
+                       apt_string_assign(&descriptor->resource_name,resource_name,pool);
+                       descriptor->resource_state = TRUE;
+               }
+
+               sdp_parser_free(parser);
+       }
+       else {
+               descriptor->resource_state = FALSE;
+       }
+       return descriptor;
+}
+
+/** Generate RTSP resource discovery response */
+MRCP_DECLARE(rtsp_message_t*) rtsp_resource_discovery_response_generate(
+                                                                                       const rtsp_message_t *request, 
+                                                                                       const char *ip,
+                                                                                       const char *origin,
+                                                                                       apr_pool_t *pool)
+{
+       rtsp_message_t *response = rtsp_response_create(request,RTSP_STATUS_CODE_OK,RTSP_REASON_PHRASE_OK,pool);
+       if(response) {
+               apr_size_t offset = 0;
+               char buffer[2048];
+               apr_size_t size = sizeof(buffer);
+               
+               if(!ip) {
+                       ip = "0.0.0.0";
+               }
+               if(!origin) {
+                       origin = "-";
+               }
+               
+               buffer[0] = '\0';
+               offset += snprintf(buffer+offset,size-offset,
+                       "v=0\r\n"
+                       "o=%s 0 0 IN IP4 %s\r\n"
+                       "s=-\r\n"
+                       "c=IN IP4 %s\r\n"
+                       "t=0 0\r\n"
+                       "m=audio 0 RTP/AVP 0 8\r\n"
+                       "a=rtpmap:0 PCMU/8000\r\n"
+                       "a=rtpmap:8 PCMA/8000\r\n",
+                       origin,
+                       ip,
+                       ip);
+               
+               response->header.transport.protocol = RTSP_TRANSPORT_RTP;
+               response->header.transport.profile = RTSP_PROFILE_AVP;
+               response->header.transport.delivery = RTSP_DELIVERY_UNICAST;
+               rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_TRANSPORT);
+
+               if(offset) {
+                       apt_string_assign_n(&response->body,buffer,offset,pool);
+                       response->header.content_type = RTSP_CONTENT_TYPE_SDP;
+                       rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_CONTENT_TYPE);
+                       response->header.content_length = offset;
+                       rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH);
+               }
+       }
+
+       return response;
+}
+
+/** Get MRCP resource name by RTSP resource name */
+MRCP_DECLARE(const char*) mrcp_name_get_by_rtsp_name(const apr_table_t *resource_map, const char *rtsp_name)
+{
+       const apr_array_header_t *header = apr_table_elts(resource_map);
+       apr_table_entry_t *entry = (apr_table_entry_t *)header->elts;
+       int i;
+       
+       for(i=0; i<header->nelts; i++) {
+               if(entry[i].val && rtsp_name) {
+                       if(apr_strnatcasecmp(entry[i].val,rtsp_name) == 0) {
+                               return entry[i].key;
+                       }
+               }
+       }
+       return rtsp_name;
+}
+
+/** Get RTSP resource name by MRCP resource name */
+MRCP_DECLARE(const char*) rtsp_name_get_by_mrcp_name(const apr_table_t *resource_map, const char *mrcp_name)
+{
+       const char *rtsp_name = apr_table_get(resource_map,mrcp_name);
+       if(rtsp_name) {
+               return rtsp_name;
+       }
+       return mrcp_name;
+}
diff --git a/libs/unimrcp/modules/mrcp-unirtsp/src/mrcp_unirtsp_server_agent.c b/libs/unimrcp/modules/mrcp-unirtsp/src/mrcp_unirtsp_server_agent.c
new file mode 100644 (file)
index 0000000..12de96a
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_general.h>
+#include <sofia-sip/sdp.h>
+
+#include "mrcp_unirtsp_server_agent.h"
+#include "mrcp_session.h"
+#include "mrcp_session_descriptor.h"
+#include "mrcp_message.h"
+#include "mrcp_resource_factory.h"
+#include "mrcp_stream.h"
+#include "rtsp_server.h"
+#include "mrcp_unirtsp_sdp.h"
+#include "apt_consumer_task.h"
+#include "apt_log.h"
+
+#define UNIRTSP_TASK_NAME "UniRTSP Agent"
+
+typedef struct mrcp_unirtsp_agent_t mrcp_unirtsp_agent_t;
+typedef struct mrcp_unirtsp_session_t mrcp_unirtsp_session_t;
+
+struct mrcp_unirtsp_agent_t {
+       mrcp_sig_agent_t     *sig_agent;
+       rtsp_server_t        *rtsp_server;
+
+       rtsp_server_config_t *config;
+};
+
+struct mrcp_unirtsp_session_t {
+       mrcp_session_t        *mrcp_session;
+       rtsp_server_session_t *rtsp_session;
+       su_home_t             *home;
+};
+
+
+static apt_bool_t mrcp_unirtsp_on_session_answer(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor);
+static apt_bool_t mrcp_unirtsp_on_session_terminate(mrcp_session_t *session);
+static apt_bool_t mrcp_unirtsp_on_session_control(mrcp_session_t *session, mrcp_message_t *message);
+
+static const mrcp_session_response_vtable_t session_response_vtable = {
+       mrcp_unirtsp_on_session_answer,
+       mrcp_unirtsp_on_session_terminate,
+       mrcp_unirtsp_on_session_control
+};
+
+static apt_bool_t mrcp_unirtsp_session_create(rtsp_server_t *server, rtsp_server_session_t *session);
+static apt_bool_t mrcp_unirtsp_session_terminate(rtsp_server_t *server, rtsp_server_session_t *session);
+static apt_bool_t mrcp_unirtsp_message_handle(rtsp_server_t *server, rtsp_server_session_t *session, rtsp_message_t *message);
+
+static const rtsp_server_vtable_t session_request_vtable = {
+       mrcp_unirtsp_session_create,
+       mrcp_unirtsp_session_terminate,
+       mrcp_unirtsp_message_handle
+};
+
+
+static apt_bool_t rtsp_config_validate(mrcp_unirtsp_agent_t *agent, rtsp_server_config_t *config, apr_pool_t *pool);
+
+
+/** Create UniRTSP Signaling Agent */
+MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_unirtsp_server_agent_create(rtsp_server_config_t *config, apr_pool_t *pool)
+{
+       apt_task_t *task;
+       mrcp_unirtsp_agent_t *agent;
+       agent = apr_palloc(pool,sizeof(mrcp_unirtsp_agent_t));
+       agent->sig_agent = mrcp_signaling_agent_create(agent,MRCP_VERSION_1,pool);
+       agent->config = config;
+
+       if(rtsp_config_validate(agent,config,pool) == FALSE) {
+               return NULL;
+       }
+
+       agent->rtsp_server = rtsp_server_create(
+                                                               config->local_ip,
+                                                               config->local_port,
+                                                               config->max_connection_count,
+                                                               agent,
+                                                               &session_request_vtable,
+                                                               pool);
+       if(!agent->rtsp_server) {
+               return NULL;
+       }
+       
+       task = rtsp_server_task_get(agent->rtsp_server);
+       apt_task_name_set(task,UNIRTSP_TASK_NAME);
+       agent->sig_agent->task = task;
+
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create "UNIRTSP_TASK_NAME" %s:%hu [%d]",
+               config->local_ip,
+               config->local_port,
+               config->max_connection_count);
+       return agent->sig_agent;
+}
+
+/** Allocate UniRTSP config */
+MRCP_DECLARE(rtsp_server_config_t*) mrcp_unirtsp_server_config_alloc(apr_pool_t *pool)
+{
+       rtsp_server_config_t *config = apr_palloc(pool,sizeof(rtsp_server_config_t));
+       config->local_ip = NULL;
+       config->local_port = 0;
+       config->origin = NULL;
+       config->resource_location = NULL;
+       config->resource_map = apr_table_make(pool,2);
+       config->max_connection_count = 100;
+       config->force_destination = FALSE;
+       return config;
+}
+
+
+static apt_bool_t rtsp_config_validate(mrcp_unirtsp_agent_t *agent, rtsp_server_config_t *config, apr_pool_t *pool)
+{
+       if(!config->local_ip) {
+               return FALSE;
+       }
+       agent->config = config;
+       return TRUE;
+}
+
+static APR_INLINE mrcp_unirtsp_agent_t* server_agent_get(apt_task_t *task)
+{
+       apt_consumer_task_t *consumer_task = apt_task_object_get(task);
+       mrcp_unirtsp_agent_t *agent = apt_consumer_task_object_get(consumer_task);
+       return agent;
+}
+
+static apt_bool_t mrcp_unirtsp_session_create(rtsp_server_t *rtsp_server, rtsp_server_session_t *rtsp_session)
+{
+       mrcp_unirtsp_agent_t *agent = rtsp_server_object_get(rtsp_server);
+       const apt_str_t *session_id;
+       mrcp_unirtsp_session_t *session;
+       mrcp_session_t* mrcp_session = agent->sig_agent->create_server_session(agent->sig_agent);
+       if(!mrcp_session) {
+               return FALSE;
+       }
+       session_id = rtsp_server_session_id_get(rtsp_session);
+       if(session_id) {
+               mrcp_session->id = *session_id;
+       }
+       mrcp_session->response_vtable = &session_response_vtable;
+       mrcp_session->event_vtable = NULL;
+
+       session = apr_palloc(mrcp_session->pool,sizeof(mrcp_unirtsp_session_t));
+       session->mrcp_session = mrcp_session;
+       mrcp_session->obj = session;
+       
+       session->home = su_home_new(sizeof(*session->home));
+
+       rtsp_server_session_object_set(rtsp_session,session);
+       session->rtsp_session = rtsp_session;
+       return TRUE;
+}
+
+static apt_bool_t mrcp_unirtsp_session_terminate(rtsp_server_t *rtsp_server, rtsp_server_session_t *rtsp_session)
+{
+       mrcp_unirtsp_session_t *session = rtsp_server_session_object_get(rtsp_session);
+       if(!session) {
+               return FALSE;
+       }
+       return mrcp_session_terminate_request(session->mrcp_session);
+}
+
+static void mrcp_unirtsp_session_destroy(mrcp_unirtsp_session_t *session)
+{
+       if(session->home) {
+               su_home_unref(session->home);
+               session->home = NULL;
+       }
+       rtsp_server_session_object_set(session->rtsp_session,NULL);
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy Session "APT_SID_FMT,MRCP_SESSION_SID(session->mrcp_session));
+       mrcp_session_destroy(session->mrcp_session);
+}
+
+static apt_bool_t mrcp_unirtsp_session_announce(mrcp_unirtsp_agent_t *agent, mrcp_unirtsp_session_t *session, rtsp_message_t *message)
+{
+       const char *resource_name = mrcp_name_get_by_rtsp_name(
+               agent->config->resource_map,
+               message->start_line.common.request_line.resource_name);
+       apt_bool_t status = TRUE;
+
+       if(session && resource_name &&
+               rtsp_header_property_check(&message->header.property_set,RTSP_HEADER_FIELD_CONTENT_TYPE) == TRUE &&
+               message->header.content_type == RTSP_CONTENT_TYPE_MRCP &&
+               rtsp_header_property_check(&message->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH) == TRUE &&
+               message->header.content_length > 0) {
+
+               apt_text_stream_t text_stream;
+               mrcp_parser_t *parser;
+               apt_str_t resource_name_str;
+
+               text_stream.text = message->body;
+               text_stream.pos = text_stream.text.buf;
+               apt_string_set(&resource_name_str,resource_name);
+
+               parser = mrcp_parser_create(agent->sig_agent->resource_factory,session->mrcp_session->pool);
+               mrcp_parser_resource_name_set(parser,&resource_name_str);
+               if(mrcp_parser_run(parser,&text_stream) == MRCP_STREAM_MESSAGE_COMPLETE) {
+                       mrcp_message_t *mrcp_message = mrcp_parser_message_get(parser);
+                       mrcp_message->channel_id.session_id = message->header.session_id;
+                       status = mrcp_session_control_request(session->mrcp_session,mrcp_message);
+               }
+               else {
+                       /* error response */
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse MRCPv1 Message");
+                       status = FALSE;
+               }
+       }
+       else {
+               /* error response */
+               status = FALSE;
+       }
+       return status;
+}
+
+static apt_bool_t mrcp_unirtsp_message_handle(rtsp_server_t *rtsp_server, rtsp_server_session_t *rtsp_session, rtsp_message_t *rtsp_message)
+{
+       apt_bool_t status = FALSE;
+       mrcp_unirtsp_agent_t *agent = rtsp_server_object_get(rtsp_server);
+       mrcp_unirtsp_session_t *session = rtsp_server_session_object_get(rtsp_session);
+       if(!session) {
+               return FALSE;
+       }
+
+       switch(rtsp_message->start_line.common.request_line.method_id) {
+               case RTSP_METHOD_SETUP:
+               case RTSP_METHOD_TEARDOWN:
+               {
+                       const char *force_destination_ip = NULL;
+                       mrcp_session_descriptor_t *descriptor;
+
+                       if(agent->config->force_destination == TRUE) {
+                               force_destination_ip = rtsp_server_session_destination_get(rtsp_session);
+                       }
+                       descriptor = mrcp_descriptor_generate_by_rtsp_request(
+                                                       rtsp_message,
+                                                       force_destination_ip,
+                                                       agent->config->resource_map,
+                                                       session->mrcp_session->pool,
+                                                       session->home);
+                       if(!descriptor) {
+                               rtsp_message_t *response = rtsp_response_create(rtsp_message,
+                                                                               RTSP_STATUS_CODE_BAD_REQUEST,
+                                                                               RTSP_REASON_PHRASE_BAD_REQUEST,
+                                                                               rtsp_message->pool);
+                               status = rtsp_server_session_respond(rtsp_server,session->rtsp_session,response);
+                               break;
+                       }
+                       status = mrcp_session_offer(session->mrcp_session,descriptor);
+                       break;
+               }
+               case RTSP_METHOD_ANNOUNCE:
+               {
+                       status = mrcp_unirtsp_session_announce(agent,session,rtsp_message);
+                       break;
+               }
+               case RTSP_METHOD_DESCRIBE:
+               {
+                       rtsp_message_t *response = rtsp_resource_discovery_response_generate(
+                                               rtsp_message,
+                                               agent->config->local_ip,
+                                               agent->config->origin,
+                                               session->mrcp_session->pool);
+                       status = rtsp_server_session_respond(rtsp_server,session->rtsp_session,response);
+                       break;
+               }
+               default:
+                       break;
+       }
+
+       return status;
+}
+
+static apt_bool_t mrcp_unirtsp_on_session_answer(mrcp_session_t *mrcp_session, mrcp_session_descriptor_t *descriptor)
+{
+       mrcp_unirtsp_session_t *session = mrcp_session->obj;
+       mrcp_unirtsp_agent_t *agent = mrcp_session->signaling_agent->obj;
+       rtsp_message_t *response = NULL;
+       const rtsp_message_t *request = rtsp_server_session_request_get(session->rtsp_session);
+       if(!request) {
+               return FALSE;
+       }
+
+       if(request->start_line.common.request_line.method_id == RTSP_METHOD_SETUP) {
+               if(agent->config->origin) {
+                       apt_string_set(&descriptor->origin,agent->config->origin);
+               }
+
+               response = rtsp_response_generate_by_mrcp_descriptor(
+                                               request,
+                                               descriptor,
+                                               agent->config->resource_map,
+                                               mrcp_session->pool);
+       }
+       else if(request->start_line.common.request_line.method_id == RTSP_METHOD_TEARDOWN) {
+               response = rtsp_response_create(request,RTSP_STATUS_CODE_OK,RTSP_REASON_PHRASE_OK,mrcp_session->pool);
+       }
+
+       if(!response) {
+               return FALSE;
+       }
+       rtsp_server_session_respond(agent->rtsp_server,session->rtsp_session,response);
+       return TRUE;
+}
+
+static apt_bool_t mrcp_unirtsp_on_session_terminate(mrcp_session_t *mrcp_session)
+{
+       mrcp_unirtsp_session_t *session = mrcp_session->obj;
+       rtsp_server_session_t *rtsp_session = session->rtsp_session;
+       mrcp_unirtsp_agent_t *agent = mrcp_session->signaling_agent->obj;
+
+       mrcp_unirtsp_session_destroy(session);
+       rtsp_server_session_terminate(agent->rtsp_server,rtsp_session);
+       return TRUE;
+}
+
+static apt_bool_t mrcp_unirtsp_on_session_control(mrcp_session_t *mrcp_session, mrcp_message_t *mrcp_message)
+{
+       mrcp_unirtsp_session_t *session = mrcp_session->obj;
+       mrcp_unirtsp_agent_t *agent = mrcp_session->signaling_agent->obj;
+
+       char buffer[500];
+       apt_text_stream_t stream;
+       rtsp_message_t *rtsp_message = NULL;
+       apt_str_t *body;
+
+       apt_text_stream_init(&stream,buffer,sizeof(buffer));
+
+       mrcp_message->start_line.version = MRCP_VERSION_1;
+       if(mrcp_message_generate(agent->sig_agent->resource_factory,mrcp_message,&stream) != TRUE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Generate MRCPv1 Message");
+               return FALSE;
+       }
+       stream.text.length = stream.pos - stream.text.buf;
+
+       if(mrcp_message->start_line.message_type == MRCP_MESSAGE_TYPE_RESPONSE) {
+               /* send RTSP response (OK) */
+               const rtsp_message_t *request = rtsp_server_session_request_get(session->rtsp_session);
+               if(request) {
+                       rtsp_message = rtsp_response_create(request,RTSP_STATUS_CODE_OK,RTSP_REASON_PHRASE_OK,mrcp_session->pool);
+               }
+       }
+       else if(mrcp_message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
+               /* send RTSP announce */
+               rtsp_message = rtsp_request_create(mrcp_session->pool);
+               rtsp_message->start_line.common.request_line.method_id = RTSP_METHOD_ANNOUNCE;
+       }
+
+       if(!rtsp_message) {
+               return FALSE;
+       }
+
+       body = &rtsp_message->body;
+       body->length = mrcp_message->start_line.length;
+       body->buf = apr_palloc(rtsp_message->pool,body->length+1);
+       memcpy(body->buf,stream.text.buf,stream.text.length);
+       if(mrcp_message->body.length) {
+               memcpy(body->buf+stream.text.length,mrcp_message->body.buf,mrcp_message->body.length);
+       }
+       body->buf[body->length] = '\0';
+
+       rtsp_message->header.content_type = RTSP_CONTENT_TYPE_MRCP;
+       rtsp_header_property_add(&rtsp_message->header.property_set,RTSP_HEADER_FIELD_CONTENT_TYPE);
+       rtsp_message->header.content_length = body->length;
+       rtsp_header_property_add(&rtsp_message->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH);
+
+       rtsp_server_session_respond(agent->rtsp_server,session->rtsp_session,rtsp_message);
+       return TRUE;
+}
diff --git a/libs/unimrcp/packages/inno-setup/setup.iss b/libs/unimrcp/packages/inno-setup/setup.iss
new file mode 100644 (file)
index 0000000..a14c500
--- /dev/null
@@ -0,0 +1,14 @@
+#define uni_version "0.6.0"
+
+AppName=UniMRCP
+AppVerName=UniMRCP-{#= uni_version}
+AppPublisher=UniMRCP
+AppPublisherURL=http://www.unimrcp.org/
+AppSupportURL=http://groups.google.com/group/unimrcp
+AppUpdatesURL=http://code.google.com/p/unimrcp/downloads/list
+DefaultDirName={pf}\UniMRCP
+DefaultGroupName=UniMRCP
+Compression=lzma
+InternalCompressLevel=max
+SolidCompression=true
+
diff --git a/libs/unimrcp/packages/inno-setup/unimrcp-sdk.iss b/libs/unimrcp/packages/inno-setup/unimrcp-sdk.iss
new file mode 100644 (file)
index 0000000..cf876f7
--- /dev/null
@@ -0,0 +1,56 @@
+[Setup]
+#include "setup.iss"
+OutputBaseFilename=unimrcp-sdk-{#= uni_version}
+
+[Types]
+Name: "full"; Description: "Full installation"
+Name: "sdk"; Description: "SDK installation"
+Name: "docs"; Description: "Documentation installation"
+Name: "custom"; Description: "Custom installation"; Flags: iscustom
+
+[Components]
+Name: "sdk"; Description: "UniMRCP SDK (client, server and plugin development)"; Types: full sdk
+Name: "docs"; Description: "UniMRCP documentation"; Types: full docs
+Name: "docs\design"; Description: "Design concepts"; Types: full docs
+Name: "docs\api"; Description: "API"; Types: full docs
+
+[Files]
+Source: "..\..\libs\apr\include\*.h"; DestDir: "{app}\include"; Components: sdk
+Source: "..\..\libs\apr-toolkit\include\*.h"; DestDir: "{app}\include"; Components: sdk
+Source: "..\..\libs\mpf\include\*.h"; DestDir: "{app}\include"; Components: sdk
+Source: "..\..\libs\mrcp\include\*.h"; DestDir: "{app}\include"; Components: sdk
+Source: "..\..\libs\mrcp\message\include\*.h"; DestDir: "{app}\include"; Components: sdk
+Source: "..\..\libs\mrcp\control\include\*.h"; DestDir: "{app}\include"; Components: sdk
+Source: "..\..\libs\mrcp\resources\include\*.h"; DestDir: "{app}\include"; Components: sdk
+Source: "..\..\libs\mrcp-engine\include\*.h"; DestDir: "{app}\include"; Components: sdk
+Source: "..\..\libs\mrcp-signaling\include\*.h"; DestDir: "{app}\include"; Components: sdk
+Source: "..\..\libs\mrcpv2-transport\include\*.h"; DestDir: "{app}\include"; Components: sdk
+Source: "..\..\libs\mrcp-client\include\*.h"; DestDir: "{app}\include"; Components: sdk
+Source: "..\..\libs\mrcp-server\include\*.h"; DestDir: "{app}\include"; Components: sdk
+Source: "..\..\platforms\libunimrcp-client\include\*.h"; DestDir: "{app}\include"; Components: sdk
+Source: "..\..\platforms\libunimrcp-server\include\*.h"; DestDir: "{app}\include"; Components: sdk
+Source: "..\..\Release\bin\*.lib"; DestDir: "{app}\lib"; Components: sdk
+Source: "..\..\libs\apr\Release\*.lib"; DestDir: "{app}\lib"; Components: sdk
+Source: "..\..\libs\apr-util\Release\*.lib"; DestDir: "{app}\lib"; Components: sdk
+Source: "..\..\libs\sofia-sip\win32\libsofia-sip-ua\Release\*.lib"; DestDir: "{app}\lib"; Components: sdk
+Source: "..\..\build\vsprops\sdk\*.vsprops"; DestDir: "{app}\vsprops"; Components: sdk; AfterInstall: SetProjectPath()
+Source: "..\..\docs\ea\*"; DestDir: "{app}\doc\ea"; Components: docs/design; Flags: recursesubdirs
+Source: "..\..\docs\dox\*"; DestDir: "{app}\doc\dox"; Components: docs/api; Flags: recursesubdirs
+
+[Icons]
+Name: "{group}\UniMRCP Docs\Design concepts"; Filename: "{app}\doc\ea\index.htm"; Components: docs\design
+Name: "{group}\UniMRCP Docs\API"; Filename: "{app}\doc\dox\html\index.html"; Components: docs\api
+Name: "{group}\Uninstall"; Filename: "{uninstallexe}"
+
+[Code]
+procedure SetProjectPath();
+var
+  VspropsFile: String;
+  Content: String;
+begin
+  VspropsFile := ExpandConstant('{app}\vsprops\unimrcpsdk.vsprops');
+  LoadStringFromFile (VspropsFile, Content);
+  StringChange (Content, 'Value="C:\Program Files\UniMRCP"', ExpandConstant('Value="{app}"'));
+  SaveStringToFile (VspropsFile, Content, False);
+end;
+
diff --git a/libs/unimrcp/packages/inno-setup/unimrcp.iss b/libs/unimrcp/packages/inno-setup/unimrcp.iss
new file mode 100644 (file)
index 0000000..b582652
--- /dev/null
@@ -0,0 +1,85 @@
+[Setup]
+#include "setup.iss"
+OutputBaseFilename=unimrcp-{#= uni_version}
+
+[Types]
+Name: "full"; Description: "Full installation"
+Name: "server"; Description: "Server installation"
+Name: "client"; Description: "Client installation"
+Name: "custom"; Description: "Custom installation"; Flags: iscustom
+
+[Components]
+Name: "server"; Description: "UniMRCP server"; Types: full server
+Name: "server\cepstral"; Description: "Cepstral synthesizer plugin"; Types: full server
+Name: "server\demosynth"; Description: "Demo synthesizer plugin"; Types: full server
+Name: "server\demorecog"; Description: "Demo recognizer plugin"; Types: full server
+Name: "client"; Description: "UniMRCP client (demo application)"; Types: full client
+
+[Dirs]
+Name: "{app}\data"; Permissions: everyone-full;
+Name: "{app}\log"; Permissions: everyone-full;
+
+[Files]
+#define uni_root "..\..\Release"
+Source: "{#= uni_root}\bin\unimrcpserver.exe"; DestDir: "{app}\bin"; Components: server
+Source: "{#= uni_root}\bin\unimrcpservice.exe"; DestDir: "{app}\bin"; Components: server
+Source: "{#= uni_root}\bin\unimrcpclient.exe"; DestDir: "{app}\bin"; Components: client
+Source: "{#= uni_root}\bin\*.dll"; DestDir: "{app}\bin"; Components: server client
+Source: "{#= uni_root}\plugin\mrcpcepstral.dll"; DestDir: "{app}\plugin"; Components: server/cepstral
+Source: "{#= uni_root}\plugin\demosynth.dll"; DestDir: "{app}\plugin"; Components: server/demosynth
+Source: "{#= uni_root}\plugin\demorecog.dll"; DestDir: "{app}\plugin"; Components: server/demorecog
+Source: "{#= uni_root}\conf\unimrcpserver.xml"; DestDir: "{app}\conf"; Components: server
+Source: "{#= uni_root}\conf\unimrcpclient.xml"; DestDir: "{app}\conf"; Components: client
+Source: "{#= uni_root}\data\*.pcm"; DestDir: "{app}\data"; Components: server client
+Source: "{#= uni_root}\data\*.xml"; DestDir: "{app}\data"; Components: server client
+
+[Icons]
+Name: "{group}\UniMRCP Server Console"; Filename: "{app}\bin\unimrcpserver.exe"; Parameters: "--root-dir ""{app}"""; Components: server
+Name: "{group}\UniMRCP Client Console"; Filename: "{app}\bin\unimrcpclient.exe"; Parameters: "--root-dir ""{app}"""; Components: client
+Name: "{group}\UniMRCP Service\Start Server"; Filename: "{app}\bin\unimrcpservice.exe"; Parameters: "--start"; Components: server
+Name: "{group}\UniMRCP Service\Stop Server"; Filename: "{app}\bin\unimrcpservice.exe"; Parameters: "--stop"; Components: server
+Name: "{group}\Uninstall"; Filename: "{uninstallexe}"
+
+[Run]
+Filename: "{app}\bin\unimrcpservice.exe"; Description: "Register service"; Parameters: "--register ""{app}"""; Components: server
+
+[UninstallRun]
+Filename: "{app}\bin\unimrcpservice.exe"; Parameters: "--unregister"; Components: server
+
+[Code]
+var
+  Content: String;
+  
+procedure ModifyPluginConf(PluginName: String; Enable: Boolean);
+var
+  TextFrom: String;
+  TextTo: String;
+begin
+  if Enable = True then
+  begin
+    TextFrom := 'class="' + PluginName + '" enable="0"';
+    TextTo := 'class="' + PluginName + '" enable="1"';
+  end
+  else
+  begin
+    TextFrom := 'class="' + PluginName + '" enable="1"';
+    TextTo := 'class="' + PluginName + '" enable="0"';
+  end
+  StringChange (Content, TextFrom, TextTo);
+end;
+
+procedure CurStepChanged(CurStep: TSetupStep);
+var
+  CfgFile: String;
+begin
+  if CurStep = ssPostInstall then
+  begin
+    CfgFile := ExpandConstant('{app}\conf\unimrcpserver.xml');
+    LoadStringFromFile (CfgFile, Content);
+    ModifyPluginConf ('mrcpcepstral', IsComponentSelected('server\cepstral'));
+    ModifyPluginConf ('demosynth', IsComponentSelected('server\demosynth'));
+    ModifyPluginConf ('demorecog', IsComponentSelected('server\demorecog'));
+    SaveStringToFile (CfgFile, Content, False);
+  end
+end;
+
diff --git a/libs/unimrcp/platforms/Makefile.am b/libs/unimrcp/platforms/Makefile.am
new file mode 100644 (file)
index 0000000..d6ce93d
--- /dev/null
@@ -0,0 +1,4 @@
+MAINTAINERCLEANFILES   = Makefile.in
+
+SUBDIRS                = libunimrcp-server unimrcp-server \
+                         libunimrcp-client unimrcp-client
diff --git a/libs/unimrcp/platforms/libunimrcp-client/Makefile.am b/libs/unimrcp/platforms/libunimrcp-client/Makefile.am
new file mode 100644 (file)
index 0000000..a21f667
--- /dev/null
@@ -0,0 +1,34 @@
+MAINTAINERCLEANFILES       = Makefile.in
+
+INCLUDES                    = -I$(top_srcdir)/platforms/libunimrcp-client/include \
+                              -I$(top_srcdir)/modules/mrcp-sofiasip/include \
+                              -I$(top_srcdir)/modules/mrcp-unirtsp/include \
+                              -I$(top_srcdir)/libs/mrcp-client/include \
+                              -I$(top_srcdir)/libs/mrcp-signaling/include \
+                              -I$(top_srcdir)/libs/mrcpv2-transport/include \
+                              -I$(top_srcdir)/libs/mrcp/include \
+                              -I$(top_srcdir)/libs/mrcp/message/include \
+                              -I$(top_srcdir)/libs/mrcp/control/include \
+                              -I$(top_srcdir)/libs/mrcp/resources/include \
+                              -I$(top_srcdir)/libs/mpf/include \
+                              -I$(top_srcdir)/libs/apr-toolkit/include \
+                              -I$(top_srcdir)/build \
+                              $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+lib_LTLIBRARIES             = libunimrcpclient.la
+
+include_HEADERS             = include/unimrcp_client.h
+
+libunimrcpclient_la_SOURCES = src/unimrcp_client.c
+
+libunimrcpclient_la_LIBADD  = $(top_builddir)/modules/mrcp-sofiasip/libmrcpsofiasip.la \
+                              $(top_builddir)/modules/mrcp-unirtsp/libmrcpunirtsp.la \
+                              $(top_builddir)/libs/mrcpv2-transport/libmrcpv2transport.la \
+                              $(top_builddir)/libs/mrcp-client/libmrcpclient.la \
+                              $(top_builddir)/libs/mrcp-signaling/libmrcpsignaling.la \
+                              $(top_builddir)/libs/mrcp/libmrcp.la \
+                              $(top_builddir)/libs/mpf/libmpf.la \
+                              $(top_builddir)/libs/apr-toolkit/libaprtoolkit.la \
+                              $(UNIMRCP_APR_LIBS) $(UNIMRCP_APU_LIBS) $(UNIMRCP_SOFIA_LIBS)
+                              
+libunimrcpclient_la_LDFLAGS = $(UNI_LT_VERSION)
diff --git a/libs/unimrcp/platforms/libunimrcp-client/include/unimrcp_client.h b/libs/unimrcp/platforms/libunimrcp-client/include/unimrcp_client.h
new file mode 100644 (file)
index 0000000..152f856
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UNIMRCP_CLIENT_H__
+#define __UNIMRCP_CLIENT_H__
+
+/**
+ * @file unimrcp_client.h
+ * @brief UniMRCP Client
+ */ 
+
+#include "mrcp_client.h"
+
+APT_BEGIN_EXTERN_C
+
+/**
+ * Create UniMRCP client.
+ * @param dir_layout the dir layout structure
+ */
+MRCP_DECLARE(mrcp_client_t*) unimrcp_client_create(apt_dir_layout_t *dir_layout);
+
+
+APT_END_EXTERN_C
+
+#endif /*__UNIMRCP_CLIENT_H__*/
diff --git a/libs/unimrcp/platforms/libunimrcp-client/libunimrcpclient.vcproj b/libs/unimrcp/platforms/libunimrcp-client/libunimrcpclient.vcproj
new file mode 100644 (file)
index 0000000..d0c7e7a
--- /dev/null
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="libunimrcpclient"
+       ProjectGUID="{EE157390-1E85-416C-946E-620E32C9AD33}"
+       RootNamespace="libunimrcpclient"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\unimrcpclient.vsprops"
+                       CharacterSet="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="&quot;$(ProjectRootDir)modules\mrcp-sofiasip\include&quot;;&quot;$(ProjectRootDir)modules\mrcp-unirtsp\include&quot;"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\unimrcpclient.vsprops"
+                       CharacterSet="1"
+                       WholeProgramOptimization="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="&quot;$(ProjectRootDir)modules\mrcp-sofiasip\include&quot;;&quot;$(ProjectRootDir)modules\mrcp-unirtsp\include&quot;"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+                       <File
+                               RelativePath="..\..\build\uni_version.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\unimrcp_client.h"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       >
+                       <File
+                               RelativePath=".\src\unimrcp_client.c"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/platforms/libunimrcp-client/src/unimrcp_client.c b/libs/unimrcp/platforms/libunimrcp-client/src/unimrcp_client.c
new file mode 100644 (file)
index 0000000..5844f5c
--- /dev/null
@@ -0,0 +1,596 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_xml.h>
+#include "unimrcp_client.h"
+#include "uni_version.h"
+#include "mrcp_default_factory.h"
+#include "mpf_engine.h"
+#include "mpf_codec_manager.h"
+#include "mpf_rtp_termination_factory.h"
+#include "mrcp_sofiasip_client_agent.h"
+#include "mrcp_unirtsp_client_agent.h"
+#include "mrcp_client_connection.h"
+#include "apt_net.h"
+#include "apt_log.h"
+
+#define CONF_FILE_NAME            "unimrcpclient.xml"
+#define DEFAULT_CONF_DIR_PATH     "../conf"
+
+#define DEFAULT_LOCAL_IP_ADDRESS  "127.0.0.1"
+#define DEFAULT_REMOTE_IP_ADDRESS "127.0.0.1"
+#define DEFAULT_SIP_LOCAL_PORT    8062
+#define DEFAULT_SIP_REMOTE_PORT   8060
+#define DEFAULT_RTP_PORT_MIN      4000
+#define DEFAULT_RTP_PORT_MAX      5000
+
+#define DEFAULT_SOFIASIP_UA_NAME  "UniMRCP SofiaSIP"
+#define DEFAULT_SDP_ORIGIN        "UniMRCPClient"
+#define DEFAULT_RESOURCE_LOCATION "media"
+
+#define XML_FILE_BUFFER_LENGTH    2000
+
+static apr_xml_doc* unimrcp_client_config_parse(const char *path, apr_pool_t *pool);
+static apt_bool_t unimrcp_client_config_load(mrcp_client_t *client, const apr_xml_doc *doc, apr_pool_t *pool);
+
+/** Start UniMRCP client */
+MRCP_DECLARE(mrcp_client_t*) unimrcp_client_create(apt_dir_layout_t *dir_layout)
+{
+       apr_pool_t *pool;
+       apr_xml_doc *doc;
+       mrcp_resource_factory_t *resource_factory;
+       mpf_codec_manager_t *codec_manager;
+       mrcp_client_t *client;
+
+       if(!dir_layout) {
+               return NULL;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"UniMRCP Client ["UNI_VERSION_STRING"]");
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"APR ["APR_VERSION_STRING"]");
+       client = mrcp_client_create(dir_layout);
+       if(!client) {
+               return NULL;
+       }
+       pool = mrcp_client_memory_pool_get(client);
+       if(!pool) {
+               return NULL;
+       }
+
+       resource_factory = mrcp_default_factory_create(pool);
+       if(resource_factory) {
+               mrcp_client_resource_factory_register(client,resource_factory);
+       }
+
+       codec_manager = mpf_engine_codec_manager_create(pool);
+       if(codec_manager) {
+               mrcp_client_codec_manager_register(client,codec_manager);
+       }
+
+       doc = unimrcp_client_config_parse(dir_layout->conf_dir_path,pool);
+       if(doc) {
+               unimrcp_client_config_load(client,doc,pool);
+       }
+
+       return client;
+}
+
+/** Parse config file */
+static apr_xml_doc* unimrcp_client_config_parse(const char *dir_path, apr_pool_t *pool)
+{
+       apr_xml_parser *parser = NULL;
+       apr_xml_doc *doc = NULL;
+       apr_file_t *fd = NULL;
+       apr_status_t rv;
+       const char *file_path;
+
+       if(!dir_path) {
+               dir_path = DEFAULT_CONF_DIR_PATH;
+       }
+       if(*dir_path == '\0') {
+               file_path = CONF_FILE_NAME;
+       }
+       else {
+               file_path = apr_psprintf(pool,"%s/%s",dir_path,CONF_FILE_NAME);
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Open Config File [%s]",file_path);
+       rv = apr_file_open(&fd,file_path,APR_READ|APR_BINARY,0,pool);
+       if(rv != APR_SUCCESS) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Open Config File [%s]",file_path);
+               return NULL;
+       }
+
+       rv = apr_xml_parse_file(pool,&parser,&doc,fd,XML_FILE_BUFFER_LENGTH);
+       if(rv != APR_SUCCESS) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse Config File [%s]",file_path);
+               return NULL;
+       }
+
+       apr_file_close(fd);
+       return doc;
+}
+
+static apt_bool_t param_name_value_get(const apr_xml_elem *elem, const apr_xml_attr **name, const apr_xml_attr **value)
+{
+       const apr_xml_attr *attr;
+       if(!name || !value) {
+               return FALSE;
+       }
+
+       *name = NULL;
+       *value = NULL;
+       for(attr = elem->attr; attr; attr = attr->next) {
+               if(strcasecmp(attr->name,"name") == 0) {
+                       *name = attr;
+               }
+               else if(strcasecmp(attr->name,"value") == 0) {
+                       *value = attr;
+               }
+       }
+       return (*name && *value) ? TRUE : FALSE;
+}
+
+static char* ip_addr_get(const char *value, apr_pool_t *pool)
+{
+       if(!value || strcasecmp(value,"auto") == 0) {
+               char *addr = DEFAULT_LOCAL_IP_ADDRESS;
+               apt_ip_get(&addr,pool);
+               return addr;
+       }
+       return apr_pstrdup(pool,value);
+}
+
+/** Load map of MRCP resource names */
+static apt_bool_t resource_map_load(apr_table_t *resource_map, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_attr *attr_name;
+       const apr_xml_attr *attr_value;
+       const apr_xml_elem *elem;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Resource Map");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"param") == 0) {
+                       if(param_name_value_get(elem,&attr_name,&attr_value) == TRUE) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Param %s:%s",attr_name->value,attr_value->value);
+                               apr_table_set(resource_map,attr_name->value,attr_value->value);
+                       }
+               }
+       }    
+       return TRUE;
+}
+
+/** Load SofiaSIP signaling agent */
+static mrcp_sig_agent_t* unimrcp_client_sofiasip_agent_load(mrcp_client_t *client, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       mrcp_sofia_client_config_t *config = mrcp_sofiasip_client_config_alloc(pool);
+       config->local_ip = DEFAULT_LOCAL_IP_ADDRESS;
+       config->local_port = DEFAULT_SIP_LOCAL_PORT;
+       config->remote_ip = DEFAULT_REMOTE_IP_ADDRESS;
+       config->remote_port = DEFAULT_SIP_REMOTE_PORT;
+       config->ext_ip = NULL;
+       config->user_agent_name = DEFAULT_SOFIASIP_UA_NAME;
+       config->origin = DEFAULT_SDP_ORIGIN;
+
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading SofiaSIP Agent");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"param") == 0) {
+                       const apr_xml_attr *attr_name;
+                       const apr_xml_attr *attr_value;
+                       if(param_name_value_get(elem,&attr_name,&attr_value) == TRUE) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Param %s:%s",attr_name->value,attr_value->value);
+                               if(strcasecmp(attr_name->value,"client-ip") == 0) {
+                                       config->local_ip = ip_addr_get(attr_value->value,pool);
+                               }
+                               else if(strcasecmp(attr_name->value,"client-ext-ip") == 0) {
+                                       config->ext_ip = ip_addr_get(attr_value->value,pool);
+                               }
+                               else if(strcasecmp(attr_name->value,"client-port") == 0) {
+                                       config->local_port = (apr_port_t)atol(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"server-ip") == 0) {
+                                       config->remote_ip = ip_addr_get(attr_value->value,pool);
+                               }
+                               else if(strcasecmp(attr_name->value,"server-port") == 0) {
+                                       config->remote_port = (apr_port_t)atol(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"server-username") == 0) {
+                                       config->remote_user_name = apr_pstrdup(pool,attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"force-destination") == 0) {
+                                       config->force_destination = atoi(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"sip-transport") == 0) {
+                                       config->transport = apr_pstrdup(pool,attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"ua-name") == 0) {
+                                       config->user_agent_name = apr_pstrdup(pool,attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"sdp-origin") == 0) {
+                                       config->origin = apr_pstrdup(pool,attr_value->value);
+                               }
+                               else {
+                                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr_name->value);
+                               }
+                       }
+               }
+       }    
+       return mrcp_sofiasip_client_agent_create(config,pool);
+}
+
+/** Load UniRTSP signaling agent */
+static mrcp_sig_agent_t* unimrcp_client_rtsp_agent_load(mrcp_client_t *client, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       rtsp_client_config_t *config = mrcp_unirtsp_client_config_alloc(pool);
+       config->origin = DEFAULT_SDP_ORIGIN;
+       config->resource_location = DEFAULT_RESOURCE_LOCATION;
+
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading UniRTSP Agent");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"param") == 0) {
+                       const apr_xml_attr *attr_name;
+                       const apr_xml_attr *attr_value;
+                       if(param_name_value_get(elem,&attr_name,&attr_value) == TRUE) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Param %s:%s",attr_name->value,attr_value->value);
+                               if(strcasecmp(attr_name->value,"server-ip") == 0) {
+                                       config->server_ip = ip_addr_get(attr_value->value,pool);
+                               }
+                               else if(strcasecmp(attr_name->value,"server-port") == 0) {
+                                       config->server_port = (apr_port_t)atol(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"resource-location") == 0) {
+                                       config->resource_location = apr_pstrdup(pool,attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"sdp-origin") == 0) {
+                                       config->origin = apr_pstrdup(pool,attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"max-connection-count") == 0) {
+                                       config->max_connection_count = atol(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"force-destination") == 0) {
+                                       config->force_destination = atoi(attr_value->value);
+                               }
+                               else {
+                                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr_name->value);
+                               }
+                       }
+               }
+               else if(strcasecmp(elem->name,"resourcemap") == 0) {
+                       resource_map_load(config->resource_map,elem,pool);
+               }
+       }    
+       return mrcp_unirtsp_client_agent_create(config,pool);
+}
+
+/** Load signaling agents */
+static apt_bool_t unimrcp_client_signaling_agents_load(mrcp_client_t *client, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Signaling Agents");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"agent") == 0) {
+                       mrcp_sig_agent_t *sig_agent = NULL;
+                       const char *name = NULL;
+                       const apr_xml_attr *attr;
+                       for(attr = elem->attr; attr; attr = attr->next) {
+                               if(strcasecmp(attr->name,"name") == 0) {
+                                       name = apr_pstrdup(pool,attr->value);
+                               }
+                               else if(strcasecmp(attr->name,"class") == 0) {
+                                       if(strcasecmp(attr->value,"SofiaSIP") == 0) {
+                                               sig_agent = unimrcp_client_sofiasip_agent_load(client,elem,pool);
+                                       }
+                                       else if(strcasecmp(attr->value,"UniRTSP") == 0) {
+                                               sig_agent = unimrcp_client_rtsp_agent_load(client,elem,pool);
+                                       }
+                               }
+                               else {
+                                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name);
+                               }
+                       }
+                       if(sig_agent) {
+                               mrcp_client_signaling_agent_register(client,sig_agent,name);
+                       }
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name);
+               }
+       }    
+       return TRUE;
+}
+
+/** Load MRCPv2 connection agent */
+static mrcp_connection_agent_t* unimrcp_client_connection_agent_load(mrcp_client_t *client, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       apr_size_t max_connection_count = 100;
+       apt_bool_t offer_new_connection = FALSE;
+
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading MRCPv2 Agent");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"param") == 0) {
+                       const apr_xml_attr *attr_name;
+                       const apr_xml_attr *attr_value;
+                       if(param_name_value_get(elem,&attr_name,&attr_value) == TRUE) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Param %s:%s",attr_name->value,attr_value->value);
+                               if(strcasecmp(attr_name->value,"max-connection-count") == 0) {
+                                       max_connection_count = atol(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"offer-new-connection") == 0) {
+                                       offer_new_connection = atoi(attr_value->value);
+                               }
+                               else {
+                                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr_name->value);
+                               }
+                       }
+               }
+       }    
+       return mrcp_client_connection_agent_create(max_connection_count,offer_new_connection,pool);
+}
+
+/** Load MRCPv2 conection agents */
+static apt_bool_t unimrcp_client_connection_agents_load(mrcp_client_t *client, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Connection Agents");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"agent") == 0) {
+                       mrcp_connection_agent_t *connection_agent;
+                       const char *name = NULL;
+                       const apr_xml_attr *attr;
+                       for(attr = elem->attr; attr; attr = attr->next) {
+                               if(strcasecmp(attr->name,"name") == 0) {
+                                       name = apr_pstrdup(pool,attr->value);
+                               }
+                               else {
+                                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name);
+                               }
+                       }
+                       connection_agent = unimrcp_client_connection_agent_load(client,elem,pool);
+                       if(connection_agent) {
+                               mrcp_client_connection_agent_register(client,connection_agent,name);
+                       }
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name);
+               }
+       }    
+       return TRUE;
+}
+
+/** Load RTP termination factory */
+static mpf_termination_factory_t* unimrcp_client_rtp_factory_load(mrcp_client_t *client, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       char *rtp_ip = DEFAULT_LOCAL_IP_ADDRESS;
+       char *rtp_ext_ip = NULL;
+       mpf_rtp_config_t *rtp_config = mpf_rtp_config_create(pool);
+       rtp_config->rtp_port_min = DEFAULT_RTP_PORT_MIN;
+       rtp_config->rtp_port_max = DEFAULT_RTP_PORT_MAX;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading RTP Termination Factory");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"param") == 0) {
+                       const apr_xml_attr *attr_name;
+                       const apr_xml_attr *attr_value;
+                       if(param_name_value_get(elem,&attr_name,&attr_value) == TRUE) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Param %s:%s",attr_name->value,attr_value->value);
+                               if(strcasecmp(attr_name->value,"rtp-ip") == 0) {
+                                       rtp_ip = ip_addr_get(attr_value->value,pool);
+                               }
+                               else if(strcasecmp(attr_name->value,"rtp-ext-ip") == 0) {
+                                       rtp_ext_ip = ip_addr_get(attr_value->value,pool);
+                               }
+                               else if(strcasecmp(attr_name->value,"rtp-port-min") == 0) {
+                                       rtp_config->rtp_port_min = (apr_port_t)atol(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"rtp-port-max") == 0) {
+                                       rtp_config->rtp_port_max = (apr_port_t)atol(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"playout-delay") == 0) {
+                                       rtp_config->jb_config.initial_playout_delay = atol(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"min-playout-delay") == 0) {
+                                       rtp_config->jb_config.min_playout_delay = atol(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"max-playout-delay") == 0) {
+                                       rtp_config->jb_config.max_playout_delay = atol(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"codecs") == 0) {
+                                       const mpf_codec_manager_t *codec_manager = mrcp_client_codec_manager_get(client);
+                                       if(codec_manager) {
+                                               mpf_codec_manager_codec_list_load(codec_manager,&rtp_config->codec_list,attr_value->value,pool);
+                                       }
+                               }
+                               else if(strcasecmp(attr_name->value,"ptime") == 0) {
+                                       rtp_config->ptime = (apr_uint16_t)atol(attr_value->value);
+                               }
+                               else {
+                                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr_name->value);
+                               }
+                       }
+               }
+       }    
+       apt_string_set(&rtp_config->ip,rtp_ip);
+       if(rtp_ext_ip) {
+               apt_string_set(&rtp_config->ext_ip,rtp_ext_ip);
+       }
+       return mpf_rtp_termination_factory_create(rtp_config,pool);
+}
+
+/** Load media engines */
+static apt_bool_t unimrcp_client_media_engines_load(mrcp_client_t *client, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Media Engines");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"engine") == 0) {
+                       mpf_engine_t *media_engine;
+                       const char *name = NULL;
+                       const apr_xml_attr *attr;
+                       for(attr = elem->attr; attr; attr = attr->next) {
+                               if(strcasecmp(attr->name,"name") == 0) {
+                                       name = apr_pstrdup(pool,attr->value);
+                               }
+                               else {
+                                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name);
+                               }
+                       }
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Media Engine");
+                       media_engine = mpf_engine_create(pool);
+                       if(media_engine) {
+                               mrcp_client_media_engine_register(client,media_engine,name);
+                       }
+               }
+               else if(strcasecmp(elem->name,"rtp") == 0) {
+                       mpf_termination_factory_t *rtp_factory;
+                       const char *name = NULL;
+                       const apr_xml_attr *attr;
+                       for(attr = elem->attr; attr; attr = attr->next) {
+                               if(strcasecmp(attr->name,"name") == 0) {
+                                       name = apr_pstrdup(pool,attr->value);
+                               }
+                               else {
+                                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name);
+                               }
+                       }
+                       rtp_factory = unimrcp_client_rtp_factory_load(client,elem,pool);
+                       if(rtp_factory) {
+                               mrcp_client_rtp_factory_register(client,rtp_factory,name);
+                       }
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name);
+               }
+       }    
+       return TRUE;
+}
+
+/** Load settings */
+static apt_bool_t unimrcp_client_settings_load(mrcp_client_t *client, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Settings");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"signaling") == 0) {
+                       unimrcp_client_signaling_agents_load(client,elem,pool);
+               }
+               else if(strcasecmp(elem->name,"connection") == 0) {
+                       unimrcp_client_connection_agents_load(client,elem,pool);
+               }
+               else if(strcasecmp(elem->name,"media") == 0) {
+                       unimrcp_client_media_engines_load(client,elem,pool);
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name);
+               }
+       }    
+       return TRUE;
+}
+
+/** Load profile */
+static apt_bool_t unimrcp_client_profile_load(mrcp_client_t *client, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const char *name = NULL;
+       mrcp_profile_t *profile;
+       mrcp_sig_agent_t *sig_agent = NULL;
+       mrcp_connection_agent_t *cnt_agent = NULL;
+       mpf_engine_t *media_engine = NULL;
+       mpf_termination_factory_t *rtp_factory = NULL;
+       const apr_xml_elem *elem;
+       const apr_xml_attr *attr;
+       for(attr = root->attr; attr; attr = attr->next) {
+               if(strcasecmp(attr->name,"name") == 0) {
+                       name = apr_pstrdup(pool,attr->value);
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Profile [%s]",name);
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name);
+               }
+       }
+       if(!name) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Load Profile: no profile name specified");
+               return FALSE;
+       }
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"param") == 0) {
+                       const apr_xml_attr *attr_name;
+                       const apr_xml_attr *attr_value;
+                       if(param_name_value_get(elem,&attr_name,&attr_value) == TRUE) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Loading Profile %s [%s]",attr_name->value,attr_value->value);
+                               if(strcasecmp(attr_name->value,"signaling-agent") == 0) {
+                                       sig_agent = mrcp_client_signaling_agent_get(client,attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"connection-agent") == 0) {
+                                       cnt_agent = mrcp_client_connection_agent_get(client,attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"media-engine") == 0) {
+                                       media_engine = mrcp_client_media_engine_get(client,attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"rtp-factory") == 0) {
+                                       rtp_factory = mrcp_client_rtp_factory_get(client,attr_value->value);
+                               }
+                               else {
+                                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr_name->value);
+                               }
+                       }
+               }
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create Profile [%s]",name);
+       profile = mrcp_client_profile_create(NULL,sig_agent,cnt_agent,media_engine,rtp_factory,pool);
+       return mrcp_client_profile_register(client,profile,name);
+}
+
+/** Load profiles */
+static apt_bool_t unimrcp_client_profiles_load(mrcp_client_t *client, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Profiles");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"profile") == 0) {
+                       unimrcp_client_profile_load(client,elem,pool);
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name);
+               }
+       }
+    return TRUE;
+}
+
+/** Load configuration (settings and profiles) */
+static apt_bool_t unimrcp_client_config_load(mrcp_client_t *client, const apr_xml_doc *doc, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       const apr_xml_elem *root = doc->root;
+       if(!root || strcasecmp(root->name,"unimrcpclient") != 0) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Document");
+               return FALSE;
+       }
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"settings") == 0) {
+                       unimrcp_client_settings_load(client,elem,pool);
+               }
+               else if(strcasecmp(elem->name,"profiles") == 0) {
+                       unimrcp_client_profiles_load(client,elem,pool);
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name);
+               }
+       }
+    
+       return TRUE;
+}
diff --git a/libs/unimrcp/platforms/libunimrcp-server/Makefile.am b/libs/unimrcp/platforms/libunimrcp-server/Makefile.am
new file mode 100644 (file)
index 0000000..a67510e
--- /dev/null
@@ -0,0 +1,36 @@
+MAINTAINERCLEANFILES       = Makefile.in
+
+INCLUDES                    = -I$(top_srcdir)/platforms/libunimrcp-server/include \
+                              -I$(top_srcdir)/modules/mrcp-sofiasip/include \
+                              -I$(top_srcdir)/modules/mrcp-unirtsp/include \
+                              -I$(top_srcdir)/libs/mrcp-server/include \
+                              -I$(top_srcdir)/libs/mrcp-engine/include \
+                              -I$(top_srcdir)/libs/mrcp-signaling/include \
+                              -I$(top_srcdir)/libs/mrcpv2-transport/include \
+                              -I$(top_srcdir)/libs/mrcp/include \
+                              -I$(top_srcdir)/libs/mrcp/message/include \
+                              -I$(top_srcdir)/libs/mrcp/control/include \
+                              -I$(top_srcdir)/libs/mrcp/resources/include \
+                              -I$(top_srcdir)/libs/mpf/include \
+                              -I$(top_srcdir)/libs/apr-toolkit/include \
+                              -I$(top_srcdir)/build \
+                              $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+lib_LTLIBRARIES             = libunimrcpserver.la
+
+include_HEADERS             = include/unimrcp_server.h
+
+libunimrcpserver_la_SOURCES = src/unimrcp_server.c
+
+libunimrcpserver_la_LIBADD  = $(top_builddir)/modules/mrcp-sofiasip/libmrcpsofiasip.la \
+                              $(top_builddir)/modules/mrcp-unirtsp/libmrcpunirtsp.la \
+                              $(top_builddir)/libs/mrcp-server/libmrcpserver.la \
+                              $(top_builddir)/libs/mrcp-signaling/libmrcpsignaling.la \
+                              $(top_builddir)/libs/mrcpv2-transport/libmrcpv2transport.la \
+                              $(top_builddir)/libs/mrcp-engine/libmrcpengine.la \
+                              $(top_builddir)/libs/mrcp/libmrcp.la \
+                              $(top_builddir)/libs/mpf/libmpf.la \
+                              $(top_builddir)/libs/apr-toolkit/libaprtoolkit.la \
+                              $(UNIMRCP_APR_LIBS) $(UNIMRCP_APU_LIBS) $(UNIMRCP_SOFIA_LIBS)
+
+libunimrcpserver_la_LDFLAGS = $(UNI_LT_VERSION)
diff --git a/libs/unimrcp/platforms/libunimrcp-server/include/unimrcp_server.h b/libs/unimrcp/platforms/libunimrcp-server/include/unimrcp_server.h
new file mode 100644 (file)
index 0000000..39f3813
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UNIMRCP_SERVER_H__
+#define __UNIMRCP_SERVER_H__
+
+/**
+ * @file unimrcp_server.h
+ * @brief UniMRCP Server
+ */ 
+
+#include "mrcp_server.h"
+
+APT_BEGIN_EXTERN_C
+
+/** 
+ * Start UniMRCP server.
+ * @param dir_layout the dir layout structure
+ */
+MRCP_DECLARE(mrcp_server_t*) unimrcp_server_start(apt_dir_layout_t *dir_layout);
+
+/** 
+ * Shutdown UniMRCP server.
+ * @param server the MRCP server to shutdown
+ */
+MRCP_DECLARE(apt_bool_t) unimrcp_server_shutdown(mrcp_server_t *server);
+
+APT_END_EXTERN_C
+
+#endif /*__UNIMRCP_SERVER_H__*/
diff --git a/libs/unimrcp/platforms/libunimrcp-server/libunimrcpserver.vcproj b/libs/unimrcp/platforms/libunimrcp-server/libunimrcpserver.vcproj
new file mode 100644 (file)
index 0000000..0a89e9d
--- /dev/null
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="libunimrcpserver"
+       ProjectGUID="{C98AF157-352E-4737-BD30-A24E2647F5AE}"
+       RootNamespace="libunimrcpserver"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\unimrcpserver.vsprops"
+                       CharacterSet="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="&quot;$(ProjectRootDir)modules\mrcp-sofiasip\include&quot;;&quot;$(ProjectRootDir)modules\mrcp-unirtsp\include&quot;"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\unimrcpserver.vsprops"
+                       CharacterSet="1"
+                       WholeProgramOptimization="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="&quot;$(ProjectRootDir)modules\mrcp-sofiasip\include&quot;;&quot;$(ProjectRootDir)modules\mrcp-unirtsp\include&quot;"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+                       <File
+                               RelativePath="..\..\build\uni_version.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\unimrcp_server.h"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       >
+                       <File
+                               RelativePath=".\src\unimrcp_server.c"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/platforms/libunimrcp-server/src/unimrcp_server.c b/libs/unimrcp/platforms/libunimrcp-server/src/unimrcp_server.c
new file mode 100644 (file)
index 0000000..f95e62f
--- /dev/null
@@ -0,0 +1,701 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_xml.h>
+#include "unimrcp_server.h"
+#include "uni_version.h"
+#include "mrcp_default_factory.h"
+#include "mpf_engine.h"
+#include "mpf_codec_manager.h"
+#include "mpf_rtp_termination_factory.h"
+#include "mrcp_sofiasip_server_agent.h"
+#include "mrcp_unirtsp_server_agent.h"
+#include "mrcp_server_connection.h"
+#include "apt_net.h"
+#include "apt_log.h"
+
+#define CONF_FILE_NAME            "unimrcpserver.xml"
+#define DEFAULT_CONF_DIR_PATH     "../conf"
+#define DEFAULT_PLUGIN_DIR_PATH   "../plugin"
+#ifdef WIN32
+#define DEFAULT_PLUGIN_EXT        "dll"
+#else
+#define DEFAULT_PLUGIN_EXT        "so"
+#endif
+
+#define DEFAULT_IP_ADDRESS        "127.0.0.1"
+#define DEFAULT_SIP_PORT          8060
+#define DEFAULT_RTSP_PORT         1554
+#define DEFAULT_MRCP_PORT         1544
+#define DEFAULT_RTP_PORT_MIN      5000
+#define DEFAULT_RTP_PORT_MAX      6000
+
+#define DEFAULT_SOFIASIP_UA_NAME  "UniMRCP SofiaSIP"
+#define DEFAULT_SDP_ORIGIN        "UniMRCPServer"
+
+#define XML_FILE_BUFFER_LENGTH    2000
+
+static apr_xml_doc* unimrcp_server_config_parse(const char *path, apr_pool_t *pool);
+static apt_bool_t unimrcp_server_config_load(mrcp_server_t *server, const char *plugin_dir_path, const apr_xml_doc *doc, apr_pool_t *pool);
+
+/** Start UniMRCP server */
+MRCP_DECLARE(mrcp_server_t*) unimrcp_server_start(apt_dir_layout_t *dir_layout)
+{
+       apr_pool_t *pool;
+       apr_xml_doc *doc;
+       mrcp_resource_factory_t *resource_factory;
+       mpf_codec_manager_t *codec_manager;
+       mrcp_server_t *server;
+
+       if(!dir_layout) {
+               return NULL;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"UniMRCP Server ["UNI_VERSION_STRING"]");
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"APR ["APR_VERSION_STRING"]");
+       server = mrcp_server_create(dir_layout);
+       if(!server) {
+               return NULL;
+       }
+       pool = mrcp_server_memory_pool_get(server);
+       if(!pool) {
+               return NULL;
+       }
+
+       resource_factory = mrcp_default_factory_create(pool);
+       if(resource_factory) {
+               mrcp_server_resource_factory_register(server,resource_factory);
+       }
+
+       codec_manager = mpf_engine_codec_manager_create(pool);
+       if(codec_manager) {
+               mrcp_server_codec_manager_register(server,codec_manager);
+       }
+
+       doc = unimrcp_server_config_parse(dir_layout->conf_dir_path,pool);
+       if(doc) {
+               unimrcp_server_config_load(server,dir_layout->plugin_dir_path,doc,pool);
+       }
+
+       mrcp_server_start(server);
+       return server;
+}
+
+/** Shutdown UniMRCP server */
+MRCP_DECLARE(apt_bool_t) unimrcp_server_shutdown(mrcp_server_t *server)
+{
+       if(mrcp_server_shutdown(server) == FALSE) {
+               return FALSE;
+       }
+       return mrcp_server_destroy(server);
+}
+
+
+/** Parse config file */
+static apr_xml_doc* unimrcp_server_config_parse(const char *dir_path, apr_pool_t *pool)
+{
+       apr_xml_parser *parser = NULL;
+       apr_xml_doc *doc = NULL;
+       apr_file_t *fd = NULL;
+       apr_status_t rv;
+       const char *file_path;
+
+       if(!dir_path) {
+               dir_path = DEFAULT_CONF_DIR_PATH;
+       }
+       if(*dir_path == '\0') {
+               file_path = CONF_FILE_NAME;
+       }
+       else {
+               file_path = apr_psprintf(pool,"%s/%s",dir_path,CONF_FILE_NAME);
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Open Config File [%s]",file_path);
+       rv = apr_file_open(&fd,file_path,APR_READ|APR_BINARY,0,pool);
+       if(rv != APR_SUCCESS) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Open Config File [%s]",file_path);
+               return NULL;
+       }
+
+       rv = apr_xml_parse_file(pool,&parser,&doc,fd,XML_FILE_BUFFER_LENGTH);
+       if(rv != APR_SUCCESS) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse Config File [%s]",file_path);
+               return NULL;
+       }
+
+       apr_file_close(fd);
+       return doc;
+}
+
+static apt_bool_t param_name_value_get(const apr_xml_elem *elem, const apr_xml_attr **name, const apr_xml_attr **value)
+{
+       const apr_xml_attr *attr;
+       if(!name || !value) {
+               return FALSE;
+       }
+
+       *name = NULL;
+       *value = NULL;
+       for(attr = elem->attr; attr; attr = attr->next) {
+               if(strcasecmp(attr->name,"name") == 0) {
+                       *name = attr;
+               }
+               else if(strcasecmp(attr->name,"value") == 0) {
+                       *value = attr;
+               }
+       }
+       return (*name && *value) ? TRUE : FALSE;
+}
+
+static char* ip_addr_get(const char *value, apr_pool_t *pool)
+{
+       if(!value || strcasecmp(value,"auto") == 0) {
+               char *addr = DEFAULT_IP_ADDRESS;
+               apt_ip_get(&addr,pool);
+               return addr;
+       }
+       return apr_pstrdup(pool,value);
+}
+
+/** Load map of MRCP resource names */
+static apt_bool_t resource_map_load(apr_table_t *resource_map, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_attr *attr_name;
+       const apr_xml_attr *attr_value;
+       const apr_xml_elem *elem;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Resource Map");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"param") == 0) {
+                       if(param_name_value_get(elem,&attr_name,&attr_value) == TRUE) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Param %s:%s",attr_name->value,attr_value->value);
+                               apr_table_set(resource_map,attr_name->value,attr_value->value);
+                       }
+               }
+       }    
+       return TRUE;
+}
+
+/** Load map of plugins */
+static apt_bool_t plugin_map_load(apr_table_t *plugin_map, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_attr *attr_name;
+       const apr_xml_attr *attr_value;
+       const apr_xml_elem *elem;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Plugin Map");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"param") == 0) {
+                       if(param_name_value_get(elem,&attr_name,&attr_value) == TRUE) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Param %s:%s",attr_name->value,attr_value->value);
+                               apr_table_set(plugin_map,attr_name->value,attr_value->value);
+                       }
+               }
+       }    
+       return TRUE;
+}
+
+/** Load SofiaSIP signaling agent */
+static mrcp_sig_agent_t* unimrcp_server_sofiasip_agent_load(mrcp_server_t *server, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       mrcp_sofia_server_config_t *config = mrcp_sofiasip_server_config_alloc(pool);
+       config->local_ip = DEFAULT_IP_ADDRESS;
+       config->local_port = DEFAULT_SIP_PORT;
+       config->ext_ip = NULL;
+       config->user_agent_name = DEFAULT_SOFIASIP_UA_NAME;
+       config->origin = DEFAULT_SDP_ORIGIN;
+
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading SofiaSIP Agent");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"param") == 0) {
+                       const apr_xml_attr *attr_name;
+                       const apr_xml_attr *attr_value;
+                       if(param_name_value_get(elem,&attr_name,&attr_value) == TRUE) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Param %s:%s",attr_name->value,attr_value->value);
+                               if(strcasecmp(attr_name->value,"sip-ip") == 0) {
+                                       config->local_ip = ip_addr_get(attr_value->value,pool);
+                               }
+                               else if(strcasecmp(attr_name->value,"sip-ext-ip") == 0) {
+                                       config->ext_ip = ip_addr_get(attr_value->value,pool);
+                               }
+                               else if(strcasecmp(attr_name->value,"sip-port") == 0) {
+                                       config->local_port = (apr_port_t)atol(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"sip-transport") == 0) {
+                                       config->transport = apr_pstrdup(pool,attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"ua-name") == 0) {
+                                       config->user_agent_name = apr_pstrdup(pool,attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"sdp-origin") == 0) {
+                                       config->origin = apr_pstrdup(pool,attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"force-destination") == 0) {
+                                       config->force_destination = atoi(attr_value->value);
+                               }
+                               else {
+                                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr_name->value);
+                               }
+                       }
+               }
+       }    
+       return mrcp_sofiasip_server_agent_create(config,pool);
+}
+
+/** Load UniRTSP signaling agent */
+static mrcp_sig_agent_t* unimrcp_server_rtsp_agent_load(mrcp_server_t *server, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       rtsp_server_config_t *config = mrcp_unirtsp_server_config_alloc(pool);
+       config->local_ip = DEFAULT_IP_ADDRESS;
+       config->local_port = DEFAULT_RTSP_PORT;
+       config->origin = DEFAULT_SDP_ORIGIN;
+
+
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading UniRTSP Agent");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"param") == 0) {
+                       const apr_xml_attr *attr_name;
+                       const apr_xml_attr *attr_value;
+                       if(param_name_value_get(elem,&attr_name,&attr_value) == TRUE) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Param %s:%s",attr_name->value,attr_value->value);
+                               if(strcasecmp(attr_name->value,"rtsp-ip") == 0) {
+                                       config->local_ip = ip_addr_get(attr_value->value,pool);
+                               }
+                               else if(strcasecmp(attr_name->value,"rtsp-port") == 0) {
+                                       config->local_port = (apr_port_t)atol(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"sdp-origin") == 0) {
+                                       config->origin = apr_pstrdup(pool,attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"max-connection-count") == 0) {
+                                       config->max_connection_count = atol(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"force-destination") == 0) {
+                                       config->force_destination = atoi(attr_value->value);
+                               }
+                               else {
+                                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr_name->value);
+                               }
+                       }
+               }
+               else if(strcasecmp(elem->name,"resourcemap") == 0) {
+                       resource_map_load(config->resource_map,elem,pool);
+               }
+       }
+       return mrcp_unirtsp_server_agent_create(config,pool);
+}
+
+/** Load signaling agents */
+static apt_bool_t unimrcp_server_signaling_agents_load(mrcp_server_t *server, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Signaling Agents");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"agent") == 0) {
+                       mrcp_sig_agent_t *sig_agent = NULL;
+                       const char *name = NULL;
+                       const apr_xml_attr *attr;
+                       for(attr = elem->attr; attr; attr = attr->next) {
+                               if(strcasecmp(attr->name,"name") == 0) {
+                                       name = apr_pstrdup(pool,attr->value);
+                               }
+                               else if(strcasecmp(attr->name,"class") == 0) {
+                                       if(strcasecmp(attr->value,"SofiaSIP") == 0) {
+                                               sig_agent = unimrcp_server_sofiasip_agent_load(server,elem,pool);
+                                       }
+                                       else if(strcasecmp(attr->value,"UniRTSP") == 0) {
+                                               sig_agent = unimrcp_server_rtsp_agent_load(server,elem,pool);
+                                       }
+                               }
+                               else {
+                                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name);
+                               }
+                       }
+                       if(sig_agent) {
+                               mrcp_server_signaling_agent_register(server,sig_agent,name);
+                       }
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name);
+               }
+       }    
+       return TRUE;
+}
+
+/** Load MRCPv2 connection agent */
+static mrcp_connection_agent_t* unimrcp_server_connection_agent_load(mrcp_server_t *server, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       char *mrcp_ip = DEFAULT_IP_ADDRESS;
+       apr_port_t mrcp_port = DEFAULT_MRCP_PORT;
+       apr_size_t max_connection_count = 100;
+       apt_bool_t force_new_connection = FALSE;
+
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading MRCPv2 Agent");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"param") == 0) {
+                       const apr_xml_attr *attr_name;
+                       const apr_xml_attr *attr_value;
+                       if(param_name_value_get(elem,&attr_name,&attr_value) == TRUE) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Param %s:%s",attr_name->value,attr_value->value);
+                               if(strcasecmp(attr_name->value,"mrcp-ip") == 0) {
+                                       mrcp_ip = ip_addr_get(attr_value->value,pool);
+                               }
+                               else if(strcasecmp(attr_name->value,"mrcp-port") == 0) {
+                                       mrcp_port = (apr_port_t)atol(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"max-connection-count") == 0) {
+                                       max_connection_count = atol(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"force-new-connection") == 0) {
+                                       force_new_connection = atoi(attr_value->value);
+                               }
+                               else {
+                                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr_name->value);
+                               }
+                       }
+               }
+       }    
+       return mrcp_server_connection_agent_create(mrcp_ip,mrcp_port,max_connection_count,force_new_connection,pool);
+}
+
+/** Load MRCPv2 conection agents */
+static apt_bool_t unimrcp_server_connection_agents_load(mrcp_server_t *server, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Connection Agents");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"agent") == 0) {
+                       mrcp_connection_agent_t *connection_agent;
+                       const char *name = NULL;
+                       const apr_xml_attr *attr;
+                       for(attr = elem->attr; attr; attr = attr->next) {
+                               if(strcasecmp(attr->name,"name") == 0) {
+                                       name = apr_pstrdup(pool,attr->value);
+                               }
+                               else {
+                                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name);
+                               }
+                       }
+                       connection_agent = unimrcp_server_connection_agent_load(server,elem,pool);
+                       if(connection_agent) {
+                               mrcp_server_connection_agent_register(server,connection_agent,name);
+                       }
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name);
+               }
+       }    
+       return TRUE;
+}
+
+/** Load RTP termination factory */
+static mpf_termination_factory_t* unimrcp_server_rtp_factory_load(mrcp_server_t *server, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       char *rtp_ip = DEFAULT_IP_ADDRESS;
+       char *rtp_ext_ip = NULL;
+       mpf_rtp_config_t *rtp_config = mpf_rtp_config_create(pool);
+       rtp_config->rtp_port_min = DEFAULT_RTP_PORT_MIN;
+       rtp_config->rtp_port_max = DEFAULT_RTP_PORT_MAX;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading RTP Termination Factory");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"param") == 0) {
+                       const apr_xml_attr *attr_name;
+                       const apr_xml_attr *attr_value;
+                       if(param_name_value_get(elem,&attr_name,&attr_value) == TRUE) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Param %s:%s",attr_name->value,attr_value->value);
+                               if(strcasecmp(attr_name->value,"rtp-ip") == 0) {
+                                       rtp_ip = ip_addr_get(attr_value->value,pool);
+                               }
+                               else if(strcasecmp(attr_name->value,"rtp-ext-ip") == 0) {
+                                       rtp_ext_ip = ip_addr_get(attr_value->value,pool);
+                               }
+                               else if(strcasecmp(attr_name->value,"rtp-port-min") == 0) {
+                                       rtp_config->rtp_port_min = (apr_port_t)atol(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"rtp-port-max") == 0) {
+                                       rtp_config->rtp_port_max = (apr_port_t)atol(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"playout-delay") == 0) {
+                                       rtp_config->jb_config.initial_playout_delay = atol(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"min-playout-delay") == 0) {
+                                       rtp_config->jb_config.min_playout_delay = atol(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"max-playout-delay") == 0) {
+                                       rtp_config->jb_config.max_playout_delay = atol(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"codecs") == 0) {
+                                       const mpf_codec_manager_t *codec_manager = mrcp_server_codec_manager_get(server);
+                                       if(codec_manager) {
+                                               mpf_codec_manager_codec_list_load(codec_manager,&rtp_config->codec_list,attr_value->value,pool);
+                                       }
+                               }
+                               else if(strcasecmp(attr_name->value,"ptime") == 0) {
+                                       rtp_config->ptime = (apr_uint16_t)atol(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"own-preference") == 0) {
+                                       rtp_config->own_preferrence = atoi(attr_value->value);
+                               }
+                               else {
+                                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr_name->value);
+                               }
+                       }
+               }
+       }
+       apt_string_set(&rtp_config->ip,rtp_ip);
+       if(rtp_ext_ip) {
+               apt_string_set(&rtp_config->ext_ip,rtp_ext_ip);
+       }
+       return mpf_rtp_termination_factory_create(rtp_config,pool);
+}
+
+/** Load media engines */
+static apt_bool_t unimrcp_server_media_engines_load(mrcp_server_t *server, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Media Engines");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"engine") == 0) {
+                       mpf_engine_t *media_engine;
+                       const char *name = NULL;
+                       const apr_xml_attr *attr;
+                       for(attr = elem->attr; attr; attr = attr->next) {
+                               if(strcasecmp(attr->name,"name") == 0) {
+                                       name = apr_pstrdup(pool,attr->value);
+                               }
+                               else {
+                                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name);
+                               }
+                       }
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Media Engine");
+                       media_engine = mpf_engine_create(pool);
+                       if(media_engine) {
+                               mrcp_server_media_engine_register(server,media_engine,name);
+                       }
+               }
+               else if(strcasecmp(elem->name,"rtp") == 0) {
+                       mpf_termination_factory_t *rtp_factory;
+                       const char *name = NULL;
+                       const apr_xml_attr *attr;
+                       for(attr = elem->attr; attr; attr = attr->next) {
+                               if(strcasecmp(attr->name,"name") == 0) {
+                                       name = apr_pstrdup(pool,attr->value);
+                               }
+                               else {
+                                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name);
+                               }
+                       }
+                       rtp_factory = unimrcp_server_rtp_factory_load(server,elem,pool);
+                       if(rtp_factory) {
+                               mrcp_server_rtp_factory_register(server,rtp_factory,name);
+                       }
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name);
+               }
+       }    
+       return TRUE;
+}
+
+/** Load plugin */
+static apt_bool_t unimrcp_server_plugin_load(mrcp_server_t *server, const char *plugin_dir_path, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const char *plugin_name = NULL;
+       const char *plugin_class = NULL;
+       const char *plugin_ext = NULL;
+       const char *plugin_path = NULL;
+       apt_bool_t plugin_enabled = TRUE;
+       const apr_xml_attr *attr;
+       for(attr = root->attr; attr; attr = attr->next) {
+               if(strcasecmp(attr->name,"name") == 0) {
+                       plugin_name = apr_pstrdup(pool,attr->value);
+               }
+               else if(strcasecmp(attr->name,"class") == 0) {
+                       plugin_class = attr->value;
+               }
+               else if(strcasecmp(attr->name,"ext") == 0) {
+                       plugin_ext = attr->value;
+               }
+               else if(strcasecmp(attr->name,"enable") == 0) {
+                       plugin_enabled = atoi(attr->value);
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name);
+               }
+       }
+
+       if(!plugin_class || !plugin_enabled) {
+               return FALSE;
+       }
+       if(!plugin_dir_path) {
+               plugin_dir_path = DEFAULT_PLUGIN_DIR_PATH;
+       }
+       if(!plugin_ext) {
+               plugin_ext = DEFAULT_PLUGIN_EXT;
+       }
+
+       if(*plugin_dir_path == '\0') {
+               plugin_path = apr_psprintf(pool,"%s.%s",plugin_class,plugin_ext);
+       }
+       else {
+               plugin_path = apr_psprintf(pool,"%s/%s.%s",plugin_dir_path,plugin_class,plugin_ext);
+       }
+
+       return mrcp_server_plugin_register(server,plugin_path,plugin_name);
+}
+
+/** Load plugins */
+static apt_bool_t unimrcp_server_plugins_load(mrcp_server_t *server, const char *plugin_dir_path, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Plugins (Resource Engines)");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"engine") == 0) {
+                       unimrcp_server_plugin_load(server,plugin_dir_path,elem,pool);
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name);
+               }
+       }    
+       return TRUE;
+}
+
+
+/** Load settings */
+static apt_bool_t unimrcp_server_settings_load(mrcp_server_t *server, const char *plugin_dir_path, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Settings");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"signaling") == 0) {
+                       unimrcp_server_signaling_agents_load(server,elem,pool);
+               }
+               else if(strcasecmp(elem->name,"connection") == 0) {
+                       unimrcp_server_connection_agents_load(server,elem,pool);
+               }
+               else if(strcasecmp(elem->name,"media") == 0) {
+                       unimrcp_server_media_engines_load(server,elem,pool);
+               }
+               else if(strcasecmp(elem->name,"plugin") == 0) {
+                       unimrcp_server_plugins_load(server,plugin_dir_path,elem,pool);
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name);
+               }
+       }    
+       return TRUE;
+}
+
+/** Load profile */
+static apt_bool_t unimrcp_server_profile_load(mrcp_server_t *server, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const char *name = NULL;
+       mrcp_profile_t *profile;
+       mrcp_sig_agent_t *sig_agent = NULL;
+       mrcp_connection_agent_t *cnt_agent = NULL;
+       mpf_engine_t *media_engine = NULL;
+       mpf_termination_factory_t *rtp_factory = NULL;
+       apr_table_t *plugin_map = NULL;
+       const apr_xml_elem *elem;
+       const apr_xml_attr *attr;
+       for(attr = root->attr; attr; attr = attr->next) {
+               if(strcasecmp(attr->name,"name") == 0) {
+                       name = apr_pstrdup(pool,attr->value);
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Profile [%s]",name);
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name);
+               }
+       }
+       if(!name) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Load Profile: no profile name specified");
+               return FALSE;
+       }
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"param") == 0) {
+                       const apr_xml_attr *attr_name;
+                       const apr_xml_attr *attr_value;
+                       if(param_name_value_get(elem,&attr_name,&attr_value) == TRUE) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Loading Profile %s [%s]",attr_name->value,attr_value->value);
+                               if(strcasecmp(attr_name->value,"signaling-agent") == 0) {
+                                       sig_agent = mrcp_server_signaling_agent_get(server,attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"connection-agent") == 0) {
+                                       cnt_agent = mrcp_server_connection_agent_get(server,attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"media-engine") == 0) {
+                                       media_engine = mrcp_server_media_engine_get(server,attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"rtp-factory") == 0) {
+                                       rtp_factory = mrcp_server_rtp_factory_get(server,attr_value->value);
+                               }
+                               else {
+                                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr_name->value);
+                               }
+                       }
+               }
+               else if(strcasecmp(elem->name,"pluginmap") == 0) {
+                       plugin_map = apr_table_make(pool,2);
+                       plugin_map_load(plugin_map,elem,pool);
+               }
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create Profile [%s]",name);
+       profile = mrcp_server_profile_create(NULL,sig_agent,cnt_agent,media_engine,rtp_factory,pool);
+       return mrcp_server_profile_register(server,profile,plugin_map,name);
+}
+
+/** Load profiles */
+static apt_bool_t unimrcp_server_profiles_load(mrcp_server_t *server, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Profiles");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"profile") == 0) {
+                       unimrcp_server_profile_load(server,elem,pool);
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name);
+               }
+       }
+    return TRUE;
+}
+
+/** Load configuration (settings and profiles) */
+static apt_bool_t unimrcp_server_config_load(mrcp_server_t *server, const char *plugin_dir_path, const apr_xml_doc *doc, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       const apr_xml_elem *root = doc->root;
+       if(!root || strcasecmp(root->name,"unimrcpserver") != 0) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Document");
+               return FALSE;
+       }
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"settings") == 0) {
+                       unimrcp_server_settings_load(server,plugin_dir_path,elem,pool);
+               }
+               else if(strcasecmp(elem->name,"profiles") == 0) {
+                       unimrcp_server_profiles_load(server,elem,pool);
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name);
+               }
+       }
+    
+       return TRUE;
+}
diff --git a/libs/unimrcp/platforms/unimrcp-client/Makefile.am b/libs/unimrcp/platforms/unimrcp-client/Makefile.am
new file mode 100644 (file)
index 0000000..22fae8c
--- /dev/null
@@ -0,0 +1,24 @@
+MAINTAINERCLEANFILES   = Makefile.in
+
+INCLUDES               = -Iinclude \
+                         -I$(top_srcdir)/platforms/libunimrcp-client/include \
+                         -I$(top_srcdir)/libs/mrcp-client/include \
+                         -I$(top_srcdir)/libs/mrcp-signaling/include \
+                         -I$(top_srcdir)/libs/mrcpv2-transport/include \
+                         -I$(top_srcdir)/libs/mrcp/include \
+                         -I$(top_srcdir)/libs/mrcp/message/include \
+                         -I$(top_srcdir)/libs/mrcp/control/include \
+                         -I$(top_srcdir)/libs/mrcp/resources/include \
+                         -I$(top_srcdir)/libs/mpf/include \
+                         -I$(top_srcdir)/libs/apr-toolkit/include \
+                         $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+bin_PROGRAMS           = unimrcpclient
+unimrcpclient_SOURCES  = src/main.c \
+                         src/demo_framework.c \
+                         src/demo_synth_application.c \
+                         src/demo_recog_application.c \
+                         src/demo_bypass_application.c \
+                         src/demo_discover_application.c \
+                         src/demo_util.c
+unimrcpclient_LDADD    = $(top_builddir)/platforms/libunimrcp-client/libunimrcpclient.la
diff --git a/libs/unimrcp/platforms/unimrcp-client/include/demo_application.h b/libs/unimrcp/platforms/unimrcp-client/include/demo_application.h
new file mode 100644 (file)
index 0000000..608d996
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DEMO_APPLICATION_H__
+#define __DEMO_APPLICATION_H__
+
+/**
+ * @file demo_application.h
+ * @brief Demo MRCP Application
+ */ 
+
+#include "mrcp_application.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Demo application declaration */
+typedef struct demo_application_t demo_application_t;
+
+/** Demo application */
+struct demo_application_t {
+       /** MRCP application */
+       mrcp_application_t              *application;
+       /** Demo framework */
+       void                            *framework;
+
+       /** Virtual run method */
+       apt_bool_t (*run)(demo_application_t *application, const char *profile);
+       /** Virtual app_message handler */
+       apt_bool_t (*handler)(demo_application_t *application, const mrcp_app_message_t *app_message);
+};
+
+
+/** Create demo synthesizer application */
+demo_application_t* demo_synth_application_create(apr_pool_t *pool);
+
+/** Create demo recognizer application */
+demo_application_t* demo_recog_application_create(apr_pool_t *pool);
+
+/** Create demo bypass media application */
+demo_application_t* demo_bypass_application_create(apr_pool_t *pool);
+
+/** Create demo resource discover application */
+demo_application_t* demo_discover_application_create(apr_pool_t *pool);
+
+
+APT_END_EXTERN_C
+
+#endif /*__DEMO_APPLICATION_H__*/
diff --git a/libs/unimrcp/platforms/unimrcp-client/include/demo_framework.h b/libs/unimrcp/platforms/unimrcp-client/include/demo_framework.h
new file mode 100644 (file)
index 0000000..5cef923
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DEMO_FRAMEWORK_H__
+#define __DEMO_FRAMEWORK_H__
+
+/**
+ * @file demo_framework.h
+ * @brief Demo MRCP Application Framework
+ */ 
+
+#include "mrcp_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque demo framework declaration */
+typedef struct demo_framework_t demo_framework_t;
+
+/**
+ * Create demo framework.
+ */
+demo_framework_t* demo_framework_create(apt_dir_layout_t *dir_layout);
+
+/**
+ * Run demo application.
+ * @param framework the framework to run application for
+ * @param app_name the name of the application to run
+ * @param profile_name the name of the profile to use
+ */
+apt_bool_t demo_framework_app_run(demo_framework_t *framework, const char *app_name, const char *profile_name);
+
+/**
+ * Destroy demo framework.
+ * @param framework the framework to destroy
+ */
+apt_bool_t demo_framework_destroy(demo_framework_t *framework);
+
+APT_END_EXTERN_C
+
+#endif /*__DEMO_FRAMEWORK_H__*/
diff --git a/libs/unimrcp/platforms/unimrcp-client/include/demo_util.h b/libs/unimrcp/platforms/unimrcp-client/include/demo_util.h
new file mode 100644 (file)
index 0000000..78f8ef0
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DEMO_UTIL_H__
+#define __DEMO_UTIL_H__
+
+/**
+ * @file demo_util.h
+ * @brief Demo MRCP Utilities
+ */ 
+
+#include "mrcp_application.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Create demo MRCP message (SPEAK request) */
+mrcp_message_t* demo_speak_message_create(mrcp_session_t *session, mrcp_channel_t *channel, const apt_dir_layout_t *dir_layout);
+
+/** Create demo MRCP message (DEFINE-GRAMMAR request) */
+mrcp_message_t* demo_define_grammar_message_create(mrcp_session_t *session, mrcp_channel_t *channel, const apt_dir_layout_t *dir_layout);
+/** Create demo MRCP message (RECOGNIZE request) */
+mrcp_message_t* demo_recognize_message_create(mrcp_session_t *session, mrcp_channel_t *channel, const apt_dir_layout_t *dir_layout);
+
+
+/** Create demo RTP termination descriptor */
+mpf_rtp_termination_descriptor_t* demo_rtp_descriptor_create(apr_pool_t *pool);
+
+APT_END_EXTERN_C
+
+#endif /*__DEMO_UTIL_H__*/
diff --git a/libs/unimrcp/platforms/unimrcp-client/src/demo_bypass_application.c b/libs/unimrcp/platforms/unimrcp-client/src/demo_bypass_application.c
new file mode 100644 (file)
index 0000000..639b411
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* 
+ * Demo synthesizer scenario (client stack stays out of media path).
+ * C -> S: SIP INVITE or RTPS SETUP   (add synthesizer channel)
+ * S -> C: SIP OK or RTPS OK
+ * C -> S: MRCP SPEAK
+ * S -> C: MRCP IN-PROGRESS
+ * S -> X: RTP Start Transmission     (RTP stream is sent directly to external endpoint bypassing client stack)
+ * S -> C: MRCP SPEAK-COMPLETE
+ * S -> X: RTP Stop Transmission
+ * C -> S: SIP INVITE or RTPS SETUP   (optionally remove synthesizer channel)
+ * S -> C: SIP OK or RTPS OK
+ * C -> S: SIP BYE or RTPS TEARDOWN
+ * S -> C: SIP OK or RTPS OK
+ */
+
+#include "demo_application.h"
+#include "demo_util.h"
+#include "mrcp_session.h"
+#include "mrcp_message.h"
+#include "mrcp_generic_header.h"
+#include "mrcp_synth_header.h"
+#include "mrcp_synth_resource.h"
+#include "apt_log.h"
+
+typedef struct demo_app_channel_t demo_app_channel_t;
+
+/** Declaration of synthesizer application channel */
+struct demo_app_channel_t {
+       /** MRCP control channel */
+       mrcp_channel_t     *channel;
+};
+
+/** Declaration of demo application methods */
+static apt_bool_t demo_application_run(demo_application_t *demo_application, const char *profile);
+static apt_bool_t demo_application_handler(demo_application_t *application, const mrcp_app_message_t *app_message);
+
+static apt_bool_t demo_application_on_session_update(mrcp_application_t *application, mrcp_session_t *session, mrcp_sig_status_code_e status);
+static apt_bool_t demo_application_on_session_terminate(mrcp_application_t *application, mrcp_session_t *session, mrcp_sig_status_code_e status);
+static apt_bool_t demo_application_on_channel_add(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_sig_status_code_e status);
+static apt_bool_t demo_application_on_channel_remove(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_sig_status_code_e status);
+static apt_bool_t demo_application_on_message_receive(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_message_t *message);
+
+static const mrcp_app_message_dispatcher_t demo_application_dispatcher = {
+       demo_application_on_session_update,
+       demo_application_on_session_terminate,
+       demo_application_on_channel_add,
+       demo_application_on_channel_remove,
+       demo_application_on_message_receive
+};
+
+
+/** Create demo bypass media application */
+demo_application_t* demo_bypass_application_create(apr_pool_t *pool)
+{
+       demo_application_t *demo_application = apr_palloc(pool,sizeof(demo_application_t));
+       demo_application->application = NULL;
+       demo_application->framework = NULL;
+       demo_application->handler = demo_application_handler;
+       demo_application->run = demo_application_run;
+       return demo_application;
+}
+
+/** Create demo channel */
+static mrcp_channel_t* demo_application_channel_create(mrcp_session_t *session)
+{
+       mrcp_channel_t *channel;
+       /* create channel */
+       demo_app_channel_t *demo_channel = apr_palloc(session->pool,sizeof(demo_app_channel_t));
+       mpf_rtp_termination_descriptor_t *rtp_descriptor = demo_rtp_descriptor_create(session->pool);
+       channel = mrcp_application_channel_create(
+                       session,                     /* session, channel belongs to */
+                       MRCP_SYNTHESIZER_RESOURCE,   /* MRCP resource identifier */
+                       NULL,                        /* no termination (not to use internal media processing)  */
+                       rtp_descriptor,              /* RTP descriptor, used to create RTP termination */
+                       demo_channel);               /* object to associate */
+       return channel;
+}
+
+
+/** Run demo scenario */
+static apt_bool_t demo_application_run(demo_application_t *demo_application, const char *profile)
+{
+       mrcp_channel_t *channel;
+       /* create session */
+       mrcp_session_t *session = mrcp_application_session_create(demo_application->application,profile,NULL);
+       if(!session) {
+               return FALSE;
+       }
+       
+       /* create channel and associate all the required data */
+       channel = demo_application_channel_create(session);
+       if(!channel) {
+               mrcp_application_session_destroy(session);
+               return FALSE;
+       }
+
+       /* add channel to session (send asynchronous request) */
+       if(mrcp_application_channel_add(session,channel) != TRUE) {
+               /* session and channel are still not referenced 
+               and both are allocated from session pool and will
+               be freed with session destroy call */
+               mrcp_application_session_destroy(session);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+/** Handle the messages sent from the MRCP client stack */
+static apt_bool_t demo_application_handler(demo_application_t *application, const mrcp_app_message_t *app_message)
+{
+       /* app_message should be dispatched now,
+       *  the default dispatcher is used in demo. */
+       return mrcp_application_message_dispatch(&demo_application_dispatcher,app_message);
+}
+
+/** Handle the responses sent to session update requests */
+static apt_bool_t demo_application_on_session_update(mrcp_application_t *application, mrcp_session_t *session, mrcp_sig_status_code_e status)
+{
+       return TRUE;
+}
+
+/** Handle the responses sent to session terminate requests */
+static apt_bool_t demo_application_on_session_terminate(mrcp_application_t *application, mrcp_session_t *session, mrcp_sig_status_code_e status)
+{
+       /* received response to session termination request,
+       now it's safe to destroy no more referenced session */
+       mrcp_application_session_destroy(session);
+       return TRUE;
+}
+
+/** Handle the responses sent to channel add requests */
+static apt_bool_t demo_application_on_channel_add(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_sig_status_code_e status)
+{
+       if(status == MRCP_SIG_STATUS_CODE_SUCCESS) {
+               mpf_rtp_termination_descriptor_t *rtp_descriptor;
+               mrcp_message_t *mrcp_message;
+               const apt_dir_layout_t *dir_layout = mrcp_application_dir_layout_get(application);
+               /* create and send SPEAK request */
+               mrcp_message = demo_speak_message_create(session,channel,dir_layout);
+               if(mrcp_message) {
+                       mrcp_application_message_send(session,channel,mrcp_message);
+               }
+               rtp_descriptor = mrcp_application_rtp_descriptor_get(channel);
+               if(rtp_descriptor) {
+                       mpf_rtp_media_descriptor_t *local_media = rtp_descriptor->audio.local;
+                       mpf_rtp_media_descriptor_t *remote_media = rtp_descriptor->audio.remote;
+                       if(local_media && remote_media) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Media Attributes: L[%s/%d] R[%s/%d]",
+                                       local_media->base.ip.buf,
+                                       local_media->base.port,
+                                       remote_media->base.ip.buf,
+                                       remote_media->base.port);
+                       }
+               }
+       }
+       else {
+               /* error case, just terminate the demo */
+               mrcp_application_session_terminate(session);
+       }
+       return TRUE;
+}
+
+/** Handle the responses sent to channel remove requests */
+static apt_bool_t demo_application_on_channel_remove(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_sig_status_code_e status)
+{
+       /* terminate the demo */
+       mrcp_application_session_terminate(session);
+       return TRUE;
+}
+
+/** Handle the MRCP responses/events */
+static apt_bool_t demo_application_on_message_receive(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_message_t *message)
+{
+       if(message->start_line.message_type == MRCP_MESSAGE_TYPE_RESPONSE) {
+               /* received MRCP response */
+               if(message->start_line.method_id == SYNTHESIZER_SPEAK) {
+                       /* received the response to SPEAK request, 
+                       waiting for SPEAK-COMPLETE event */
+               }
+               else {
+                       /* received unexpected response */
+               }
+       }
+       else if(message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
+               /* received MRCP event */
+               if(message->start_line.method_id == SYNTHESIZER_SPEAK_COMPLETE) {
+                       /* received SPEAK-COMPLETE event, remove channel */
+                       mrcp_application_channel_remove(session,channel);
+               }
+       }
+       return TRUE;
+}
diff --git a/libs/unimrcp/platforms/unimrcp-client/src/demo_discover_application.c b/libs/unimrcp/platforms/unimrcp-client/src/demo_discover_application.c
new file mode 100644 (file)
index 0000000..e0b2e35
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* 
+ * Demo resource discovery.
+ * C -> S: SIP OPTIONS or RTPS DESCRIBE
+ * S -> C: SIP OK or RTPS OK
+ */
+
+#include "demo_application.h"
+#include "mrcp_session_descriptor.h"
+#include "mrcp_control_descriptor.h"
+#include "apt_log.h"
+
+
+/** Declaration of synthesizer application methods */
+static apt_bool_t discover_application_run(demo_application_t *demo_application, const char *profile);
+static apt_bool_t discover_application_handler(demo_application_t *application, const mrcp_app_message_t *app_message);
+
+/** Declaration of application message handlers */
+static apt_bool_t discover_application_on_session_terminate(mrcp_application_t *application, mrcp_session_t *session, mrcp_sig_status_code_e status);
+static apt_bool_t discover_application_on_resource_discover(mrcp_application_t *application, mrcp_session_t *session, mrcp_session_descriptor_t *descriptor, mrcp_sig_status_code_e status);
+
+static const mrcp_app_message_dispatcher_t discover_application_dispatcher = {
+       NULL,
+       discover_application_on_session_terminate,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       discover_application_on_resource_discover
+};
+
+/** Create demo resource discover application */
+demo_application_t* demo_discover_application_create(apr_pool_t *pool)
+{
+       demo_application_t *discover_application = apr_palloc(pool,sizeof(demo_application_t));
+       discover_application->application = NULL;
+       discover_application->framework = NULL;
+       discover_application->handler = discover_application_handler;
+       discover_application->run = discover_application_run;
+       return discover_application;
+}
+
+/** Run demo resource discover scenario */
+static apt_bool_t discover_application_run(demo_application_t *demo_application, const char *profile)
+{
+       /* create session */
+       mrcp_session_t *session = mrcp_application_session_create(demo_application->application,profile,NULL);
+       if(!session) {
+               return FALSE;
+       }
+       
+       /* send resource discover request */
+       if(mrcp_application_resource_discover(session) != TRUE) {
+               mrcp_application_session_destroy(session);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+/** Handle the messages sent from the MRCP client stack */
+static apt_bool_t discover_application_handler(demo_application_t *application, const mrcp_app_message_t *app_message)
+{
+       /* app_message should be dispatched now,
+       *  the default dispatcher is used in demo. */
+       return mrcp_application_message_dispatch(&discover_application_dispatcher,app_message);
+}
+
+/** Handle the responses sent to session terminate requests */
+static apt_bool_t discover_application_on_session_terminate(mrcp_application_t *application, mrcp_session_t *session, mrcp_sig_status_code_e status)
+{
+       /* received response to session termination request,
+       now it's safe to destroy no more referenced session */
+       mrcp_application_session_destroy(session);
+       return TRUE;
+}
+
+/** Handle the responses sent to resource discover requests */
+static apt_bool_t discover_application_on_resource_discover(mrcp_application_t *application, mrcp_session_t *session, mrcp_session_descriptor_t *descriptor, mrcp_sig_status_code_e status)
+{
+       if(descriptor && status == MRCP_SIG_STATUS_CODE_SUCCESS) {
+               int i;
+               int count = descriptor->control_media_arr->nelts;
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"On Resource Discover [%d]", count);
+
+               for(i = 0; i < count; i++) {
+                       mrcp_control_descriptor_t *control_media = mrcp_session_control_media_get(descriptor,i);
+                       if(control_media) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"[%d] - %s", i,control_media->resource_name.buf);
+                       }
+               }
+       }
+       else {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Failed to Discover Resources");
+       }
+       
+       mrcp_application_session_terminate(session);
+       return TRUE;
+}
diff --git a/libs/unimrcp/platforms/unimrcp-client/src/demo_framework.c b/libs/unimrcp/platforms/unimrcp-client/src/demo_framework.c
new file mode 100644 (file)
index 0000000..9d65750
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_hash.h>
+#include "demo_framework.h"
+#include "demo_application.h"
+#include "unimrcp_client.h"
+#include "apt_consumer_task.h"
+#include "apt_log.h"
+
+#define FRAMEWORK_TASK_NAME "Framework Task"
+
+#define MAX_APP_NAME_LENGTH     16
+#define MAX_PROFILE_NAME_LENGTH 16
+
+/** Demo framework */
+struct demo_framework_t {
+       /** MRCP client stack instance */
+       mrcp_client_t       *client;
+       /** Message processing task */
+       apt_consumer_task_t *task;
+       /** Table of demo applications */
+       apr_hash_t          *application_table;
+       /** Memory to allocate memory from */
+       apr_pool_t          *pool;
+};
+
+typedef struct framework_task_data_t framework_task_data_t;
+struct framework_task_data_t {
+       char                      app_name[MAX_APP_NAME_LENGTH];
+       char                      profile_name[MAX_PROFILE_NAME_LENGTH];
+       demo_application_t       *demo_application;
+       const mrcp_app_message_t *app_message;
+};
+
+typedef enum {
+       DEMO_APPLICATION_MSG_ID,
+       DEMO_CONSOLE_MSG_ID
+} framework_msg_type_e;
+
+static apt_bool_t demo_framework_message_handler(const mrcp_app_message_t *app_message);
+static apt_bool_t demo_framework_consumer_task_create(demo_framework_t *framework);
+static apt_bool_t demo_framework_app_register(demo_framework_t *framework, demo_application_t *demo_application, const char *name);
+
+/** Create demo framework */
+demo_framework_t* demo_framework_create(apt_dir_layout_t *dir_layout)
+{
+       demo_framework_t *framework = NULL;
+       mrcp_client_t *client = unimrcp_client_create(dir_layout);
+       if(client) {
+               demo_application_t *demo_application;
+               apr_pool_t *pool = mrcp_client_memory_pool_get(client);
+               /* create demo framework */
+               framework = apr_palloc(pool,sizeof(demo_framework_t));
+               framework->pool = pool;
+               framework->client = client;
+               framework->application_table = apr_hash_make(pool);
+
+               /* create demo synthesizer application */
+               demo_application = demo_synth_application_create(framework->pool);
+               if(demo_application) {
+                       demo_framework_app_register(framework,demo_application,"synth");
+               }
+
+               /* create demo recognizer application */
+               demo_application = demo_recog_application_create(framework->pool);
+               if(demo_application) {
+                       demo_framework_app_register(framework,demo_application,"recog");
+               }
+
+               /* create demo bypass media application */
+               demo_application = demo_bypass_application_create(framework->pool);
+               if(demo_application) {
+                       demo_framework_app_register(framework,demo_application,"bypass");
+               }
+
+               /* create demo resource discover application */
+               demo_application = demo_discover_application_create(framework->pool);
+               if(demo_application) {
+                       demo_framework_app_register(framework,demo_application,"discover");
+               }
+
+               demo_framework_consumer_task_create(framework);
+
+               if(framework->task) {
+                       apt_task_t *task = apt_consumer_task_base_get(framework->task);
+                       apt_task_start(task);
+               }
+               
+               /* start client stack */
+               mrcp_client_start(client);
+       }
+
+       return framework;
+}
+
+/** Run demo application */
+apt_bool_t demo_framework_app_run(demo_framework_t *framework, const char *app_name, const char *profile_name)
+{
+       apt_task_t *task = apt_consumer_task_base_get(framework->task);
+       apt_task_msg_t *task_msg = apt_task_msg_get(task);
+       if(task_msg) {
+               framework_task_data_t *framework_task_data = (framework_task_data_t*)task_msg->data;
+               task_msg->type = TASK_MSG_USER;
+               task_msg->sub_type = DEMO_CONSOLE_MSG_ID;
+               framework_task_data = (framework_task_data_t*) task_msg->data;
+               strcpy(framework_task_data->app_name,app_name);
+               strcpy(framework_task_data->profile_name,profile_name);
+               framework_task_data->app_message = NULL;
+               framework_task_data->demo_application = NULL;
+               apt_task_msg_signal(task,task_msg);
+       }
+       return TRUE;
+}
+
+/** Destroy demo framework */
+apt_bool_t demo_framework_destroy(demo_framework_t *framework)
+{
+       if(!framework) {
+               return FALSE;
+       }
+
+       if(framework->task) {
+               apt_task_t *task = apt_consumer_task_base_get(framework->task);
+               apt_task_terminate(task,TRUE);
+               apt_task_destroy(task);
+               framework->task = NULL;
+       }
+
+       mrcp_client_shutdown(framework->client);
+       return mrcp_client_destroy(framework->client);
+}
+
+static apt_bool_t demo_framework_app_register(demo_framework_t *framework, demo_application_t *demo_application, const char *name)
+{
+       apr_hash_set(framework->application_table,name,APR_HASH_KEY_STRING,demo_application);
+       demo_application->framework = framework;
+       demo_application->application = mrcp_application_create(
+                                                                               demo_framework_message_handler,
+                                                                               demo_application,
+                                                                               framework->pool);
+       return mrcp_client_application_register(framework->client,demo_application->application,name);
+}
+
+static void demo_framework_on_start_complete(apt_task_t *task)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Run Demo Framework");
+}
+
+static apt_bool_t demo_framework_console_msg_process(demo_framework_t *framework, const char *app_name, const char *profile_name)
+{
+       demo_application_t *demo_application = apr_hash_get(framework->application_table,app_name,APR_HASH_KEY_STRING);
+       if(!demo_application) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Such Demo Application [%s]",app_name);
+               return FALSE;
+       }
+       
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Run Demo Application Scenario [%s]",app_name);
+       return demo_application->run(demo_application,profile_name);
+}
+
+static apt_bool_t demo_framework_msg_process(apt_task_t *task, apt_task_msg_t *msg)
+{
+       if(msg->type == TASK_MSG_USER) {
+               framework_task_data_t *data = (framework_task_data_t*)msg->data;
+               switch(msg->sub_type) {
+                       case DEMO_APPLICATION_MSG_ID:
+                       {
+                               data->demo_application->handler(data->demo_application,data->app_message);
+                               break;
+                       }
+                       case DEMO_CONSOLE_MSG_ID:
+                       {
+                               apt_consumer_task_t *consumer_task = apt_task_object_get(task);
+                               demo_framework_t *framework = apt_consumer_task_object_get(consumer_task);
+                               demo_framework_console_msg_process(framework,data->app_name,data->profile_name);
+                               break;
+                       }
+               }
+       }
+       return TRUE;
+}
+
+static apt_bool_t demo_framework_consumer_task_create(demo_framework_t *framework)
+{
+       apt_task_t *task;
+       apt_task_vtable_t *vtable;
+       apt_task_msg_pool_t *msg_pool;
+
+       msg_pool = apt_task_msg_pool_create_dynamic(sizeof(framework_task_data_t),framework->pool);
+       framework->task = apt_consumer_task_create(framework,msg_pool,framework->pool);
+       if(!framework->task) {
+               return FALSE;
+       }
+       task = apt_consumer_task_base_get(framework->task);
+       apt_task_name_set(task,FRAMEWORK_TASK_NAME);
+       vtable = apt_consumer_task_vtable_get(framework->task);
+       if(vtable) {
+               vtable->process_msg = demo_framework_msg_process;
+               vtable->on_start_complete = demo_framework_on_start_complete;
+       }
+
+       return TRUE;
+}
+
+/** Callback is called from MRCP client stack (task) context.
+ *  Signal app_message to the main consumer task of the demo framework
+ *  for further processing (see demo_framework_msg_process).
+ */
+static apt_bool_t demo_framework_message_handler(const mrcp_app_message_t *app_message)
+{
+       demo_application_t *demo_application;
+       if(!app_message->application) {
+               return FALSE;
+       }
+       demo_application = mrcp_application_object_get(app_message->application);
+       if(demo_application && demo_application->framework) {
+               demo_framework_t *framework = demo_application->framework;
+               apt_task_t *task = apt_consumer_task_base_get(framework->task);
+               apt_task_msg_t *task_msg = apt_task_msg_get(task);
+               if(task_msg) {
+                       framework_task_data_t *framework_task_data = (framework_task_data_t*)task_msg->data;
+                       task_msg->type = TASK_MSG_USER;
+                       task_msg->sub_type = DEMO_APPLICATION_MSG_ID;
+                       framework_task_data = (framework_task_data_t*) task_msg->data;
+                       framework_task_data->app_message = app_message;
+                       framework_task_data->demo_application = demo_application;
+                       apt_task_msg_signal(task,task_msg);
+               }
+       }
+       return TRUE;
+}
diff --git a/libs/unimrcp/platforms/unimrcp-client/src/demo_recog_application.c b/libs/unimrcp/platforms/unimrcp-client/src/demo_recog_application.c
new file mode 100644 (file)
index 0000000..6c45bc1
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Demo recognizer scenario.
+ * C -> S: SIP INVITE or RTPS SETUP   (add recognizer channel)
+ * S -> C: SIP OK or RTPS OK
+ * C -> S: MRCP RECOGNIZE
+ * S -> C: MRCP IN-PROGRESS
+ * C -> S: RTP Start Transmission
+ * S -> C: MRCP START-OF-INPUT
+ * S -> C: MRCP RECOGNITION-COMPLETE
+ * C -> S: RTP Stop Transmission
+ * C -> S: SIP INVITE or RTPS SETUP   (optionally remove recognizer channel)
+ * S -> C: SIP OK or RTPS OK
+ * C -> S: SIP BYE or RTPS TEARDOWN
+ * S -> C: SIP OK or RTPS OK
+ */
+
+#include "demo_application.h"
+#include "demo_util.h"
+#include "mrcp_session.h"
+#include "mrcp_message.h"
+#include "mrcp_generic_header.h"
+#include "mrcp_recog_header.h"
+#include "mrcp_recog_resource.h"
+#include "apt_log.h"
+
+#define DEMO_SPEECH_SOURCE_FILE "one.pcm"
+
+typedef struct recog_app_channel_t recog_app_channel_t;
+
+/** Declaration of recognizer application channel */
+struct recog_app_channel_t {
+       /** MRCP control channel */
+       mrcp_channel_t *channel;
+
+       /** Streaming is in-progress */
+       apt_bool_t      streaming;
+       /** File to read audio stream from */
+       FILE           *audio_in;
+       /** Estimated time to complete (used if no audio_in available) */
+       apr_size_t      time_to_complete;
+};
+
+/** Declaration of recognizer application methods */
+static apt_bool_t recog_application_run(demo_application_t *demo_application, const char *profile);
+static apt_bool_t recog_application_handler(demo_application_t *application, const mrcp_app_message_t *app_message);
+
+/** Declaration of application message handlers */
+static apt_bool_t recog_application_on_session_update(mrcp_application_t *application, mrcp_session_t *session, mrcp_sig_status_code_e status);
+static apt_bool_t recog_application_on_session_terminate(mrcp_application_t *application, mrcp_session_t *session, mrcp_sig_status_code_e status);
+static apt_bool_t recog_application_on_channel_add(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_sig_status_code_e status);
+static apt_bool_t recog_application_on_channel_remove(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_sig_status_code_e status);
+static apt_bool_t recog_application_on_message_receive(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_message_t *message);
+
+static const mrcp_app_message_dispatcher_t recog_application_dispatcher = {
+       recog_application_on_session_update,
+       recog_application_on_session_terminate,
+       recog_application_on_channel_add,
+       recog_application_on_channel_remove,
+       recog_application_on_message_receive
+};
+
+/** Declaration of recognizer audio stream methods */
+static apt_bool_t recog_app_stream_destroy(mpf_audio_stream_t *stream);
+static apt_bool_t recog_app_stream_open(mpf_audio_stream_t *stream);
+static apt_bool_t recog_app_stream_close(mpf_audio_stream_t *stream);
+static apt_bool_t recog_app_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *frame);
+
+static const mpf_audio_stream_vtable_t audio_stream_vtable = {
+       recog_app_stream_destroy,
+       recog_app_stream_open,
+       recog_app_stream_close,
+       recog_app_stream_read,
+       NULL,
+       NULL,
+       NULL
+};
+
+
+/** Create demo recognizer application */
+demo_application_t* demo_recog_application_create(apr_pool_t *pool)
+{
+       demo_application_t *recog_application = apr_palloc(pool,sizeof(demo_application_t));
+       recog_application->application = NULL;
+       recog_application->framework = NULL;
+       recog_application->handler = recog_application_handler;
+       recog_application->run = recog_application_run;
+       return recog_application;
+}
+
+/** Create demo recognizer channel */
+static mrcp_channel_t* recog_application_channel_create(mrcp_session_t *session)
+{
+       mrcp_channel_t *channel;
+       mpf_termination_t *termination;
+       mpf_codec_descriptor_t *codec_descriptor = NULL;
+
+       /* create channel */
+       recog_app_channel_t *recog_channel = apr_palloc(session->pool,sizeof(recog_app_channel_t));
+       recog_channel->streaming = FALSE;
+       recog_channel->audio_in = NULL;
+       recog_channel->time_to_complete = 0;
+
+#if 0 /* in case your audio source isn't in linear PCM, create appropriate codec descriptor below */
+       codec_descriptor = apr_palloc(session->pool,sizeof(mpf_codec_descriptor_t));
+       mpf_codec_descriptor_init(codec_descriptor);
+       codec_descriptor->channel_count = 1;
+       codec_descriptor->payload_type = 0;
+       apt_string_set(&codec_descriptor->name,"PCMU");
+       codec_descriptor->sampling_rate = 8000;
+#endif
+
+       termination = mrcp_application_source_termination_create(
+                       session,                   /* session, termination belongs to */
+                       &audio_stream_vtable,      /* virtual methods table of audio stream */
+                       codec_descriptor,          /* codec descriptor of audio stream (NULL by default) */
+                       recog_channel);            /* object to associate */
+       
+       channel = mrcp_application_channel_create(
+                       session,                   /* session, channel belongs to */
+                       MRCP_RECOGNIZER_RESOURCE,  /* MRCP resource identifier */
+                       termination,               /* media termination, used to terminate audio stream */
+                       NULL,                      /* RTP descriptor, used to create RTP termination (NULL by default) */
+                       recog_channel);            /* object to associate */
+       return channel;
+}
+
+/** Run demo recognizer scenario */
+static apt_bool_t recog_application_run(demo_application_t *demo_application, const char *profile)
+{
+       mrcp_channel_t *channel;
+       /* create session */
+       mrcp_session_t *session = mrcp_application_session_create(demo_application->application,profile,NULL);
+       if(!session) {
+               return FALSE;
+       }
+       
+       /* create channel and associate all the required data */
+       channel = recog_application_channel_create(session);
+       if(!channel) {
+               mrcp_application_session_destroy(session);
+               return FALSE;
+       }
+
+       /* add channel to session (send asynchronous request) */
+       if(mrcp_application_channel_add(session,channel) != TRUE) {
+               /* session and channel are still not referenced 
+               and both are allocated from session pool and will
+               be freed with session destroy call */
+               mrcp_application_session_destroy(session);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+/** Handle the messages sent from the MRCP client stack */
+static apt_bool_t recog_application_handler(demo_application_t *application, const mrcp_app_message_t *app_message)
+{
+       /* app_message should be dispatched now,
+       *  the default dispatcher is used in demo. */
+       return mrcp_application_message_dispatch(&recog_application_dispatcher,app_message);
+}
+
+/** Handle the responses sent to session update requests */
+static apt_bool_t recog_application_on_session_update(mrcp_application_t *application, mrcp_session_t *session, mrcp_sig_status_code_e status)
+{
+       /* not used in demo */
+       return TRUE;
+}
+
+/** Handle the responses sent to session terminate requests */
+static apt_bool_t recog_application_on_session_terminate(mrcp_application_t *application, mrcp_session_t *session, mrcp_sig_status_code_e status)
+{
+       /* received response to session termination request,
+       now it's safe to destroy no more referenced session */
+       mrcp_application_session_destroy(session);
+       return TRUE;
+}
+
+/** Handle the responses sent to channel add requests */
+static apt_bool_t recog_application_on_channel_add(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_sig_status_code_e status)
+{
+       if(status == MRCP_SIG_STATUS_CODE_SUCCESS) {
+               mrcp_message_t *mrcp_message;
+               const apt_dir_layout_t *dir_layout = mrcp_application_dir_layout_get(application);
+               /* create and send DEFINE-GRAMMAR request */
+               mrcp_message = demo_define_grammar_message_create(session,channel,dir_layout);
+               if(mrcp_message) {
+                       mrcp_application_message_send(session,channel,mrcp_message);
+               }
+       }
+       else {
+               /* error case, just terminate the demo */
+               mrcp_application_session_terminate(session);
+       }
+       return TRUE;
+}
+
+static apt_bool_t recog_application_on_channel_remove(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_sig_status_code_e status)
+{
+       recog_app_channel_t *recog_channel = mrcp_application_channel_object_get(channel);
+
+       /* terminate the demo */
+       mrcp_application_session_terminate(session);
+
+       if(recog_channel) {
+               FILE *audio_in = recog_channel->audio_in;
+               if(audio_in) {
+                       recog_channel->audio_in = NULL;
+                       fclose(audio_in);
+               }
+       }
+       return TRUE;
+}
+
+/** Handle the DEFINE-GRAMMAR responses */
+static apt_bool_t recog_application_on_define_grammar(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel)
+{
+       recog_app_channel_t *recog_channel = mrcp_application_channel_object_get(channel);
+       mrcp_message_t *mrcp_message;
+       const apt_dir_layout_t *dir_layout = mrcp_application_dir_layout_get(application);
+       /* create and send RECOGNIZE request */
+       mrcp_message = demo_recognize_message_create(session,channel,dir_layout);
+       if(mrcp_message) {
+               mrcp_application_message_send(session,channel,mrcp_message);
+       }
+       if(recog_channel) {
+               char *file_path = apt_datadir_filepath_get(dir_layout,DEMO_SPEECH_SOURCE_FILE,session->pool);
+               if(file_path) {
+                       recog_channel->audio_in = fopen(file_path,"rb");
+                       if(recog_channel->audio_in) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set [%s] as Speech Source",file_path);
+                       }
+                       else {
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Cannot Find [%s]",file_path);
+                               /* set some estimated time to complete */
+                               recog_channel->time_to_complete = 5000; // 5 sec
+                       }
+               }
+       }
+       return TRUE;
+}
+
+static apt_bool_t recog_application_on_message_receive(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_message_t *message)
+{
+       recog_app_channel_t *recog_channel = mrcp_application_channel_object_get(channel);
+       if(message->start_line.message_type == MRCP_MESSAGE_TYPE_RESPONSE) {
+               /* received MRCP response */
+               if(message->start_line.method_id == RECOGNIZER_DEFINE_GRAMMAR) {
+                       /* received the response to DEFINE-GRAMMAR request */
+                       if(message->start_line.request_state == MRCP_REQUEST_STATE_COMPLETE) {
+                               recog_application_on_define_grammar(application,session,channel);
+                       }
+                       else {
+                               /* received unexpected response, remove channel */
+                               mrcp_application_channel_remove(session,channel);
+                       }
+               }
+               else if(message->start_line.method_id == RECOGNIZER_RECOGNIZE) {
+                       /* received the response to RECOGNIZE request */
+                       if(message->start_line.request_state == MRCP_REQUEST_STATE_INPROGRESS) {
+                               /* start to stream the speech to recognize */
+                               if(recog_channel) {
+                                       recog_channel->streaming = TRUE;
+                               }
+                       }
+                       else {
+                               /* received unexpected response, remove channel */
+                               mrcp_application_channel_remove(session,channel);
+                       }
+               }
+               else {
+                       /* received unexpected response */
+               }
+       }
+       else if(message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
+               if(message->start_line.method_id == RECOGNIZER_RECOGNITION_COMPLETE) {
+                       if(recog_channel) {
+                               recog_channel->streaming = FALSE;
+                       }
+                       mrcp_application_channel_remove(session,channel);
+               }
+               else if(message->start_line.method_id == RECOGNIZER_START_OF_INPUT) {
+                       /* received start-of-input, do whatever you need here */
+               }
+       }
+       return TRUE;
+}
+
+/** Callback is called from MPF engine context to destroy any additional data associated with audio stream */
+static apt_bool_t recog_app_stream_destroy(mpf_audio_stream_t *stream)
+{
+       return TRUE;
+}
+
+/** Callback is called from MPF engine context to perform application stream specific action before open */
+static apt_bool_t recog_app_stream_open(mpf_audio_stream_t *stream)
+{
+       return TRUE;
+}
+
+/** Callback is called from MPF engine context to perform application stream specific action after close */
+static apt_bool_t recog_app_stream_close(mpf_audio_stream_t *stream)
+{
+       return TRUE;
+}
+
+/** Callback is called from MPF engine context to read new frame */
+static apt_bool_t recog_app_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *frame)
+{
+       recog_app_channel_t *recog_channel = stream->obj;
+       if(recog_channel && recog_channel->streaming == TRUE) {
+               if(recog_channel->audio_in) {
+                       if(fread(frame->codec_frame.buffer,1,frame->codec_frame.size,recog_channel->audio_in) == frame->codec_frame.size) {
+                               /* normal read */
+                               frame->type |= MEDIA_FRAME_TYPE_AUDIO;
+                       }
+                       else {
+                               /* file is over */
+                               recog_channel->streaming = FALSE;
+                       }
+               }
+               else {
+                       /* fill with silence in case no file available */
+                       if(recog_channel->time_to_complete >= CODEC_FRAME_TIME_BASE) {
+                               frame->type |= MEDIA_FRAME_TYPE_AUDIO;
+                               memset(frame->codec_frame.buffer,0,frame->codec_frame.size);
+                               recog_channel->time_to_complete -= CODEC_FRAME_TIME_BASE;
+                       }
+                       else {
+                               recog_channel->streaming = FALSE;
+                       }
+               }
+       }
+       return TRUE;
+}
diff --git a/libs/unimrcp/platforms/unimrcp-client/src/demo_synth_application.c b/libs/unimrcp/platforms/unimrcp-client/src/demo_synth_application.c
new file mode 100644 (file)
index 0000000..9aba1ad
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* 
+ * Demo synthesizer scenario.
+ * C -> S: SIP INVITE or RTPS SETUP   (add synthesizer channel)
+ * S -> C: SIP OK or RTPS OK
+ * C -> S: MRCP SPEAK
+ * S -> C: MRCP IN-PROGRESS
+ * S -> C: RTP Start Transmission
+ * S -> C: MRCP SPEAK-COMPLETE
+ * S -> C: RTP Stop Transmission
+ * C -> S: SIP INVITE or RTPS SETUP   (optionally remove synthesizer channel)
+ * S -> C: SIP OK or RTPS OK
+ * C -> S: SIP BYE or RTPS TEARDOWN
+ * S -> C: SIP OK or RTPS OK
+ */
+
+#include "demo_application.h"
+#include "demo_util.h"
+#include "mrcp_session.h"
+#include "mrcp_message.h"
+#include "mrcp_generic_header.h"
+#include "mrcp_synth_header.h"
+#include "mrcp_synth_resource.h"
+
+typedef struct synth_app_channel_t synth_app_channel_t;
+
+/** Declaration of synthesizer application channel */
+struct synth_app_channel_t {
+       /** MRCP control channel */
+       mrcp_channel_t *channel;
+       /** File to write audio stream to */
+       FILE           *audio_out;
+};
+
+/** Declaration of synthesizer application methods */
+static apt_bool_t synth_application_run(demo_application_t *demo_application, const char *profile);
+static apt_bool_t synth_application_handler(demo_application_t *application, const mrcp_app_message_t *app_message);
+
+/** Declaration of application message handlers */
+static apt_bool_t synth_application_on_session_update(mrcp_application_t *application, mrcp_session_t *session, mrcp_sig_status_code_e status);
+static apt_bool_t synth_application_on_session_terminate(mrcp_application_t *application, mrcp_session_t *session, mrcp_sig_status_code_e status);
+static apt_bool_t synth_application_on_channel_add(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_sig_status_code_e status);
+static apt_bool_t synth_application_on_channel_remove(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_sig_status_code_e status);
+static apt_bool_t synth_application_on_message_receive(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_message_t *message);
+
+static const mrcp_app_message_dispatcher_t synth_application_dispatcher = {
+       synth_application_on_session_update,
+       synth_application_on_session_terminate,
+       synth_application_on_channel_add,
+       synth_application_on_channel_remove,
+       synth_application_on_message_receive
+};
+
+/** Declaration of synthesizer audio stream methods */
+static apt_bool_t synth_app_stream_destroy(mpf_audio_stream_t *stream);
+static apt_bool_t synth_app_stream_open(mpf_audio_stream_t *stream);
+static apt_bool_t synth_app_stream_close(mpf_audio_stream_t *stream);
+static apt_bool_t synth_app_stream_write(mpf_audio_stream_t *stream, const mpf_frame_t *frame);
+
+static const mpf_audio_stream_vtable_t audio_stream_vtable = {
+       synth_app_stream_destroy,
+       NULL,
+       NULL,
+       NULL,
+       synth_app_stream_open,
+       synth_app_stream_close,
+       synth_app_stream_write
+};
+
+
+/** Create demo synthesizer application */
+demo_application_t* demo_synth_application_create(apr_pool_t *pool)
+{
+       demo_application_t *synth_application = apr_palloc(pool,sizeof(demo_application_t));
+       synth_application->application = NULL;
+       synth_application->framework = NULL;
+       synth_application->handler = synth_application_handler;
+       synth_application->run = synth_application_run;
+       return synth_application;
+}
+
+/** Create demo synthesizer channel */
+static mrcp_channel_t* synth_application_channel_create(mrcp_session_t *session)
+{
+       mrcp_channel_t *channel;
+       mpf_termination_t *termination;
+       mpf_codec_descriptor_t *codec_descriptor = NULL;
+
+       /* create channel */
+       synth_app_channel_t *synth_channel = apr_palloc(session->pool,sizeof(synth_app_channel_t));
+       synth_channel->audio_out = NULL;
+
+#if 0
+       codec_descriptor = apr_palloc(session->pool,sizeof(mpf_codec_descriptor_t));
+       mpf_codec_descriptor_init(codec_descriptor);
+       codec_descriptor->channel_count = 1;
+       codec_descriptor->payload_type = 0;
+       apt_string_set(&codec_descriptor->name,"PCMU");
+       codec_descriptor->sampling_rate = 8000;
+#endif
+
+       termination = mrcp_application_sink_termination_create(
+                       session,                   /* session, termination belongs to */
+                       &audio_stream_vtable,      /* virtual methods table of audio stream */
+                       codec_descriptor,          /* codec descriptor of audio stream (NULL by default) */
+                       synth_channel);            /* object to associate */
+       
+       channel = mrcp_application_channel_create(
+                       session,                   /* session, channel belongs to */
+                       MRCP_SYNTHESIZER_RESOURCE, /* MRCP resource identifier */
+                       termination,               /* media termination, used to terminate audio stream */
+                       NULL,                      /* RTP descriptor, used to create RTP termination (NULL by default) */
+                       synth_channel);            /* object to associate */
+       return channel;
+}
+
+
+/** Run demo synthesizer scenario */
+static apt_bool_t synth_application_run(demo_application_t *demo_application, const char *profile)
+{
+       mrcp_channel_t *channel;
+       /* create session */
+       mrcp_session_t *session = mrcp_application_session_create(demo_application->application,profile,NULL);
+       if(!session) {
+               return FALSE;
+       }
+       
+       /* create channel and associate all the required data */
+       channel = synth_application_channel_create(session);
+       if(!channel) {
+               mrcp_application_session_destroy(session);
+               return FALSE;
+       }
+
+       /* add channel to session (send asynchronous request) */
+       if(mrcp_application_channel_add(session,channel) != TRUE) {
+               /* session and channel are still not referenced 
+               and both are allocated from session pool and will
+               be freed with session destroy call */
+               mrcp_application_session_destroy(session);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+/** Handle the messages sent from the MRCP client stack */
+static apt_bool_t synth_application_handler(demo_application_t *application, const mrcp_app_message_t *app_message)
+{
+       /* app_message should be dispatched now,
+       *  the default dispatcher is used in demo. */
+       return mrcp_application_message_dispatch(&synth_application_dispatcher,app_message);
+}
+
+/** Handle the responses sent to session update requests */
+static apt_bool_t synth_application_on_session_update(mrcp_application_t *application, mrcp_session_t *session, mrcp_sig_status_code_e status)
+{
+       /* not used in demo */
+       return TRUE;
+}
+
+/** Handle the responses sent to session terminate requests */
+static apt_bool_t synth_application_on_session_terminate(mrcp_application_t *application, mrcp_session_t *session, mrcp_sig_status_code_e status)
+{
+       /* received response to session termination request,
+       now it's safe to destroy no more referenced session */
+       mrcp_application_session_destroy(session);
+       return TRUE;
+}
+
+/** Handle the responses sent to channel add requests */
+static apt_bool_t synth_application_on_channel_add(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_sig_status_code_e status)
+{
+       synth_app_channel_t *synth_channel = mrcp_application_channel_object_get(channel);
+       if(status == MRCP_SIG_STATUS_CODE_SUCCESS) {
+               mrcp_message_t *mrcp_message;
+               const apt_dir_layout_t *dir_layout = mrcp_application_dir_layout_get(application);
+               /* create and send SPEAK request */
+               mrcp_message = demo_speak_message_create(session,channel,dir_layout);
+               if(mrcp_message) {
+                       mrcp_application_message_send(session,channel,mrcp_message);
+               }
+
+               if(synth_channel && session) {
+                       char *file_name = apr_pstrcat(session->pool,"synth-",session->id.buf,".pcm",NULL);
+                       char *file_path = apt_datadir_filepath_get(dir_layout,file_name,session->pool);
+                       if(file_path) {
+                               synth_channel->audio_out = fopen(file_path,"wb");
+                       }
+               }
+       }
+       else {
+               /* error case, just terminate the demo */
+               mrcp_application_session_terminate(session);
+       }
+       return TRUE;
+}
+
+/** Handle the responses sent to channel remove requests */
+static apt_bool_t synth_application_on_channel_remove(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_sig_status_code_e status)
+{
+       synth_app_channel_t *synth_channel = mrcp_application_channel_object_get(channel);
+
+       /* terminate the demo */
+       mrcp_application_session_terminate(session);
+
+       if(synth_channel) {
+               FILE *audio_out = synth_channel->audio_out;
+               if(audio_out) {
+                       synth_channel->audio_out = NULL;
+                       fclose(audio_out);
+               }
+       }
+       return TRUE;
+}
+
+/** Handle the MRCP responses/events */
+static apt_bool_t synth_application_on_message_receive(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_message_t *message)
+{
+       if(message->start_line.message_type == MRCP_MESSAGE_TYPE_RESPONSE) {
+               /* received MRCP response */
+               if(message->start_line.method_id == SYNTHESIZER_SPEAK) {
+                       /* received the response to SPEAK request */
+                       if(message->start_line.request_state == MRCP_REQUEST_STATE_INPROGRESS) {
+                               /* waiting for SPEAK-COMPLETE event */
+                       }
+                       else {
+                               /* received unexpected response, remove channel */
+                               mrcp_application_channel_remove(session,channel);
+                       }
+               }
+               else {
+                       /* received unexpected response */
+               }
+       }
+       else if(message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
+               /* received MRCP event */
+               if(message->start_line.method_id == SYNTHESIZER_SPEAK_COMPLETE) {
+                       /* received SPEAK-COMPLETE event, remove channel */
+                       mrcp_application_channel_remove(session,channel);
+               }
+       }
+       return TRUE;
+}
+
+/** Callback is called from MPF engine context to destroy any additional data associated with audio stream */
+static apt_bool_t synth_app_stream_destroy(mpf_audio_stream_t *stream)
+{
+       /* nothing to destroy in demo */
+       return TRUE;
+}
+
+/** Callback is called from MPF engine context to perform application stream specific action before open */
+static apt_bool_t synth_app_stream_open(mpf_audio_stream_t *stream)
+{
+       return TRUE;
+}
+
+/** Callback is called from MPF engine context to perform application stream specific action after close */
+static apt_bool_t synth_app_stream_close(mpf_audio_stream_t *stream)
+{
+       return TRUE;
+}
+
+/** Callback is called from MPF engine context to make new frame available to write/send */
+static apt_bool_t synth_app_stream_write(mpf_audio_stream_t *stream, const mpf_frame_t *frame)
+{
+       synth_app_channel_t *synth_channel = stream->obj;
+       if(synth_channel && synth_channel->audio_out) {
+               fwrite(frame->codec_frame.buffer,1,frame->codec_frame.size,synth_channel->audio_out);
+       }
+       return TRUE;
+}
diff --git a/libs/unimrcp/platforms/unimrcp-client/src/demo_util.c b/libs/unimrcp/platforms/unimrcp-client/src/demo_util.c
new file mode 100644 (file)
index 0000000..d281885
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "demo_util.h"
+/* common includes */
+#include "mrcp_session.h"
+#include "mrcp_message.h"
+#include "mrcp_generic_header.h"
+/* synthesizer includes */
+#include "mrcp_synth_header.h"
+#include "mrcp_synth_resource.h"
+/* recognizer includes */
+#include "mrcp_recog_header.h"
+#include "mrcp_recog_resource.h"
+
+static void demo_message_body_set(mrcp_message_t *mrcp_message, const apt_dir_layout_t *dir_layout, const char *file_name)
+{
+       char *file_path = apt_datadir_filepath_get(dir_layout,file_name,mrcp_message->pool);
+       if(file_path) {
+               FILE *file = fopen(file_path,"r");
+               if(file) {
+                       char text[1024];
+                       apr_size_t size;
+                       size = fread(text,1,sizeof(text),file);
+                       apt_string_assign_n(&mrcp_message->body,text,size,mrcp_message->pool);
+                       fclose(file);
+               }
+       }
+}
+
+/** Create demo MRCP message (SPEAK request) */
+mrcp_message_t* demo_speak_message_create(mrcp_session_t *session, mrcp_channel_t *channel, const apt_dir_layout_t *dir_layout)
+{
+       /* create MRCP message */
+       mrcp_message_t *mrcp_message = mrcp_application_message_create(session,channel,SYNTHESIZER_SPEAK);
+       if(mrcp_message) {
+               mrcp_generic_header_t *generic_header;
+               mrcp_synth_header_t *synth_header;
+               /* get/allocate generic header */
+               generic_header = mrcp_generic_header_prepare(mrcp_message);
+               if(generic_header) {
+                       /* set generic header fields */
+                       apt_string_assign(&generic_header->content_type,"application/synthesis+ssml",mrcp_message->pool);
+                       mrcp_generic_header_property_add(mrcp_message,GENERIC_HEADER_CONTENT_TYPE);
+               }
+               /* get/allocate synthesizer header */
+               synth_header = mrcp_resource_header_prepare(mrcp_message);
+               if(synth_header) {
+                       /* set synthesizer header fields */
+                       synth_header->voice_param.age = 28;
+                       mrcp_resource_header_property_add(mrcp_message,SYNTHESIZER_HEADER_VOICE_AGE);
+               }
+               /* set message body */
+               demo_message_body_set(mrcp_message,dir_layout,"speak.xml");
+       }
+       return mrcp_message;
+}
+
+/** Create demo MRCP message (DEFINE-GRAMMAR request) */
+mrcp_message_t* demo_define_grammar_message_create(mrcp_session_t *session, mrcp_channel_t *channel, const apt_dir_layout_t *dir_layout)
+{
+       /* create MRCP message */
+       mrcp_message_t *mrcp_message = mrcp_application_message_create(session,channel,RECOGNIZER_DEFINE_GRAMMAR);
+       if(mrcp_message) {
+               mrcp_generic_header_t *generic_header;
+               /* get/allocate generic header */
+               generic_header = mrcp_generic_header_prepare(mrcp_message);
+               if(generic_header) {
+                       /* set generic header fields */
+                       if(mrcp_message->start_line.version == MRCP_VERSION_2) {
+                               apt_string_assign(&generic_header->content_type,"application/srgs+xml",mrcp_message->pool);
+                       }
+                       else {
+                               apt_string_assign(&generic_header->content_type,"application/grammar+xml",mrcp_message->pool);
+                       }
+                       mrcp_generic_header_property_add(mrcp_message,GENERIC_HEADER_CONTENT_TYPE);
+                       apt_string_assign(&generic_header->content_id,"request1@form-level.store",mrcp_message->pool);
+                       mrcp_generic_header_property_add(mrcp_message,GENERIC_HEADER_CONTENT_ID);
+               }
+               /* set message body */
+               demo_message_body_set(mrcp_message,dir_layout,"grammar.xml");
+       }
+       return mrcp_message;
+}
+
+/** Create demo MRCP message (RECOGNIZE request) */
+mrcp_message_t* demo_recognize_message_create(mrcp_session_t *session, mrcp_channel_t *channel, const apt_dir_layout_t *dir_layout)
+{
+       const char text[] = "session:request1@form-level.store";
+
+       /* create MRCP message */
+       mrcp_message_t *mrcp_message = mrcp_application_message_create(session,channel,RECOGNIZER_RECOGNIZE);
+       if(mrcp_message) {
+               mrcp_recog_header_t *recog_header;
+               mrcp_generic_header_t *generic_header;
+               /* get/allocate generic header */
+               generic_header = mrcp_generic_header_prepare(mrcp_message);
+               if(generic_header) {
+                       /* set generic header fields */
+                       apt_string_assign(&generic_header->content_type,"text/uri-list",mrcp_message->pool);
+                       mrcp_generic_header_property_add(mrcp_message,GENERIC_HEADER_CONTENT_TYPE);
+               }
+               /* get/allocate recognizer header */
+               recog_header = mrcp_resource_header_prepare(mrcp_message);
+               if(recog_header) {
+                       if(mrcp_message->start_line.version == MRCP_VERSION_2) {
+                               /* set recognizer header fields */
+                               recog_header->cancel_if_queue = FALSE;
+                               mrcp_resource_header_property_add(mrcp_message,RECOGNIZER_HEADER_CANCEL_IF_QUEUE);
+                       }
+                       recog_header->no_input_timeout = 5000;
+                       mrcp_resource_header_property_add(mrcp_message,RECOGNIZER_HEADER_NO_INPUT_TIMEOUT);
+                       recog_header->recognition_timeout = 10000;
+                       mrcp_resource_header_property_add(mrcp_message,RECOGNIZER_HEADER_RECOGNITION_TIMEOUT);
+                       recog_header->start_input_timers = TRUE;
+                       mrcp_resource_header_property_add(mrcp_message,RECOGNIZER_HEADER_START_INPUT_TIMERS);
+               }
+               /* set message body */
+               apt_string_assign(&mrcp_message->body,text,mrcp_message->pool);
+       }
+       return mrcp_message;
+}
+
+
+/** Create demo RTP termination descriptor */
+mpf_rtp_termination_descriptor_t* demo_rtp_descriptor_create(apr_pool_t *pool)
+{
+       mpf_codec_descriptor_t *codec_descriptor;
+       mpf_rtp_media_descriptor_t *media;
+       /* create rtp descriptor */
+       mpf_rtp_termination_descriptor_t *rtp_descriptor = apr_palloc(pool,sizeof(mpf_rtp_termination_descriptor_t));
+       mpf_rtp_termination_descriptor_init(rtp_descriptor);
+       /* create rtp local media */
+       media = apr_palloc(pool,sizeof(mpf_rtp_media_descriptor_t));
+       mpf_rtp_media_descriptor_init(media);
+       apt_string_assign(&media->base.ip,"127.0.0.1",pool);
+       media->base.port = 6000;
+       media->base.state = MPF_MEDIA_ENABLED;
+       media->mode = STREAM_MODE_RECEIVE;
+
+       /* initialize codec list */
+       mpf_codec_list_init(&media->codec_list,2,pool);
+       /* set codec descriptor */
+       codec_descriptor = mpf_codec_list_add(&media->codec_list);
+       if(codec_descriptor) {
+               codec_descriptor->payload_type = 0;
+       }
+       /* set another codec descriptor */
+       codec_descriptor = mpf_codec_list_add(&media->codec_list);
+       if(codec_descriptor) {
+               codec_descriptor->payload_type = 96;
+               apt_string_set(&codec_descriptor->name,"PCMU");
+               codec_descriptor->sampling_rate = 16000;
+               codec_descriptor->channel_count = 1;
+       }
+
+       rtp_descriptor->audio.local = media;
+       return rtp_descriptor;
+}
diff --git a/libs/unimrcp/platforms/unimrcp-client/src/main.c b/libs/unimrcp/platforms/unimrcp-client/src/main.c
new file mode 100644 (file)
index 0000000..6a242ca
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <apr_getopt.h>
+#include <apr_file_info.h>
+#include "demo_framework.h"
+#include "apt_pool.h"
+#include "apt_log.h"
+
+typedef struct {
+       const char        *root_dir_path;
+       apt_log_priority_e log_priority;
+       apt_log_output_e   log_output;
+} client_options_t;
+
+static apt_bool_t demo_framework_cmdline_process(demo_framework_t *framework, char *cmdline)
+{
+       apt_bool_t running = TRUE;
+       char *name;
+       char *last;
+       name = apr_strtok(cmdline, " ", &last);
+
+       if(strcasecmp(name,"run") == 0) {
+               char *app_name = apr_strtok(NULL, " ", &last);
+               if(app_name) {
+                       char *profile_name = apr_strtok(NULL, " ", &last);
+                       if(!profile_name) {
+                               profile_name = "MRCPv2-Default";
+                       }
+                       demo_framework_app_run(framework,app_name,profile_name);
+               }
+       }
+       else if(strcasecmp(name,"loglevel") == 0) {
+               char *priority = apr_strtok(NULL, " ", &last);
+               if(priority) {
+                       apt_log_priority_set(atol(priority));
+               }
+       }
+       else if(strcasecmp(name,"exit") == 0 || strcmp(name,"quit") == 0) {
+               running = FALSE;
+       }
+       else if(strcasecmp(name,"help") == 0) {
+               printf("usage:\n"
+                      "\n- run [app_name] [profile_name] (run demo application)\n"
+                          "       app_name is one of 'synth', 'recog', 'bypass', 'discover'\n"
+                          "       profile_name is one of 'MRCPv2-Default', 'MRCPv1-Default', ...\n"
+                          "\n       examples: \n"
+                          "           run synth\n"
+                          "           run recog\n"
+                          "           run synth MRCPv1-Default\n"
+                          "           run recog MRCPv1-Default\n"
+                      "\n- loglevel [level] (set loglevel, one of 0,1...7)\n"
+                      "\n- quit, exit\n");
+       }
+       else {
+               printf("unknown command: %s (input help for usage)\n",name);
+       }
+       return running;
+}
+
+static apt_bool_t demo_framework_cmdline_run(demo_framework_t *framework)
+{
+       apt_bool_t running = TRUE;
+       char cmdline[1024];
+       int i;
+       do {
+               printf(">");
+               memset(&cmdline, 0, sizeof(cmdline));
+               for(i = 0; i < sizeof(cmdline); i++) {
+                       cmdline[i] = (char) getchar();
+                       if(cmdline[i] == '\n') {
+                               cmdline[i] = '\0';
+                               break;
+                       }
+               }
+               if(*cmdline) {
+                       running = demo_framework_cmdline_process(framework,cmdline);
+               }
+       }
+       while(running != 0);
+       return TRUE;
+}
+
+static void usage()
+{
+       printf(
+               "\n"
+               "Usage:\n"
+               "\n"
+               "  unimrcpclient [options]\n"
+               "\n"
+               "  Available options:\n"
+               "\n"
+               "   -r [--root-dir] path     : Set the project root directory path.\n"
+               "\n"
+               "   -l [--log-prio] priority : Set the log priority.\n"
+               "                              (0-emergency, ..., 7-debug)\n"
+               "\n"
+               "   -o [--log-output] mode   : Set the log output mode.\n"
+               "                              (0-none, 1-console only, 2-file only, 3-both)\n"
+               "\n"
+               "   -h [--help]              : Show the help.\n"
+               "\n");
+}
+
+static apt_bool_t demo_framework_options_load(client_options_t *options, int argc, const char * const *argv, apr_pool_t *pool)
+{
+       apr_status_t rv;
+       apr_getopt_t *opt = NULL;
+       int optch;
+       const char *optarg;
+
+       const apr_getopt_option_t opt_option[] = {
+               /* long-option, short-option, has-arg flag, description */
+               { "root-dir",    'r', TRUE,  "path to root dir" },  /* -r arg or --root-dir arg */
+               { "log-prio",    'l', TRUE,  "log priority" },      /* -l arg or --log-prio arg */
+               { "log-output",  'o', TRUE,  "log output mode" },   /* -o arg or --log-output arg */
+               { "help",        'h', FALSE, "show help" },         /* -h or --help */
+               { NULL, 0, 0, NULL },                               /* end */
+       };
+
+       rv = apr_getopt_init(&opt, pool , argc, argv);
+       if(rv != APR_SUCCESS) {
+               return FALSE;
+       }
+
+       while((rv = apr_getopt_long(opt, opt_option, &optch, &optarg)) == APR_SUCCESS) {
+               switch(optch) {
+                       case 'r':
+                               options->root_dir_path = optarg;
+                               break;
+                       case 'l':
+                               if(optarg) {
+                                       options->log_priority = atoi(optarg);
+                               }
+                               break;
+                       case 'o':
+                               if(optarg) {
+                                       options->log_output = atoi(optarg);
+                               }
+                               break;
+                       case 'h':
+                               usage();
+                               return FALSE;
+               }
+       }
+
+       if(rv != APR_EOF) {
+               usage();
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+int main(int argc, const char * const *argv)
+{
+       apr_pool_t *pool = NULL;
+       client_options_t options;
+       apt_dir_layout_t *dir_layout;
+       demo_framework_t *framework;
+
+       /* APR global initialization */
+       if(apr_initialize() != APR_SUCCESS) {
+               apr_terminate();
+               return 0;
+       }
+
+       /* create APR pool */
+       pool = apt_pool_create();
+       if(!pool) {
+               apr_terminate();
+               return 0;
+       }
+
+       /* set the default options */
+       options.root_dir_path = "../";
+       options.log_priority = APT_PRIO_INFO;
+       options.log_output = APT_LOG_OUTPUT_CONSOLE;
+
+       /* load options */
+       if(demo_framework_options_load(&options,argc,argv,pool) != TRUE) {
+               apr_pool_destroy(pool);
+               apr_terminate();
+               return 0;
+       }
+
+       /* create the structure of default directories layout */
+       dir_layout = apt_default_dir_layout_create(options.root_dir_path,pool);
+       /* create singleton logger */
+       apt_log_instance_create(options.log_output,options.log_priority,pool);
+
+       if((options.log_output & APT_LOG_OUTPUT_FILE) == APT_LOG_OUTPUT_FILE) {
+               /* open the log file */
+               apt_log_file_open(dir_layout->log_dir_path,"unimrcpclient",MAX_LOG_FILE_SIZE,MAX_LOG_FILE_COUNT,pool);
+       }
+
+       /* create demo framework */
+       framework = demo_framework_create(dir_layout);
+       if(framework) {
+               /* run command line  */
+               demo_framework_cmdline_run(framework);
+               /* destroy demo framework */
+               demo_framework_destroy(framework);
+       }
+
+       /* destroy singleton logger */
+       apt_log_instance_destroy();
+       /* destroy APR pool */
+       apr_pool_destroy(pool);
+       /* APR global termination */
+       apr_terminate();
+       return 0;
+}
diff --git a/libs/unimrcp/platforms/unimrcp-client/unimrcpclient.vcproj b/libs/unimrcp/platforms/unimrcp-client/unimrcpclient.vcproj
new file mode 100644 (file)
index 0000000..eb42c46
--- /dev/null
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="unimrcpclient"
+       ProjectGUID="{57FAF32E-49FD-491F-895D-132D0D5EFE0A}"
+       RootNamespace="unimrcpclient"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\unimrcpclient.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="include"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="$(UniMRCPClientLibs)"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\unimrcpclient.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="include"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="$(UniMRCPClientLibs)"
+                               LinkTimeCodeGeneration="1"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+                       >
+                       <File
+                               RelativePath=".\src\demo_bypass_application.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\demo_discover_application.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\demo_framework.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\demo_recog_application.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\demo_synth_application.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\demo_util.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\main.c"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+                       <File
+                               RelativePath=".\include\demo_application.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\demo_framework.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\demo_util.h"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/platforms/unimrcp-server/Makefile.am b/libs/unimrcp/platforms/unimrcp-server/Makefile.am
new file mode 100644 (file)
index 0000000..284c63a
--- /dev/null
@@ -0,0 +1,19 @@
+MAINTAINERCLEANFILES   = Makefile.in
+
+INCLUDES               = -Iinclude \
+                         -I$(top_srcdir)/platforms/libunimrcp-server/include \
+                         -I$(top_srcdir)/libs/mrcp-server/include \
+                         -I$(top_srcdir)/libs/mrcp-engine/include \
+                         -I$(top_srcdir)/libs/mrcp-signaling/include \
+                         -I$(top_srcdir)/libs/mrcpv2-transport/include \
+                         -I$(top_srcdir)/libs/mrcp/include \
+                         -I$(top_srcdir)/libs/mrcp/message/include \
+                         -I$(top_srcdir)/libs/mrcp/control/include \
+                         -I$(top_srcdir)/libs/mrcp/resources/include \
+                         -I$(top_srcdir)/libs/mpf/include \
+                         -I$(top_srcdir)/libs/apr-toolkit/include \
+                         $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+bin_PROGRAMS           = unimrcpserver
+unimrcpserver_SOURCES  = src/main.c src/uni_cmdline.c src/uni_daemon.c
+unimrcpserver_LDADD    = $(top_builddir)/platforms/libunimrcp-server/libunimrcpserver.la
diff --git a/libs/unimrcp/platforms/unimrcp-server/src/main.c b/libs/unimrcp/platforms/unimrcp-server/src/main.c
new file mode 100644 (file)
index 0000000..eb283f9
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <apr_getopt.h>
+#include <apr_file_info.h>
+#include "apt_pool.h"
+#include "apt_dir_layout.h"
+#include "apt_log.h"
+
+typedef struct {
+       const char        *root_dir_path;
+       apt_bool_t         foreground;
+       apt_log_priority_e log_priority;
+       apt_log_output_e   log_output;
+} server_options_t;
+
+#ifdef WIN32
+apt_bool_t uni_service_run(apt_dir_layout_t *dir_layout, apr_pool_t *pool);
+#else
+apt_bool_t uni_daemon_run(apt_dir_layout_t *dir_layout, apr_pool_t *pool);
+#endif
+
+apt_bool_t uni_cmdline_run(apt_dir_layout_t *dir_layout, apr_pool_t *pool);
+
+
+static void usage()
+{
+       printf(
+               "\n"
+               "Usage:\n"
+               "\n"
+               "  unimrcpserver [options]\n"
+               "\n"
+               "  Available options:\n"
+               "\n"
+               "   -r [--root-dir] path     : Set the project root directory path.\n"
+               "\n"
+               "   -l [--log-prio] priority : Set the log priority.\n"
+               "                              (0-emergency, ..., 7-debug)\n"
+               "\n"
+               "   -o [--log-output] mode   : Set the log output mode.\n"
+               "                              (0-none, 1-console only, 2-file only, 3-both)\n"
+               "\n"
+#ifdef WIN32
+               "   -s [--service]           : Run as the Windows service.\n"
+               "\n"
+#else
+               "   -d [--daemon]            : Run as the daemon.\n"
+               "\n"
+#endif
+               "   -h [--help]              : Show the help.\n"
+               "\n");
+}
+
+static apt_bool_t options_load(server_options_t *options, int argc, const char * const *argv, apr_pool_t *pool)
+{
+       apr_status_t rv;
+       apr_getopt_t *opt = NULL;
+       int optch;
+       const char *optarg;
+
+       const apr_getopt_option_t opt_option[] = {
+               /* long-option, short-option, has-arg flag, description */
+               { "root-dir",    'r', TRUE,  "path to root dir" },  /* -r arg or --root-dir arg */
+               { "log-prio",    'l', TRUE,  "log priority" },      /* -l arg or --log-prio arg */
+               { "log-output",  'o', TRUE,  "log output mode" },   /* -o arg or --log-output arg */
+#ifdef WIN32
+               { "service",     's', FALSE, "run as service" },    /* -s or --service */
+#else
+               { "daemon",      'd', FALSE, "start as daemon" },   /* -d or --daemon */
+#endif
+               { "help",        'h', FALSE, "show help" },         /* -h or --help */
+               { NULL, 0, 0, NULL },                               /* end */
+       };
+
+       rv = apr_getopt_init(&opt, pool , argc, argv);
+       if(rv != APR_SUCCESS) {
+               return FALSE;
+       }
+
+       while((rv = apr_getopt_long(opt, opt_option, &optch, &optarg)) == APR_SUCCESS) {
+               switch(optch) {
+                       case 'r':
+                               options->root_dir_path = optarg;
+                               break;
+                       case 'l':
+                               if(optarg) {
+                                       options->log_priority = atoi(optarg);
+                               }
+                               break;
+                       case 'o':
+                               if(optarg) {
+                                       options->log_output = atoi(optarg);
+                               }
+                               break;
+#ifdef WIN32
+                       case 's':
+                               options->foreground = FALSE;
+                               break;
+#else
+                       case 'd':
+                               options->foreground = FALSE;
+                               break;
+#endif
+                       case 'h':
+                               usage();
+                               return FALSE;
+               }
+       }
+
+       if(rv != APR_EOF) {
+               usage();
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+int main(int argc, const char * const *argv)
+{
+       apr_pool_t *pool = NULL;
+       server_options_t options;
+       apt_dir_layout_t *dir_layout;
+
+       /* APR global initialization */
+       if(apr_initialize() != APR_SUCCESS) {
+               apr_terminate();
+               return 0;
+       }
+
+       /* create APR pool */
+       pool = apt_pool_create();
+       if(!pool) {
+               apr_terminate();
+               return 0;
+       }
+
+       /* set the default options */
+       options.root_dir_path = "../";
+       options.foreground = TRUE;
+       options.log_priority = APT_PRIO_INFO;
+       options.log_output = APT_LOG_OUTPUT_CONSOLE;
+
+       /* load options */
+       if(options_load(&options,argc,argv,pool) != TRUE) {
+               apr_pool_destroy(pool);
+               apr_terminate();
+               return 0;
+       }
+
+       /* create the structure of default directories layout */
+       dir_layout = apt_default_dir_layout_create(options.root_dir_path,pool);
+       /* create singleton logger */
+       apt_log_instance_create(options.log_output,options.log_priority,pool);
+
+       if((options.log_output & APT_LOG_OUTPUT_FILE) == APT_LOG_OUTPUT_FILE) {
+               /* open the log file */
+               apt_log_file_open(dir_layout->log_dir_path,"unimrcpserver",MAX_LOG_FILE_SIZE,MAX_LOG_FILE_COUNT,pool);
+       }
+
+       if(options.foreground == TRUE) {
+               /* run command line */
+               uni_cmdline_run(dir_layout,pool);
+       }
+#ifdef WIN32
+       else {
+               /* run as windows service */
+               uni_service_run(dir_layout,pool);
+       }
+#else
+       else {
+               /* run as daemon */
+               uni_daemon_run(dir_layout,pool);
+       }
+#endif
+
+       /* destroy singleton logger */
+       apt_log_instance_destroy();
+       /* destroy APR pool */
+       apr_pool_destroy(pool);
+       /* APR global termination */
+       apr_terminate();
+       return 0;
+}
diff --git a/libs/unimrcp/platforms/unimrcp-server/src/uni_cmdline.c b/libs/unimrcp/platforms/unimrcp-server/src/uni_cmdline.c
new file mode 100644 (file)
index 0000000..bac1d66
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "unimrcp_server.h"
+#include "apt_log.h"
+
+static apt_bool_t cmdline_process(char *cmdline)
+{
+       apt_bool_t running = TRUE;
+       char *name;
+       char *last;
+       name = apr_strtok(cmdline, " ", &last);
+
+       if(strcasecmp(name,"loglevel") == 0) {
+               char *priority = apr_strtok(NULL, " ", &last);
+               if(priority) {
+                       apt_log_priority_set(atol(priority));
+               }
+       }
+       else if(strcasecmp(name,"exit") == 0 || strcmp(name,"quit") == 0) {
+               running = FALSE;
+       }
+       else if(strcasecmp(name,"help") == 0) {
+               printf("usage:\n");
+               printf("- loglevel [level] (set loglevel, one of 0,1...7)\n");
+               printf("- quit, exit\n");
+       }
+       else {
+               printf("unknown command: %s (input help for usage)\n",name);
+       }
+       return running;
+}
+
+apt_bool_t uni_cmdline_run(apt_dir_layout_t *dir_layout, apr_pool_t *pool)
+{
+       apt_bool_t running = TRUE;
+       char cmdline[1024];
+       int i;
+       mrcp_server_t *server;
+
+       /* start server */
+       server = unimrcp_server_start(dir_layout);
+       if(!server) {
+               return FALSE;
+       }
+
+       do {
+               printf(">");
+               memset(&cmdline, 0, sizeof(cmdline));
+               for(i = 0; i < sizeof(cmdline); i++) {
+                       cmdline[i] = (char) getchar();
+                       if(cmdline[i] == '\n') {
+                               cmdline[i] = '\0';
+                               break;
+                       }
+               }
+               if(*cmdline) {
+                       running = cmdline_process(cmdline);
+               }
+       }
+       while(running != 0);
+
+       /* shutdown server */
+       unimrcp_server_shutdown(server);
+       return TRUE;
+}
diff --git a/libs/unimrcp/platforms/unimrcp-server/src/uni_daemon.c b/libs/unimrcp/platforms/unimrcp-server/src/uni_daemon.c
new file mode 100644 (file)
index 0000000..ee72870
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_signal.h>
+#include <apr_thread_proc.h>
+#include "unimrcp_server.h"
+#include "apt_log.h"
+
+static apt_bool_t daemon_running;
+
+static void sigterm_handler(int signo)
+{
+       daemon_running = FALSE;
+}
+
+apt_bool_t uni_daemon_run(apt_dir_layout_t *dir_layout, apr_pool_t *pool)
+{
+       mrcp_server_t *server;
+
+       daemon_running = TRUE;
+       apr_signal(SIGTERM,sigterm_handler);
+
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Run as Daemon");
+       apr_proc_detach(APR_PROC_DETACH_DAEMONIZE);
+
+       /* start server */
+       server = unimrcp_server_start(dir_layout);
+       if(!server) {
+               return FALSE;
+       }
+
+       while(daemon_running) apr_sleep(1000000);
+
+       /* shutdown server */
+       unimrcp_server_shutdown(server);
+       return TRUE;
+}
diff --git a/libs/unimrcp/platforms/unimrcp-server/src/uni_service.c b/libs/unimrcp/platforms/unimrcp-server/src/uni_service.c
new file mode 100644 (file)
index 0000000..9b597d8
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <windows.h>
+#include <apr_lib.h>
+#include "unimrcp_server.h"
+#include "apt_log.h"
+
+#define WIN_SERVICE_NAME "unimrcp"
+
+static SERVICE_STATUS_HANDLE win_service_status_handle = NULL;
+static SERVICE_STATUS win_service_status;
+
+static mrcp_server_t *server = NULL;
+static apt_dir_layout_t *service_dir_layout = NULL;
+
+/** SCM state change handler */
+static void WINAPI win_service_handler(DWORD control)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Service Handler %d",control);
+       switch (control)
+       {
+               case SERVICE_CONTROL_INTERROGATE:
+                       break;
+               case SERVICE_CONTROL_SHUTDOWN:
+               case SERVICE_CONTROL_STOP:
+                       if(server) {
+                               win_service_status.dwCurrentState = SERVICE_STOP_PENDING; 
+                               if(!SetServiceStatus(win_service_status_handle, &win_service_status)) { 
+                                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Set Service Status %d",GetLastError());
+                               }
+
+                               /* shutdown server */
+                               unimrcp_server_shutdown(server);
+                       }
+                       win_service_status.dwCurrentState = SERVICE_STOPPED; 
+                       win_service_status.dwCheckPoint = 0; 
+                       win_service_status.dwWaitHint = 0; 
+                       break;
+       }
+
+       if(!SetServiceStatus(win_service_status_handle, &win_service_status)) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Set Service Status %d",GetLastError());
+       }
+}
+
+static void WINAPI win_service_main(DWORD argc, LPTSTR *argv)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Service Main");
+       win_service_status.dwServiceType = SERVICE_WIN32;
+       win_service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
+       win_service_status.dwWin32ExitCode = 0;
+       win_service_status.dwServiceSpecificExitCode = 0;
+       win_service_status.dwCheckPoint = 0;
+       win_service_status.dwWaitHint = 0;
+
+       win_service_status_handle = RegisterServiceCtrlHandler(WIN_SERVICE_NAME, win_service_handler);
+       if(win_service_status_handle == (SERVICE_STATUS_HANDLE)0) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Register Service Control Handler %d",GetLastError());
+               return;
+       } 
+
+       win_service_status.dwCurrentState = SERVICE_START_PENDING;
+       if(!SetServiceStatus(win_service_status_handle, &win_service_status)) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Set Service Status %d",GetLastError());
+       } 
+
+       /* start server */
+       server = unimrcp_server_start(service_dir_layout);
+
+       win_service_status.dwCurrentState =  server ? SERVICE_RUNNING : SERVICE_STOPPED;
+       if(!SetServiceStatus(win_service_status_handle, &win_service_status)) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Set Service Status %d",GetLastError());
+       } 
+}
+
+/** Run SCM service */
+apt_bool_t uni_service_run(apt_dir_layout_t *dir_layout, apr_pool_t *pool)
+{
+       SERVICE_TABLE_ENTRY win_service_table[] = {
+               { WIN_SERVICE_NAME, win_service_main },
+               { NULL, NULL }
+       };
+
+       service_dir_layout = dir_layout;
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Run as Service");
+       if(!StartServiceCtrlDispatcher(win_service_table)) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Connect to SCM %d",GetLastError());
+       }
+       return TRUE;
+}
diff --git a/libs/unimrcp/platforms/unimrcp-server/unimrcpserver.vcproj b/libs/unimrcp/platforms/unimrcp-server/unimrcpserver.vcproj
new file mode 100644 (file)
index 0000000..68fb5d3
--- /dev/null
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="unimrcpserver"
+       ProjectGUID="{592CF22D-3F8F-4A77-A174-130D77B7623B}"
+       RootNamespace="unimrcpserver"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\unimrcpserver.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="$(UniMRCPServerLibs)"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\unimrcpserver.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="$(UniMRCPServerLibs)"
+                               LinkTimeCodeGeneration="1"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+                       >
+                       <File
+                               RelativePath=".\src\main.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\uni_cmdline.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\uni_daemon.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\uni_service.c"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/plugins/Makefile.am b/libs/unimrcp/plugins/Makefile.am
new file mode 100644 (file)
index 0000000..ff08fd3
--- /dev/null
@@ -0,0 +1,15 @@
+MAINTAINERCLEANFILES   = Makefile.in
+
+SUBDIRS                =
+
+if DEMOSYNTH_PLUGIN
+SUBDIRS               += demo-synth
+endif
+
+if DEMORECOG_PLUGIN
+SUBDIRS               += demo-recog
+endif
+
+if CEPSTRAL_PLUGIN
+SUBDIRS               += mrcp-cepstral
+endif
diff --git a/libs/unimrcp/plugins/demo-recog/Makefile.am b/libs/unimrcp/plugins/demo-recog/Makefile.am
new file mode 100644 (file)
index 0000000..ebf041f
--- /dev/null
@@ -0,0 +1,16 @@
+MAINTAINERCLEANFILES      = Makefile.in
+
+INCLUDES                   = -Iinclude \
+                             -I$(top_srcdir)/libs/mrcp-engine/include \
+                             -I$(top_srcdir)/libs/mrcp/include \
+                             -I$(top_srcdir)/libs/mrcp/message/include \
+                             -I$(top_srcdir)/libs/mrcp/control/include \
+                             -I$(top_srcdir)/libs/mrcp/resources/include \
+                             -I$(top_srcdir)/libs/mpf/include \
+                             -I$(top_srcdir)/libs/apr-toolkit/include \
+                             $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+plugin_LTLIBRARIES         = demorecog.la
+
+demorecog_la_SOURCES       = src/demo_recog_engine.c
+demorecog_la_LDFLAGS       = -module $(PLUGIN_LT_VERSION)
diff --git a/libs/unimrcp/plugins/demo-recog/demorecog.vcproj b/libs/unimrcp/plugins/demo-recog/demorecog.vcproj
new file mode 100644 (file)
index 0000000..5c8c6e5
--- /dev/null
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="demorecog"\r
+       ProjectGUID="{B495B6D9-AF84-479D-B30A-313C16EF8BFD}"\r
+       RootNamespace="demorecog"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\unimrcpplugin.vsprops"\r
+                       CharacterSet="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="include"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\unimrcpplugin.vsprops"\r
+                       CharacterSet="1"\r
+                       WholeProgramOptimization="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="include"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="include"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="src"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\src\demo_recog_engine.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/libs/unimrcp/plugins/demo-recog/src/demo_recog_engine.c b/libs/unimrcp/plugins/demo-recog/src/demo_recog_engine.c
new file mode 100644 (file)
index 0000000..72a86a5
--- /dev/null
@@ -0,0 +1,508 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* 
+ * Some mandatory rules for plugin implementation.
+ * 1. Each plugin MUST contain the following function as an entry point of the plugin
+ *        MRCP_PLUGIN_DECLARE(mrcp_resource_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
+ * 2. One and only one response MUST be sent back to the received request.
+ * 3. Methods (callbacks) of the MRCP engine channel MUST not block.
+ *   (asynch response can be sent from the context of other thread)
+ * 4. Methods (callbacks) of the MPF engine stream MUST not block.
+ */
+
+#include "mrcp_resource_engine.h"
+#include "mrcp_recog_resource.h"
+#include "mrcp_recog_header.h"
+#include "mrcp_generic_header.h"
+#include "mrcp_message.h"
+#include "mpf_activity_detector.h"
+#include "apt_consumer_task.h"
+#include "apt_log.h"
+
+#define RECOG_ENGINE_TASK_NAME "Demo Recog Engine"
+
+typedef struct demo_recog_engine_t demo_recog_engine_t;
+typedef struct demo_recog_channel_t demo_recog_channel_t;
+typedef struct demo_recog_msg_t demo_recog_msg_t;
+
+/** Declaration of recognizer engine methods */
+static apt_bool_t demo_recog_engine_destroy(mrcp_resource_engine_t *engine);
+static apt_bool_t demo_recog_engine_open(mrcp_resource_engine_t *engine);
+static apt_bool_t demo_recog_engine_close(mrcp_resource_engine_t *engine);
+static mrcp_engine_channel_t* demo_recog_engine_channel_create(mrcp_resource_engine_t *engine, apr_pool_t *pool);
+
+static const struct mrcp_engine_method_vtable_t engine_vtable = {
+       demo_recog_engine_destroy,
+       demo_recog_engine_open,
+       demo_recog_engine_close,
+       demo_recog_engine_channel_create
+};
+
+
+/** Declaration of recognizer channel methods */
+static apt_bool_t demo_recog_channel_destroy(mrcp_engine_channel_t *channel);
+static apt_bool_t demo_recog_channel_open(mrcp_engine_channel_t *channel);
+static apt_bool_t demo_recog_channel_close(mrcp_engine_channel_t *channel);
+static apt_bool_t demo_recog_channel_request_process(mrcp_engine_channel_t *channel, mrcp_message_t *request);
+
+static const struct mrcp_engine_channel_method_vtable_t channel_vtable = {
+       demo_recog_channel_destroy,
+       demo_recog_channel_open,
+       demo_recog_channel_close,
+       demo_recog_channel_request_process
+};
+
+/** Declaration of recognizer audio stream methods */
+static apt_bool_t demo_recog_stream_destroy(mpf_audio_stream_t *stream);
+static apt_bool_t demo_recog_stream_open(mpf_audio_stream_t *stream);
+static apt_bool_t demo_recog_stream_close(mpf_audio_stream_t *stream);
+static apt_bool_t demo_recog_stream_write(mpf_audio_stream_t *stream, const mpf_frame_t *frame);
+
+static const mpf_audio_stream_vtable_t audio_stream_vtable = {
+       demo_recog_stream_destroy,
+       NULL,
+       NULL,
+       NULL,
+       demo_recog_stream_open,
+       demo_recog_stream_close,
+       demo_recog_stream_write
+};
+
+/** Declaration of demo recognizer engine */
+struct demo_recog_engine_t {
+       apt_consumer_task_t    *task;
+};
+
+/** Declaration of demo recognizer channel */
+struct demo_recog_channel_t {
+       /** Back pointer to engine */
+       demo_recog_engine_t     *demo_engine;
+       /** Engine channel base */
+       mrcp_engine_channel_t   *channel;
+
+       /** Active (in-progress) recognition request */
+       mrcp_message_t          *recog_request;
+       /** Pending stop response */
+       mrcp_message_t          *stop_response;
+       /** Indicates whether input timers are started */
+       apt_bool_t               timers_started;
+       /** Voice activity detector */
+       mpf_activity_detector_t *detector;
+       /** File to write utterance to */
+       FILE                    *audio_out;
+};
+
+typedef enum {
+       DEMO_RECOG_MSG_OPEN_CHANNEL,
+       DEMO_RECOG_MSG_CLOSE_CHANNEL,
+       DEMO_RECOG_MSG_REQUEST_PROCESS
+} demo_recog_msg_type_e;
+
+/** Declaration of demo recognizer task message */
+struct demo_recog_msg_t {
+       demo_recog_msg_type_e  type;
+       mrcp_engine_channel_t *channel; 
+       mrcp_message_t        *request;
+};
+
+static apt_bool_t demo_recog_msg_signal(demo_recog_msg_type_e type, mrcp_engine_channel_t *channel, mrcp_message_t *request);
+static apt_bool_t demo_recog_msg_process(apt_task_t *task, apt_task_msg_t *msg);
+
+/** Declare this macro to use log routine of the server, plugin is loaded from */
+MRCP_PLUGIN_LOGGER_IMPLEMENT
+
+/** Create demo recognizer engine */
+MRCP_PLUGIN_DECLARE(mrcp_resource_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
+{
+       demo_recog_engine_t *demo_engine = apr_palloc(pool,sizeof(demo_recog_engine_t));
+       apt_task_t *task;
+       apt_task_vtable_t *vtable;
+       apt_task_msg_pool_t *msg_pool;
+
+       msg_pool = apt_task_msg_pool_create_dynamic(sizeof(demo_recog_msg_t),pool);
+       demo_engine->task = apt_consumer_task_create(demo_engine,msg_pool,pool);
+       if(!demo_engine->task) {
+               return NULL;
+       }
+       task = apt_consumer_task_base_get(demo_engine->task);
+       apt_task_name_set(task,RECOG_ENGINE_TASK_NAME);
+       vtable = apt_task_vtable_get(task);
+       if(vtable) {
+               vtable->process_msg = demo_recog_msg_process;
+       }
+
+       /* create resource engine base */
+       return mrcp_resource_engine_create(
+                                       MRCP_RECOGNIZER_RESOURCE,  /* MRCP resource identifier */
+                                       demo_engine,               /* object to associate */
+                                       &engine_vtable,            /* virtual methods table of resource engine */
+                                       pool);                     /* pool to allocate memory from */
+}
+
+/** Destroy recognizer engine */
+static apt_bool_t demo_recog_engine_destroy(mrcp_resource_engine_t *engine)
+{
+       demo_recog_engine_t *demo_engine = engine->obj;
+       if(demo_engine->task) {
+               apt_task_t *task = apt_consumer_task_base_get(demo_engine->task);
+               apt_task_destroy(task);
+               demo_engine->task = NULL;
+       }
+       return TRUE;
+}
+
+/** Open recognizer engine */
+static apt_bool_t demo_recog_engine_open(mrcp_resource_engine_t *engine)
+{
+       demo_recog_engine_t *demo_engine = engine->obj;
+       if(demo_engine->task) {
+               apt_task_t *task = apt_consumer_task_base_get(demo_engine->task);
+               apt_task_start(task);
+       }
+       return TRUE;
+}
+
+/** Close recognizer engine */
+static apt_bool_t demo_recog_engine_close(mrcp_resource_engine_t *engine)
+{
+       demo_recog_engine_t *demo_engine = engine->obj;
+       if(demo_engine->task) {
+               apt_task_t *task = apt_consumer_task_base_get(demo_engine->task);
+               apt_task_terminate(task,TRUE);
+       }
+       return TRUE;
+}
+
+static mrcp_engine_channel_t* demo_recog_engine_channel_create(mrcp_resource_engine_t *engine, apr_pool_t *pool)
+{
+       /* create demo recog channel */
+       demo_recog_channel_t *recog_channel = apr_palloc(pool,sizeof(demo_recog_channel_t));
+       recog_channel->demo_engine = engine->obj;
+       recog_channel->recog_request = NULL;
+       recog_channel->stop_response = NULL;
+       recog_channel->detector = mpf_activity_detector_create(pool);
+       recog_channel->audio_out = NULL;
+       /* create engine channel base */
+       recog_channel->channel = mrcp_engine_sink_channel_create(
+                       engine,               /* resource engine */
+                       &channel_vtable,      /* virtual methods table of engine channel */
+                       &audio_stream_vtable, /* virtual methods table of audio stream */
+                       recog_channel,        /* object to associate */
+                       NULL,                 /* codec descriptor might be NULL by default */
+                       pool);                /* pool to allocate memory from */
+       return recog_channel->channel;
+}
+
+/** Destroy engine channel */
+static apt_bool_t demo_recog_channel_destroy(mrcp_engine_channel_t *channel)
+{
+       demo_recog_channel_t *recog_channel = channel->method_obj;
+       if(recog_channel->audio_out) {
+               fclose(recog_channel->audio_out);
+               recog_channel->audio_out = NULL;
+       }
+
+       return TRUE;
+}
+
+/** Open engine channel (asynchronous response MUST be sent)*/
+static apt_bool_t demo_recog_channel_open(mrcp_engine_channel_t *channel)
+{
+       return demo_recog_msg_signal(DEMO_RECOG_MSG_OPEN_CHANNEL,channel,NULL);
+}
+
+/** Close engine channel (asynchronous response MUST be sent)*/
+static apt_bool_t demo_recog_channel_close(mrcp_engine_channel_t *channel)
+{
+       return demo_recog_msg_signal(DEMO_RECOG_MSG_CLOSE_CHANNEL,channel,NULL);
+}
+
+/** Process MRCP channel request (asynchronous response MUST be sent)*/
+static apt_bool_t demo_recog_channel_request_process(mrcp_engine_channel_t *channel, mrcp_message_t *request)
+{
+       return demo_recog_msg_signal(DEMO_RECOG_MSG_REQUEST_PROCESS,channel,request);
+}
+
+/** Process RECOGNIZE request */
+static apt_bool_t demo_recog_channel_recognize(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response)
+{
+       /* process RECOGNIZE request */
+       mrcp_recog_header_t *recog_header;
+       demo_recog_channel_t *recog_channel = channel->method_obj;
+       recog_channel->timers_started = TRUE;
+
+       /* get recognizer header */
+       recog_header = mrcp_resource_header_get(request);
+       if(recog_header) {
+               if(mrcp_resource_header_property_check(request,RECOGNIZER_HEADER_START_INPUT_TIMERS) == TRUE) {
+                       recog_channel->timers_started = recog_header->start_input_timers;
+               }
+               if(mrcp_resource_header_property_check(request,RECOGNIZER_HEADER_NO_INPUT_TIMEOUT) == TRUE) {
+                       mpf_activity_detector_noinput_timeout_set(recog_channel->detector,recog_header->no_input_timeout);
+               }
+               if(mrcp_resource_header_property_check(request,RECOGNIZER_HEADER_SPEECH_COMPLETE_TIMEOUT) == TRUE) {
+                       mpf_activity_detector_complete_timeout_set(recog_channel->detector,recog_header->speech_complete_timeout);
+               }
+       }
+
+       if(!recog_channel->audio_out) {
+               const apt_dir_layout_t *dir_layout = channel->engine->dir_layout;
+               char *file_name = apr_pstrcat(channel->pool,"utter-",request->channel_id.session_id.buf,".pcm",NULL);
+               char *file_path = apt_datadir_filepath_get(dir_layout,file_name,channel->pool);
+               if(file_path) {
+                       recog_channel->audio_out = fopen(file_path,"wb");
+               }
+       }
+
+       response->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS;
+       /* send asynchronous response */
+       mrcp_engine_channel_message_send(channel,response);
+       recog_channel->recog_request = request;
+       return TRUE;
+}
+
+/** Process STOP request */
+static apt_bool_t demo_recog_channel_stop(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response)
+{
+       /* process STOP request */
+       demo_recog_channel_t *recog_channel = channel->method_obj;
+       /* store STOP request, make sure there is no more activity and only then send the response */
+       recog_channel->stop_response = response;
+       return TRUE;
+}
+
+/** Process START-INPUT-TIMERS request */
+static apt_bool_t demo_recog_channel_timers_start(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response)
+{
+       demo_recog_channel_t *recog_channel = channel->method_obj;
+       recog_channel->timers_started = TRUE;
+       return mrcp_engine_channel_message_send(channel,response);
+}
+
+/** Dispatch MRCP request */
+static apt_bool_t demo_recog_channel_request_dispatch(mrcp_engine_channel_t *channel, mrcp_message_t *request)
+{
+       apt_bool_t processed = FALSE;
+       mrcp_message_t *response = mrcp_response_create(request,request->pool);
+       switch(request->start_line.method_id) {
+               case RECOGNIZER_SET_PARAMS:
+                       break;
+               case RECOGNIZER_GET_PARAMS:
+                       break;
+               case RECOGNIZER_DEFINE_GRAMMAR:
+                       break;
+               case RECOGNIZER_RECOGNIZE:
+                       processed = demo_recog_channel_recognize(channel,request,response);
+                       break;
+               case RECOGNIZER_GET_RESULT:
+                       break;
+               case RECOGNIZER_START_INPUT_TIMERS:
+                       processed = demo_recog_channel_timers_start(channel,request,response);
+                       break;
+               case RECOGNIZER_STOP:
+                       processed = demo_recog_channel_stop(channel,request,response);
+                       break;
+               default:
+                       break;
+       }
+       if(processed == FALSE) {
+               /* send asynchronous response for not handled request */
+               mrcp_engine_channel_message_send(channel,response);
+       }
+       return TRUE;
+}
+
+/** Callback is called from MPF engine context to destroy any additional data associated with audio stream */
+static apt_bool_t demo_recog_stream_destroy(mpf_audio_stream_t *stream)
+{
+       return TRUE;
+}
+
+/** Callback is called from MPF engine context to perform any action before open */
+static apt_bool_t demo_recog_stream_open(mpf_audio_stream_t *stream)
+{
+       return TRUE;
+}
+
+/** Callback is called from MPF engine context to perform any action after close */
+static apt_bool_t demo_recog_stream_close(mpf_audio_stream_t *stream)
+{
+       return TRUE;
+}
+
+/* Raise demo START-OF-INPUT event */
+static apt_bool_t demo_recog_start_of_input(demo_recog_channel_t *recog_channel)
+{
+       /* create START-OF-INPUT event */
+       mrcp_message_t *message = mrcp_event_create(
+                                               recog_channel->recog_request,
+                                               RECOGNIZER_START_OF_INPUT,
+                                               recog_channel->recog_request->pool);
+       if(!message) {
+               return FALSE;
+       }
+
+       /* set request state */
+       message->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS;
+       /* send asynch event */
+       return mrcp_engine_channel_message_send(recog_channel->channel,message);
+}
+
+/* Load demo recognition result */
+static apt_bool_t demo_recog_result_load(demo_recog_channel_t *recog_channel, mrcp_message_t *message)
+{
+       FILE *file;
+       mrcp_engine_channel_t *channel = recog_channel->channel;
+       const apt_dir_layout_t *dir_layout = channel->engine->dir_layout;
+       char *file_path = apt_datadir_filepath_get(dir_layout,"result.xml",message->pool);
+       if(!file_path) {
+               return FALSE;
+       }
+       
+       /* read the demo result from file */
+       file = fopen(file_path,"r");
+       if(file) {
+               mrcp_generic_header_t *generic_header;
+               char text[1024];
+               apr_size_t size;
+               size = fread(text,1,sizeof(text),file);
+               apt_string_assign_n(&message->body,text,size,message->pool);
+               fclose(file);
+
+               /* get/allocate generic header */
+               generic_header = mrcp_generic_header_prepare(message);
+               if(generic_header) {
+                       /* set content types */
+                       apt_string_assign(&generic_header->content_type,"application/x-nlsml",message->pool);
+                       mrcp_generic_header_property_add(message,GENERIC_HEADER_CONTENT_TYPE);
+               }
+       }
+       return TRUE;
+}
+
+/* Raise demo RECOGNITION-COMPLETE event */
+static apt_bool_t demo_recog_recognition_complete(demo_recog_channel_t *recog_channel, mrcp_recog_completion_cause_e cause)
+{
+       mrcp_recog_header_t *recog_header;
+       /* create RECOGNITION-COMPLETE event */
+       mrcp_message_t *message = mrcp_event_create(
+                                               recog_channel->recog_request,
+                                               RECOGNIZER_RECOGNITION_COMPLETE,
+                                               recog_channel->recog_request->pool);
+       if(!message) {
+               return FALSE;
+       }
+
+       /* get/allocate recognizer header */
+       recog_header = mrcp_resource_header_prepare(message);
+       if(recog_header) {
+               /* set completion cause */
+               recog_header->completion_cause = cause;
+               mrcp_resource_header_property_add(message,RECOGNIZER_HEADER_COMPLETION_CAUSE);
+       }
+       /* set request state */
+       message->start_line.request_state = MRCP_REQUEST_STATE_COMPLETE;
+
+       if(cause == RECOGNIZER_COMPLETION_CAUSE_SUCCESS) {
+               demo_recog_result_load(recog_channel,message);
+       }
+
+       recog_channel->recog_request = NULL;
+       /* send asynch event */
+       return mrcp_engine_channel_message_send(recog_channel->channel,message);
+}
+
+/** Callback is called from MPF engine context to write/send new frame */
+static apt_bool_t demo_recog_stream_write(mpf_audio_stream_t *stream, const mpf_frame_t *frame)
+{
+       demo_recog_channel_t *recog_channel = stream->obj;
+       if(recog_channel->stop_response) {
+               /* send asynchronous response to STOP request */
+               mrcp_engine_channel_message_send(recog_channel->channel,recog_channel->stop_response);
+               recog_channel->stop_response = NULL;
+               recog_channel->recog_request = NULL;
+               return TRUE;
+       }
+
+       if(recog_channel->recog_request) {
+               mpf_detector_event_e det_event = mpf_activity_detector_process(recog_channel->detector,frame);
+               switch(det_event) {
+                       case MPF_DETECTOR_EVENT_ACTIVITY:
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected Voice Activity");
+                               demo_recog_start_of_input(recog_channel);
+                               break;
+                       case MPF_DETECTOR_EVENT_INACTIVITY:
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected Voice Inactivity");
+                               demo_recog_recognition_complete(recog_channel,RECOGNIZER_COMPLETION_CAUSE_SUCCESS);
+                               break;
+                       case MPF_DETECTOR_EVENT_NOINPUT:
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected Noinput");
+                               if(recog_channel->timers_started == TRUE) {
+                                       demo_recog_recognition_complete(recog_channel,RECOGNIZER_COMPLETION_CAUSE_NO_INPUT_TIMEOUT);
+                               }
+                               break;
+                       default:
+                               break;
+               }
+
+               if(recog_channel->audio_out) {
+                       fwrite(frame->codec_frame.buffer,1,frame->codec_frame.size,recog_channel->audio_out);
+               }
+       }
+       return TRUE;
+}
+
+static apt_bool_t demo_recog_msg_signal(demo_recog_msg_type_e type, mrcp_engine_channel_t *channel, mrcp_message_t *request)
+{
+       apt_bool_t status = FALSE;
+       demo_recog_channel_t *demo_channel = channel->method_obj;
+       demo_recog_engine_t *demo_engine = demo_channel->demo_engine;
+       apt_task_t *task = apt_consumer_task_base_get(demo_engine->task);
+       apt_task_msg_t *msg = apt_task_msg_get(task);
+       if(msg) {
+               demo_recog_msg_t *demo_msg;
+               msg->type = TASK_MSG_USER;
+               demo_msg = (demo_recog_msg_t*) msg->data;
+
+               demo_msg->type = type;
+               demo_msg->channel = channel;
+               demo_msg->request = request;
+               status = apt_task_msg_signal(task,msg);
+       }
+       return status;
+}
+
+static apt_bool_t demo_recog_msg_process(apt_task_t *task, apt_task_msg_t *msg)
+{
+       demo_recog_msg_t *demo_msg = (demo_recog_msg_t*)msg->data;
+       switch(demo_msg->type) {
+               case DEMO_RECOG_MSG_OPEN_CHANNEL:
+                       /* open channel and send asynch response */
+                       mrcp_engine_channel_open_respond(demo_msg->channel,TRUE);
+                       break;
+               case DEMO_RECOG_MSG_CLOSE_CHANNEL:
+                       /* close channel, make sure there is no activity and send asynch response */
+                       mrcp_engine_channel_close_respond(demo_msg->channel);
+                       break;
+               case DEMO_RECOG_MSG_REQUEST_PROCESS:
+                       demo_recog_channel_request_dispatch(demo_msg->channel,demo_msg->request);
+                       break;
+               default:
+                       break;
+       }
+       return TRUE;
+}
diff --git a/libs/unimrcp/plugins/demo-synth/Makefile.am b/libs/unimrcp/plugins/demo-synth/Makefile.am
new file mode 100644 (file)
index 0000000..0cb6d84
--- /dev/null
@@ -0,0 +1,16 @@
+MAINTAINERCLEANFILES      = Makefile.in
+
+INCLUDES                   = -Iinclude \
+                             -I$(top_srcdir)/libs/mrcp-engine/include \
+                             -I$(top_srcdir)/libs/mrcp/include \
+                             -I$(top_srcdir)/libs/mrcp/message/include \
+                             -I$(top_srcdir)/libs/mrcp/control/include \
+                             -I$(top_srcdir)/libs/mrcp/resources/include \
+                             -I$(top_srcdir)/libs/mpf/include \
+                             -I$(top_srcdir)/libs/apr-toolkit/include \
+                             $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+plugin_LTLIBRARIES         = demosynth.la
+
+demosynth_la_SOURCES       = src/demo_synth_engine.c
+demosynth_la_LDFLAGS       = -module $(PLUGIN_LT_VERSION)
diff --git a/libs/unimrcp/plugins/demo-synth/demosynth.vcproj b/libs/unimrcp/plugins/demo-synth/demosynth.vcproj
new file mode 100644 (file)
index 0000000..3afd81a
--- /dev/null
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="demosynth"
+       ProjectGUID="{92BFA534-C419-4EB2-AAA3-510653F38F08}"
+       RootNamespace="demosynth"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="2"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\unimrcpplugin.vsprops"
+                       CharacterSet="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="include"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="2"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\unimrcpplugin.vsprops"
+                       CharacterSet="1"
+                       WholeProgramOptimization="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="include"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+               </Filter>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       >
+                       <File
+                               RelativePath=".\src\demo_synth_engine.c"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/plugins/demo-synth/src/demo_synth_engine.c b/libs/unimrcp/plugins/demo-synth/src/demo_synth_engine.c
new file mode 100644 (file)
index 0000000..c23129c
--- /dev/null
@@ -0,0 +1,521 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* 
+ * Some mandatory rules for plugin implementation.
+ * 1. Each plugin MUST contain the following function as an entry point of the plugin
+ *        MRCP_PLUGIN_DECLARE(mrcp_resource_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
+ * 2. One and only one response MUST be sent back to the received request.
+ * 3. Methods (callbacks) of the MRCP engine channel MUST not block.
+ *   (asynch response can be sent from the context of other thread)
+ * 4. Methods (callbacks) of the MPF engine stream MUST not block.
+ */
+
+#include "mrcp_resource_engine.h"
+#include "mrcp_synth_resource.h"
+#include "mrcp_synth_header.h"
+#include "mrcp_generic_header.h"
+#include "mrcp_message.h"
+#include "apt_consumer_task.h"
+#include "apt_log.h"
+
+#define SYNTH_ENGINE_TASK_NAME "Demo Synth Engine"
+
+typedef struct demo_synth_engine_t demo_synth_engine_t;
+typedef struct demo_synth_channel_t demo_synth_channel_t;
+typedef struct demo_synth_msg_t demo_synth_msg_t;
+
+/** Declaration of synthesizer engine methods */
+static apt_bool_t demo_synth_engine_destroy(mrcp_resource_engine_t *engine);
+static apt_bool_t demo_synth_engine_open(mrcp_resource_engine_t *engine);
+static apt_bool_t demo_synth_engine_close(mrcp_resource_engine_t *engine);
+static mrcp_engine_channel_t* demo_synth_engine_channel_create(mrcp_resource_engine_t *engine, apr_pool_t *pool);
+
+static const struct mrcp_engine_method_vtable_t engine_vtable = {
+       demo_synth_engine_destroy,
+       demo_synth_engine_open,
+       demo_synth_engine_close,
+       demo_synth_engine_channel_create
+};
+
+
+/** Declaration of synthesizer channel methods */
+static apt_bool_t demo_synth_channel_destroy(mrcp_engine_channel_t *channel);
+static apt_bool_t demo_synth_channel_open(mrcp_engine_channel_t *channel);
+static apt_bool_t demo_synth_channel_close(mrcp_engine_channel_t *channel);
+static apt_bool_t demo_synth_channel_request_process(mrcp_engine_channel_t *channel, mrcp_message_t *request);
+
+static const struct mrcp_engine_channel_method_vtable_t channel_vtable = {
+       demo_synth_channel_destroy,
+       demo_synth_channel_open,
+       demo_synth_channel_close,
+       demo_synth_channel_request_process
+};
+
+/** Declaration of synthesizer audio stream methods */
+static apt_bool_t demo_synth_stream_destroy(mpf_audio_stream_t *stream);
+static apt_bool_t demo_synth_stream_open(mpf_audio_stream_t *stream);
+static apt_bool_t demo_synth_stream_close(mpf_audio_stream_t *stream);
+static apt_bool_t demo_synth_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *frame);
+
+static const mpf_audio_stream_vtable_t audio_stream_vtable = {
+       demo_synth_stream_destroy,
+       demo_synth_stream_open,
+       demo_synth_stream_close,
+       demo_synth_stream_read,
+       NULL,
+       NULL,
+       NULL
+};
+
+/** Declaration of demo synthesizer engine */
+struct demo_synth_engine_t {
+       apt_consumer_task_t    *task;
+};
+
+/** Declaration of demo synthesizer channel */
+struct demo_synth_channel_t {
+       /** Back pointer to engine */
+       demo_synth_engine_t   *demo_engine;
+       /** Engine channel base */
+       mrcp_engine_channel_t *channel;
+
+       /** Active (in-progress) speak request */
+       mrcp_message_t        *speak_request;
+       /** Pending stop response */
+       mrcp_message_t        *stop_response;
+       /** Estimated time to complete */
+       apr_size_t             time_to_complete;
+       /** Is paused */
+       apt_bool_t             paused;
+       /** Speech source (used instead of actual synthesizing) */
+       FILE                  *audio_file;
+};
+
+typedef enum {
+       DEMO_SYNTH_MSG_OPEN_CHANNEL,
+       DEMO_SYNTH_MSG_CLOSE_CHANNEL,
+       DEMO_SYNTH_MSG_REQUEST_PROCESS
+} demo_synth_msg_type_e;
+
+/** Declaration of demo synthesizer task message */
+struct demo_synth_msg_t {
+       demo_synth_msg_type_e  type;
+       mrcp_engine_channel_t *channel; 
+       mrcp_message_t        *request;
+};
+
+
+#define DEMO_SPEECH_SOURCE_FILE "demo.pcm"
+static apt_bool_t demo_synth_msg_signal(demo_synth_msg_type_e type, mrcp_engine_channel_t *channel, mrcp_message_t *request);
+static apt_bool_t demo_synth_msg_process(apt_task_t *task, apt_task_msg_t *msg);
+
+/** Declare this macro to use log routine of the server, plugin is loaded from */
+MRCP_PLUGIN_LOGGER_IMPLEMENT
+
+/** Create demo synthesizer engine */
+MRCP_PLUGIN_DECLARE(mrcp_resource_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
+{
+       /* create demo engine */
+       demo_synth_engine_t *demo_engine = apr_palloc(pool,sizeof(demo_synth_engine_t));
+       apt_task_t *task;
+       apt_task_vtable_t *vtable;
+       apt_task_msg_pool_t *msg_pool;
+
+       /* create task/thread to run demo engine in the context of this task */
+       msg_pool = apt_task_msg_pool_create_dynamic(sizeof(demo_synth_msg_t),pool);
+       demo_engine->task = apt_consumer_task_create(demo_engine,msg_pool,pool);
+       if(!demo_engine->task) {
+               return NULL;
+       }
+       task = apt_consumer_task_base_get(demo_engine->task);
+       apt_task_name_set(task,SYNTH_ENGINE_TASK_NAME);
+       vtable = apt_task_vtable_get(task);
+       if(vtable) {
+               vtable->process_msg = demo_synth_msg_process;
+       }
+
+       /* create resource engine base */
+       return mrcp_resource_engine_create(
+                                       MRCP_SYNTHESIZER_RESOURCE, /* MRCP resource identifier */
+                                       demo_engine,               /* object to associate */
+                                       &engine_vtable,            /* virtual methods table of resource engine */
+                                       pool);                     /* pool to allocate memory from */
+}
+
+/** Destroy synthesizer engine */
+static apt_bool_t demo_synth_engine_destroy(mrcp_resource_engine_t *engine)
+{
+       demo_synth_engine_t *demo_engine = engine->obj;
+       if(demo_engine->task) {
+               apt_task_t *task = apt_consumer_task_base_get(demo_engine->task);
+               apt_task_destroy(task);
+               demo_engine->task = NULL;
+       }
+       return TRUE;
+}
+
+/** Open synthesizer engine */
+static apt_bool_t demo_synth_engine_open(mrcp_resource_engine_t *engine)
+{
+       demo_synth_engine_t *demo_engine = engine->obj;
+       if(demo_engine->task) {
+               apt_task_t *task = apt_consumer_task_base_get(demo_engine->task);
+               apt_task_start(task);
+       }
+       return TRUE;
+}
+
+/** Close synthesizer engine */
+static apt_bool_t demo_synth_engine_close(mrcp_resource_engine_t *engine)
+{
+       demo_synth_engine_t *demo_engine = engine->obj;
+       if(demo_engine->task) {
+               apt_task_t *task = apt_consumer_task_base_get(demo_engine->task);
+               apt_task_terminate(task,TRUE);
+       }
+       return TRUE;
+}
+
+/** Create demo synthesizer channel derived from engine channel base */
+static mrcp_engine_channel_t* demo_synth_engine_channel_create(mrcp_resource_engine_t *engine, apr_pool_t *pool)
+{
+       /* create demo synth channel */
+       demo_synth_channel_t *synth_channel = apr_palloc(pool,sizeof(demo_synth_channel_t));
+       synth_channel->demo_engine = engine->obj;
+       synth_channel->speak_request = NULL;
+       synth_channel->stop_response = NULL;
+       synth_channel->time_to_complete = 0;
+       synth_channel->paused = FALSE;
+       synth_channel->audio_file = NULL;
+       /* create engine channel base */
+       synth_channel->channel = mrcp_engine_source_channel_create(
+                       engine,               /* resource engine */
+                       &channel_vtable,      /* virtual methods table of engine channel */
+                       &audio_stream_vtable, /* virtual methods table of audio stream */
+                       synth_channel,        /* object to associate */
+                       NULL,                 /* codec descriptor might be NULL by default */
+                       pool);                /* pool to allocate memory from */
+       return synth_channel->channel;
+}
+
+/** Destroy engine channel */
+static apt_bool_t demo_synth_channel_destroy(mrcp_engine_channel_t *channel)
+{
+       /* nothing to destroy */
+       return TRUE;
+}
+
+/** Open engine channel (asynchronous response MUST be sent)*/
+static apt_bool_t demo_synth_channel_open(mrcp_engine_channel_t *channel)
+{
+       return demo_synth_msg_signal(DEMO_SYNTH_MSG_OPEN_CHANNEL,channel,NULL);
+}
+
+/** Close engine channel (asynchronous response MUST be sent)*/
+static apt_bool_t demo_synth_channel_close(mrcp_engine_channel_t *channel)
+{
+       return demo_synth_msg_signal(DEMO_SYNTH_MSG_CLOSE_CHANNEL,channel,NULL);
+}
+
+/** Process MRCP channel request (asynchronous response MUST be sent)*/
+static apt_bool_t demo_synth_channel_request_process(mrcp_engine_channel_t *channel, mrcp_message_t *request)
+{
+       return demo_synth_msg_signal(DEMO_SYNTH_MSG_REQUEST_PROCESS,channel,request);
+}
+
+/** Process SPEAK request */
+static apt_bool_t demo_synth_channel_speak(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response)
+{
+       char *file_path = NULL;
+       demo_synth_channel_t *synth_channel = channel->method_obj;
+       synth_channel->time_to_complete = 0;
+       if(channel->engine) {
+               file_path = apt_datadir_filepath_get(channel->engine->dir_layout,DEMO_SPEECH_SOURCE_FILE,channel->pool);
+       }
+       if(file_path) {
+               synth_channel->audio_file = fopen(file_path,"rb");
+               if(synth_channel->audio_file) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set [%s] as Speech Source",file_path);
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"No Speech Source [%s] Found",file_path);
+                       /* calculate estimated time to complete */
+                       if(mrcp_generic_header_property_check(request,GENERIC_HEADER_CONTENT_LENGTH) == TRUE) {
+                               mrcp_generic_header_t *generic_header = mrcp_generic_header_get(request);
+                               if(generic_header) {
+                                       synth_channel->time_to_complete = generic_header->content_length * 10; /* 10 msec per character */
+                               }
+                       }
+               }
+       }
+       
+       response->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS;
+       /* send asynchronous response */
+       mrcp_engine_channel_message_send(channel,response);
+       synth_channel->speak_request = request;
+       return TRUE;
+}
+
+/** Process STOP request */
+static apt_bool_t demo_synth_channel_stop(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response)
+{
+       demo_synth_channel_t *synth_channel = channel->method_obj;
+       /* store the request, make sure there is no more activity and only then send the response */
+       synth_channel->stop_response = response;
+       return TRUE;
+}
+
+/** Process PAUSE request */
+static apt_bool_t demo_synth_channel_pause(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response)
+{
+       demo_synth_channel_t *synth_channel = channel->method_obj;
+       synth_channel->paused = TRUE;
+       /* send asynchronous response */
+       mrcp_engine_channel_message_send(channel,response);
+       return TRUE;
+}
+
+/** Process RESUME request */
+static apt_bool_t demo_synth_channel_resume(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response)
+{
+       demo_synth_channel_t *synth_channel = channel->method_obj;
+       synth_channel->paused = FALSE;
+       /* send asynchronous response */
+       mrcp_engine_channel_message_send(channel,response);
+       return TRUE;
+}
+
+/** Process SET-PARAMS request */
+static apt_bool_t demo_synth_channel_set_params(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response)
+{
+       mrcp_synth_header_t *req_synth_header;
+       /* get synthesizer header */
+       req_synth_header = mrcp_resource_header_get(request);
+       if(req_synth_header) {
+               /* check voice age header */
+               if(mrcp_resource_header_property_check(request,SYNTHESIZER_HEADER_VOICE_AGE) == TRUE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set Voice Age [%d]",req_synth_header->voice_param.age);
+               }
+               /* check voice name header */
+               if(mrcp_resource_header_property_check(request,SYNTHESIZER_HEADER_VOICE_NAME) == TRUE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set Voice Name [%s]",req_synth_header->voice_param.name);
+               }
+       }
+       
+       /* send asynchronous response */
+       mrcp_engine_channel_message_send(channel,response);
+       return TRUE;
+}
+
+/** Process GET-PARAMS request */
+static apt_bool_t demo_synth_channel_get_params(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response)
+{
+       mrcp_synth_header_t *req_synth_header;
+       /* get synthesizer header */
+       req_synth_header = mrcp_resource_header_get(request);
+       if(req_synth_header) {
+               mrcp_synth_header_t *res_synth_header = mrcp_resource_header_prepare(response);
+               /* check voice age header */
+               if(mrcp_resource_header_property_check(request,SYNTHESIZER_HEADER_VOICE_AGE) == TRUE) {
+                       res_synth_header->voice_param.age = 25;
+                       mrcp_resource_header_property_add(response,SYNTHESIZER_HEADER_VOICE_AGE);
+               }
+               /* check voice name header */
+               if(mrcp_resource_header_property_check(request,SYNTHESIZER_HEADER_VOICE_NAME) == TRUE) {
+                       apt_string_set(&res_synth_header->voice_param.name,"David");
+                       mrcp_resource_header_property_add(response,SYNTHESIZER_HEADER_VOICE_NAME);
+               }
+       }
+
+       /* send asynchronous response */
+       mrcp_engine_channel_message_send(channel,response);
+       return TRUE;
+}
+
+/** Dispatch MRCP request */
+static apt_bool_t demo_synth_channel_request_dispatch(mrcp_engine_channel_t *channel, mrcp_message_t *request)
+{
+       apt_bool_t processed = FALSE;
+       mrcp_message_t *response = mrcp_response_create(request,request->pool);
+       switch(request->start_line.method_id) {
+               case SYNTHESIZER_SET_PARAMS:
+                       processed = demo_synth_channel_set_params(channel,request,response);
+                       break;
+               case SYNTHESIZER_GET_PARAMS:
+                       processed = demo_synth_channel_get_params(channel,request,response);
+                       break;
+               case SYNTHESIZER_SPEAK:
+                       processed = demo_synth_channel_speak(channel,request,response);
+                       break;
+               case SYNTHESIZER_STOP:
+                       processed = demo_synth_channel_stop(channel,request,response);
+                       break;
+               case SYNTHESIZER_PAUSE:
+                       processed = demo_synth_channel_pause(channel,request,response);
+                       break;
+               case SYNTHESIZER_RESUME:
+                       processed = demo_synth_channel_resume(channel,request,response);
+                       break;
+               case SYNTHESIZER_BARGE_IN_OCCURRED:
+                       processed = demo_synth_channel_stop(channel,request,response);
+                       break;
+               case SYNTHESIZER_CONTROL:
+                       break;
+               case SYNTHESIZER_DEFINE_LEXICON:
+                       break;
+               default:
+                       break;
+       }
+       if(processed == FALSE) {
+               /* send asynchronous response for not handled request */
+               mrcp_engine_channel_message_send(channel,response);
+       }
+       return TRUE;
+}
+
+/** Callback is called from MPF engine context to destroy any additional data associated with audio stream */
+static apt_bool_t demo_synth_stream_destroy(mpf_audio_stream_t *stream)
+{
+       return TRUE;
+}
+
+/** Callback is called from MPF engine context to perform any action before open */
+static apt_bool_t demo_synth_stream_open(mpf_audio_stream_t *stream)
+{
+       return TRUE;
+}
+
+/** Callback is called from MPF engine context to perform any action after close */
+static apt_bool_t demo_synth_stream_close(mpf_audio_stream_t *stream)
+{
+       return TRUE;
+}
+
+/** Callback is called from MPF engine context to read/get new frame */
+static apt_bool_t demo_synth_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *frame)
+{
+       demo_synth_channel_t *synth_channel = stream->obj;
+       /* check if STOP was requested */
+       if(synth_channel->stop_response) {
+               /* send asynchronous response to STOP request */
+               mrcp_engine_channel_message_send(synth_channel->channel,synth_channel->stop_response);
+               synth_channel->stop_response = NULL;
+               synth_channel->speak_request = NULL;
+               synth_channel->paused = FALSE;
+               if(synth_channel->audio_file) {
+                       fclose(synth_channel->audio_file);
+                       synth_channel->audio_file = NULL;
+               }
+               return TRUE;
+       }
+
+       /* check if there is active SPEAK request and it isn't in paused state */
+       if(synth_channel->speak_request && synth_channel->paused == FALSE) {
+               /* normal processing */
+               apt_bool_t completed = FALSE;
+               if(synth_channel->audio_file) {
+                       /* read speech from file */
+                       apr_size_t size = frame->codec_frame.size;
+                       if(fread(frame->codec_frame.buffer,1,size,synth_channel->audio_file) == size) {
+                               frame->type |= MEDIA_FRAME_TYPE_AUDIO;
+                       }
+                       else {
+                               completed = TRUE;
+                       }
+               }
+               else {
+                       /* fill with silence in case no file available */
+                       if(synth_channel->time_to_complete >= CODEC_FRAME_TIME_BASE) {
+                               memset(frame->codec_frame.buffer,0,frame->codec_frame.size);
+                               frame->type |= MEDIA_FRAME_TYPE_AUDIO;
+                               synth_channel->time_to_complete -= CODEC_FRAME_TIME_BASE;
+                       }
+                       else {
+                               completed = TRUE;
+                       }
+               }
+               
+               if(completed) {
+                       /* raise SPEAK-COMPLETE event */
+                       mrcp_message_t *message = mrcp_event_create(
+                                                               synth_channel->speak_request,
+                                                               SYNTHESIZER_SPEAK_COMPLETE,
+                                                               synth_channel->speak_request->pool);
+                       if(message) {
+                               /* get/allocate synthesizer header */
+                               mrcp_synth_header_t *synth_header = mrcp_resource_header_prepare(message);
+                               if(synth_header) {
+                                       /* set completion cause */
+                                       synth_header->completion_cause = SYNTHESIZER_COMPLETION_CAUSE_NORMAL;
+                                       mrcp_resource_header_property_add(message,SYNTHESIZER_HEADER_COMPLETION_CAUSE);
+                               }
+                               /* set request state */
+                               message->start_line.request_state = MRCP_REQUEST_STATE_COMPLETE;
+
+                               synth_channel->speak_request = NULL;
+                               if(synth_channel->audio_file) {
+                                       fclose(synth_channel->audio_file);
+                                       synth_channel->audio_file = NULL;
+                               }
+                               /* send asynch event */
+                               mrcp_engine_channel_message_send(synth_channel->channel,message);
+                       }
+               }
+       }
+       return TRUE;
+}
+
+static apt_bool_t demo_synth_msg_signal(demo_synth_msg_type_e type, mrcp_engine_channel_t *channel, mrcp_message_t *request)
+{
+       apt_bool_t status = FALSE;
+       demo_synth_channel_t *demo_channel = channel->method_obj;
+       demo_synth_engine_t *demo_engine = demo_channel->demo_engine;
+       apt_task_t *task = apt_consumer_task_base_get(demo_engine->task);
+       apt_task_msg_t *msg = apt_task_msg_get(task);
+       if(msg) {
+               demo_synth_msg_t *demo_msg;
+               msg->type = TASK_MSG_USER;
+               demo_msg = (demo_synth_msg_t*) msg->data;
+
+               demo_msg->type = type;
+               demo_msg->channel = channel;
+               demo_msg->request = request;
+               status = apt_task_msg_signal(task,msg);
+       }
+       return status;
+}
+
+static apt_bool_t demo_synth_msg_process(apt_task_t *task, apt_task_msg_t *msg)
+{
+       demo_synth_msg_t *demo_msg = (demo_synth_msg_t*)msg->data;
+       switch(demo_msg->type) {
+               case DEMO_SYNTH_MSG_OPEN_CHANNEL:
+                       /* open channel and send asynch response */
+                       mrcp_engine_channel_open_respond(demo_msg->channel,TRUE);
+                       break;
+               case DEMO_SYNTH_MSG_CLOSE_CHANNEL:
+                       /* close channel, make sure there is no activity and send asynch response */
+                       mrcp_engine_channel_close_respond(demo_msg->channel);
+                       break;
+               case DEMO_SYNTH_MSG_REQUEST_PROCESS:
+                       demo_synth_channel_request_dispatch(demo_msg->channel,demo_msg->request);
+                       break;
+               default:
+                       break;
+       }
+       return TRUE;
+}
diff --git a/libs/unimrcp/plugins/mrcp-cepstral/Makefile.am b/libs/unimrcp/plugins/mrcp-cepstral/Makefile.am
new file mode 100644 (file)
index 0000000..38b9bab
--- /dev/null
@@ -0,0 +1,17 @@
+MAINTAINERCLEANFILES      = Makefile.in
+
+INCLUDES                   = -Iinclude \
+                             -I$(top_srcdir)/libs/mrcp-engine/include \
+                             -I$(top_srcdir)/libs/mrcp/include \
+                             -I$(top_srcdir)/libs/mrcp/message/include \
+                             -I$(top_srcdir)/libs/mrcp/control/include \
+                             -I$(top_srcdir)/libs/mrcp/resources/include \
+                             -I$(top_srcdir)/libs/mpf/include \
+                             -I$(top_srcdir)/libs/apr-toolkit/include \
+                             $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES) $(UNIMRCP_SWIFT_INCLUDES)
+
+plugin_LTLIBRARIES         = mrcpcepstral.la
+
+mrcpcepstral_la_SOURCES    = src/mrcp_swift.c
+mrcpcepstral_la_LDFLAGS    = -module $(PLUGIN_LT_VERSION) $(UNIMRCP_SWIFT_LDFLAGS)
+mrcpcepstral_la_LIBADD     = $(UNIMRCP_SWIFT_LIBS) 
diff --git a/libs/unimrcp/plugins/mrcp-cepstral/mrcpcepstral.vcproj b/libs/unimrcp/plugins/mrcp-cepstral/mrcpcepstral.vcproj
new file mode 100644 (file)
index 0000000..d496f42
--- /dev/null
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="mrcpcepstral"
+       ProjectGUID="{729EF28E-38C9-40DE-A138-87785F021411}"
+       RootNamespace="mrcpcepstral"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="2"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\unimrcpplugin.vsprops;$(SolutionDir)build\vsprops\cepstral.vsprops"
+                       CharacterSet="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="include"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="2"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\unimrcpplugin.vsprops;$(SolutionDir)build\vsprops\cepstral.vsprops"
+                       CharacterSet="1"
+                       WholeProgramOptimization="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="include"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+               </Filter>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       >
+                       <File
+                               RelativePath=".\src\mrcp_swift.c"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/plugins/mrcp-cepstral/src/mrcp_swift.c b/libs/unimrcp/plugins/mrcp-cepstral/src/mrcp_swift.c
new file mode 100644 (file)
index 0000000..51558fd
--- /dev/null
@@ -0,0 +1,701 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* 
+ * Some mandatory rules concerning plugin implementation.
+ * 1. Each plugin MUST contain the following function as an entry point of the plugin
+ *        MRCP_PLUGIN_DECLARE(mrcp_resource_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
+ * 2. One and only one response MUST be sent back to the received request.
+ * 3. Methods (callbacks) of the MRCP engine channel MUST not block.
+ *   (asynch response can be sent from the context of other thread)
+ * 4. Methods (callbacks) of the MPF engine stream MUST not block.
+ */
+
+#include <swift.h>
+#include "mrcp_resource_engine.h"
+#include "mrcp_synth_resource.h"
+#include "mrcp_synth_header.h"
+#include "mrcp_generic_header.h"
+#include "mrcp_message.h"
+#include "mpf_buffer.h"
+#include "apt_log.h"
+
+/** Declaration of synthesizer engine methods */
+static apt_bool_t mrcp_swift_engine_destroy(mrcp_resource_engine_t *engine);
+static apt_bool_t mrcp_swift_engine_open(mrcp_resource_engine_t *engine);
+static apt_bool_t mrcp_swift_engine_close(mrcp_resource_engine_t *engine);
+static mrcp_engine_channel_t* mrcp_swift_engine_channel_create(mrcp_resource_engine_t *engine, apr_pool_t *pool);
+
+static const struct mrcp_engine_method_vtable_t engine_vtable = {
+       mrcp_swift_engine_destroy,
+       mrcp_swift_engine_open,
+       mrcp_swift_engine_close,
+       mrcp_swift_engine_channel_create
+};
+
+
+/** Declaration of synthesizer channel methods */
+static apt_bool_t mrcp_swift_channel_destroy(mrcp_engine_channel_t *channel);
+static apt_bool_t mrcp_swift_channel_open(mrcp_engine_channel_t *channel);
+static apt_bool_t mrcp_swift_channel_close(mrcp_engine_channel_t *channel);
+static apt_bool_t mrcp_swift_channel_request_process(mrcp_engine_channel_t *channel, mrcp_message_t *request);
+
+static const struct mrcp_engine_channel_method_vtable_t channel_vtable = {
+       mrcp_swift_channel_destroy,
+       mrcp_swift_channel_open,
+       mrcp_swift_channel_close,
+       mrcp_swift_channel_request_process
+};
+
+/** Declaration of synthesizer audio stream methods */
+static apt_bool_t synth_stream_destroy(mpf_audio_stream_t *stream);
+static apt_bool_t synth_stream_open(mpf_audio_stream_t *stream);
+static apt_bool_t synth_stream_close(mpf_audio_stream_t *stream);
+static apt_bool_t synth_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *frame);
+
+static const mpf_audio_stream_vtable_t audio_stream_vtable = {
+       synth_stream_destroy,
+       synth_stream_open,
+       synth_stream_close,
+       synth_stream_read,
+       NULL,
+       NULL,
+       NULL
+};
+
+typedef struct mrcp_swift_channel_t mrcp_swift_channel_t;
+/** Declaration of Swift synthesizer channel */
+struct mrcp_swift_channel_t {
+       /** Swift port */
+       swift_port            *port;
+       swift_background_t     tts_stream;
+
+       /** Audio buffer */
+       mpf_buffer_t          *audio_buffer;
+
+       /** Engine channel base */
+       mrcp_engine_channel_t *channel;
+
+       /** Active (in-progress) speak request */
+       mrcp_message_t        *speak_request;
+       /** Pending stop response */
+       mrcp_message_t        *stop_response;
+       /** Is paused */
+       apt_bool_t             paused;
+};
+
+/** Table of prosody volumes for Swift engine */
+static const int swift_prosody_volume_table[PROSODY_VOLUME_COUNT] = {
+       25,  /* PROSODY_VOLUME_SILENT */
+       50,  /* PROSODY_VOLUME_XSOFT */
+       75,  /* PROSODY_VOLUME_SOFT */
+       100, /* PROSODY_VOLUME_MEDIUM */
+       125, /* PROSODY_VOLUME_LOUD */
+       150, /* PROSODY_VOLUME_XLOUD */
+       100  /* PROSODY_VOLUME_DEFAULT */
+};
+
+/** Table of prosody rates for Swift engine */
+static const int swift_prosody_rate_table[PROSODY_RATE_COUNT] = {
+       85,  /* PROSODY_RATE_XSLOW */
+       113, /* PROSODY_RATE_SLOW */
+       170, /* PROSODY_RATE_MEDIUM */
+       225, /* PROSODY_RATE_FAST */
+       340, /* PROSODY_RATE_XFAST */
+       170  /* PROSODY_RATE_DEFAULT */
+};
+
+static apr_table_t *swift_speech_language_table;
+
+static apr_table_t* mrcp_swift_language_table_create(apr_pool_t *pool);
+static void mrcp_swift_voices_show(swift_engine *engine);
+static swift_result_t mrcp_swift_write_audio(swift_event *event, swift_event_t type, void *udata);
+static apt_bool_t mrcp_swift_channel_voice_set(mrcp_swift_channel_t *synth_channel, mrcp_message_t *message);
+static apt_bool_t mrcp_swift_channel_params_set(mrcp_swift_channel_t *synth_channel, mrcp_message_t *message);
+
+/** Declare this macro to use log routine of the server, plugin is loaded from */
+MRCP_PLUGIN_LOGGER_IMPLEMENT
+
+/** Create Swift synthesizer engine */
+MRCP_PLUGIN_DECLARE(mrcp_resource_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
+{
+       swift_engine *synth_engine;
+       mrcp_resource_engine_t *engine;
+       /* open swift engine */
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open Swift Engine [%s]",swift_version);
+       if((synth_engine = swift_engine_open(NULL)) ==  NULL) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Open Swift Engine");
+               return NULL;
+       }
+       swift_speech_language_table = mrcp_swift_language_table_create(pool);
+       mrcp_swift_voices_show(synth_engine);
+
+       /* create resource engine base */
+       engine = mrcp_resource_engine_create(
+                                       MRCP_SYNTHESIZER_RESOURCE, /* MRCP resource identifier */
+                                       synth_engine,              /* object to associate */
+                                       &engine_vtable,            /* virtual methods table of resource engine */
+                                       pool);                     /* pool to allocate memory from */
+       if(!engine) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Resource Engine");
+               swift_engine_close(synth_engine);
+       }
+       return engine;
+}
+
+/** Destroy synthesizer engine */
+static apt_bool_t mrcp_swift_engine_destroy(mrcp_resource_engine_t *engine)
+{
+       swift_engine *synth_engine = engine->obj;
+       /* close swift engine */
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close Swift Engine");
+       if(synth_engine) {
+               swift_engine_close(synth_engine);
+               engine->obj = NULL;
+       }
+       return TRUE;
+}
+
+/** Open synthesizer engine */
+static apt_bool_t mrcp_swift_engine_open(mrcp_resource_engine_t *engine)
+{
+       return TRUE;
+}
+
+/** Close synthesizer engine */
+static apt_bool_t mrcp_swift_engine_close(mrcp_resource_engine_t *engine)
+{
+       return TRUE;
+}
+
+/** Create demo synthesizer channel derived from engine channel base */
+static mrcp_engine_channel_t* mrcp_swift_engine_channel_create(mrcp_resource_engine_t *engine, apr_pool_t *pool)
+{
+       swift_engine *synth_engine = engine->obj;
+       mrcp_swift_channel_t *synth_channel;
+       mrcp_engine_channel_t *channel;
+       swift_params *params;
+       swift_port *port;
+       mpf_codec_descriptor_t *codec_descriptor;
+
+       codec_descriptor = apr_palloc(pool,sizeof(mpf_codec_descriptor_t));
+       mpf_codec_descriptor_init(codec_descriptor);
+       codec_descriptor->channel_count = 1;
+       codec_descriptor->payload_type = 96;
+       apt_string_set(&codec_descriptor->name,"L16");
+       codec_descriptor->sampling_rate = 8000;
+
+       params = swift_params_new(NULL);
+       swift_params_set_string(params, "audio/encoding", "pcm16");
+       swift_params_set_int(params, "audio/sampling-rate", codec_descriptor->sampling_rate);
+       /* open swift port */ 
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open Swift Port");
+       if((port = swift_port_open(synth_engine,params)) == NULL) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Open Swift Port");
+               return NULL;
+       }
+
+       /* create swift synth channel */
+       synth_channel = apr_palloc(pool,sizeof(mrcp_swift_channel_t));
+       synth_channel->speak_request = NULL;
+       synth_channel->stop_response = NULL;
+       synth_channel->paused = FALSE;
+       synth_channel->channel = NULL;
+       synth_channel->port = port;
+       synth_channel->tts_stream = 0;
+       /* create engine channel base */
+       channel = mrcp_engine_source_channel_create(
+                       engine,               /* resource engine */
+                       &channel_vtable,      /* virtual methods table of engine channel */
+                       &audio_stream_vtable, /* virtual methods table of audio stream */
+                       synth_channel,        /* object to associate */
+                       codec_descriptor,     /* codec descriptor might be NULL by default */
+                       pool);                /* pool to allocate memory from */
+
+       if(!channel) {
+               swift_port_close(port);
+               synth_channel->port = NULL;
+               return NULL;
+       }
+
+       synth_channel->audio_buffer = mpf_buffer_create(pool);
+
+       /* set swift_write_audio as a callback, with the output file as its param */
+       swift_port_set_callback(port, &mrcp_swift_write_audio, SWIFT_EVENT_AUDIO | SWIFT_EVENT_END, synth_channel);
+       synth_channel->channel = channel;
+       return channel;
+}
+
+/** Destroy engine channel */
+static apt_bool_t mrcp_swift_channel_destroy(mrcp_engine_channel_t *channel)
+{
+       mrcp_swift_channel_t *synth_channel = channel->method_obj;
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close Swift Port");
+       if(synth_channel->port) {
+               /* close swift port */ 
+               swift_port_close(synth_channel->port);
+               synth_channel->port = NULL;
+       }
+       return TRUE;
+}
+
+/** Open engine channel (asynchronous response MUST be sent)*/
+static apt_bool_t mrcp_swift_channel_open(mrcp_engine_channel_t *channel)
+{
+       /* open channel and send asynch response */
+       return mrcp_engine_channel_open_respond(channel,TRUE);
+}
+
+/** Close engine channel (asynchronous response MUST be sent)*/
+static apt_bool_t mrcp_swift_channel_close(mrcp_engine_channel_t *channel)
+{
+       /* close channel, make sure there is no activity and send asynch response */
+       return mrcp_engine_channel_close_respond(channel);
+}
+
+/** Process SPEAK request */
+static apt_bool_t mrcp_swift_channel_speak(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response)
+{
+       mrcp_swift_channel_t *synth_channel = channel->method_obj;
+
+       /* set voice */
+       mrcp_swift_channel_voice_set(synth_channel,request);
+       /* set params */
+       mrcp_swift_channel_params_set(synth_channel,request);
+       /* (re)start audio buffer */
+       mpf_buffer_restart(synth_channel->audio_buffer);
+       response->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS;
+       /* start to synthesize */
+       if(swift_port_speak_text(synth_channel->port,request->body.buf,0,NULL,&synth_channel->tts_stream,NULL) != SWIFT_SUCCESS) {
+               response->start_line.request_state = MRCP_REQUEST_STATE_COMPLETE;
+               response->start_line.status_code = MRCP_STATUS_CODE_METHOD_FAILED;
+       }
+       /* send asynchronous response */
+       mrcp_engine_channel_message_send(channel,response);
+       synth_channel->speak_request = request;
+       return TRUE;
+}
+
+/** Process STOP request */
+static apt_bool_t mrcp_swift_channel_stop(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response)
+{
+       mrcp_swift_channel_t *synth_channel = channel->method_obj;
+       /* store the request, make sure there is no more activity and only then send the response */
+       swift_port_stop(synth_channel->port,synth_channel->tts_stream,SWIFT_EVENT_NOW);
+       synth_channel->stop_response = response;
+       return TRUE;
+}
+
+/** Process PAUSE request */
+static apt_bool_t mrcp_swift_channel_pause(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response)
+{
+       mrcp_swift_channel_t *synth_channel = channel->method_obj;
+       synth_channel->paused = TRUE;
+       /* send asynchronous response */
+       mrcp_engine_channel_message_send(channel,response);
+       return TRUE;
+}
+
+/** Process RESUME request */
+static apt_bool_t mrcp_swift_channel_resume(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response)
+{
+       mrcp_swift_channel_t *synth_channel = channel->method_obj;
+       synth_channel->paused = FALSE;
+       /* send asynchronous response */
+       mrcp_engine_channel_message_send(channel,response);
+       return TRUE;
+}
+
+/** Process CONTROL request */
+static apt_bool_t mrcp_swift_channel_control(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response)
+{
+       mrcp_swift_channel_t *synth_channel = channel->method_obj;
+       /* set params */
+       mrcp_swift_channel_params_set(synth_channel,request);
+       /* send asynchronous response */
+       mrcp_engine_channel_message_send(channel,response);
+       return TRUE;
+}
+
+/** Process MRCP channel request (asynchronous response MUST be sent)*/
+static apt_bool_t mrcp_swift_channel_request_process(mrcp_engine_channel_t *channel, mrcp_message_t *request)
+{
+       apt_bool_t processed = FALSE;
+       mrcp_message_t *response = mrcp_response_create(request,request->pool);
+       switch(request->start_line.method_id) {
+               case SYNTHESIZER_SET_PARAMS:
+                       break;
+               case SYNTHESIZER_GET_PARAMS:
+                       break;
+               case SYNTHESIZER_SPEAK:
+                       processed = mrcp_swift_channel_speak(channel,request,response);
+                       break;
+               case SYNTHESIZER_STOP:
+                       processed = mrcp_swift_channel_stop(channel,request,response);
+                       break;
+               case SYNTHESIZER_PAUSE:
+                       processed = mrcp_swift_channel_pause(channel,request,response);
+                       break;
+               case SYNTHESIZER_RESUME:
+                       processed = mrcp_swift_channel_resume(channel,request,response);
+                       break;
+               case SYNTHESIZER_BARGE_IN_OCCURRED:
+                       processed = mrcp_swift_channel_stop(channel,request,response);
+                       break;
+               case SYNTHESIZER_CONTROL:
+                       processed = mrcp_swift_channel_control(channel,request,response);
+                       break;
+               case SYNTHESIZER_DEFINE_LEXICON:
+                       break;
+               default:
+                       break;
+       }
+       if(processed == FALSE) {
+               /* send asynchronous response for not handled request */
+               mrcp_engine_channel_message_send(channel,response);
+       }
+       return TRUE;
+}
+
+
+
+/** Callback is called from MPF engine context to destroy any additional data associated with audio stream */
+static apt_bool_t synth_stream_destroy(mpf_audio_stream_t *stream)
+{
+       return TRUE;
+}
+
+/** Callback is called from MPF engine context to perform any action before open */
+static apt_bool_t synth_stream_open(mpf_audio_stream_t *stream)
+{
+       return TRUE;
+}
+
+/** Callback is called from MPF engine context to perform any action after close */
+static apt_bool_t synth_stream_close(mpf_audio_stream_t *stream)
+{
+       return TRUE;
+}
+
+/** Raise SPEAK-COMPLETE event */
+static apt_bool_t synth_speak_complete_raise(mrcp_swift_channel_t *synth_channel)
+{
+       mrcp_message_t *message;
+       mrcp_synth_header_t *synth_header;
+       if(!synth_channel->speak_request) {
+               return FALSE;
+       }
+       message = mrcp_event_create(
+                                               synth_channel->speak_request,
+                                               SYNTHESIZER_SPEAK_COMPLETE,
+                                               synth_channel->speak_request->pool);
+       if(!message) {
+               return FALSE;
+       }
+       
+       /* get/allocate synthesizer header */
+       synth_header = mrcp_resource_header_prepare(message);
+       if(synth_header) {
+               /* set completion cause */
+               synth_header->completion_cause = SYNTHESIZER_COMPLETION_CAUSE_NORMAL;
+               mrcp_resource_header_property_add(message,SYNTHESIZER_HEADER_COMPLETION_CAUSE);
+       }
+       /* set request state */
+       message->start_line.request_state = MRCP_REQUEST_STATE_COMPLETE;
+
+       synth_channel->speak_request = NULL;
+       /* send asynch event */
+       return mrcp_engine_channel_message_send(synth_channel->channel,message);
+}
+
+/** Callback is called from MPF engine context to read/get new frame */
+static apt_bool_t synth_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *frame)
+{
+       mrcp_swift_channel_t *synth_channel = stream->obj;
+       /* check if STOP was requested */
+       if(synth_channel->stop_response) {
+               /* send asynchronous response to STOP request */
+               mrcp_engine_channel_message_send(synth_channel->channel,synth_channel->stop_response);
+               synth_channel->stop_response = NULL;
+               synth_channel->speak_request = NULL;
+               synth_channel->paused = FALSE;
+               return TRUE;
+       }
+
+       /* check if there is active SPEAK request and it isn't in paused state */
+       if(synth_channel->speak_request && synth_channel->paused == FALSE) {
+               /* normal processing */
+               mpf_buffer_frame_read(synth_channel->audio_buffer,frame);
+               
+               if((frame->type & MEDIA_FRAME_TYPE_EVENT) == MEDIA_FRAME_TYPE_EVENT) {
+                       synth_speak_complete_raise(synth_channel);
+               }
+       }
+       return TRUE;
+}
+
+/** Swift engine callback */
+static swift_result_t mrcp_swift_write_audio(swift_event *event, swift_event_t type, void *udata)
+{
+       void *buf;
+       int len;
+       mrcp_swift_channel_t *synth_channel = udata;
+       swift_event_t rv = SWIFT_SUCCESS;
+
+       if(type & SWIFT_EVENT_END) {
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Swift Engine: Write End-of-Speech Event");
+               mpf_buffer_event_write(synth_channel->audio_buffer,MEDIA_FRAME_TYPE_EVENT);
+               return rv;
+       }
+
+       rv = swift_event_get_audio(event, &buf, &len);
+       if(!SWIFT_FAILED(rv)) {
+#if 0
+               /* Get the event times */
+               float time_start, time_len; 
+               swift_event_get_times(event, &time_start, &time_len);
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Swift Engine: Write Audio [%d | %0.4f | %0.4f]",len, time_start, time_len);
+#endif
+               mpf_buffer_audio_write(synth_channel->audio_buffer,buf,len);
+       }
+
+       return rv;
+}
+
+/** Add delimiter (&) to search criteria */
+static APR_INLINE int search_criteria_delimiter_add(char *search_criteria, int size, apt_bool_t initial)
+{
+       if(initial == FALSE && size >= 3) {
+               search_criteria[0] = ' ';
+               search_criteria[1] = '&';
+               search_criteria[2] = ' ';
+               return 3;
+       }
+       return 0;
+}
+
+/** Set voice matching specified criteria */
+static apt_bool_t mrcp_swift_channel_voice_set(mrcp_swift_channel_t *synth_channel, mrcp_message_t *message)
+{
+       mrcp_synth_header_t *synth_header = mrcp_resource_header_get(message);
+       char search_criteria[1024];
+       int offset = 0;
+       swift_voice *voice;
+       swift_result_t res;
+
+       if(!synth_header) {
+               /* no params to set */
+               return TRUE;
+       }
+
+       if(mrcp_resource_header_property_check(message,SYNTHESIZER_HEADER_VOICE_NAME) == TRUE) {
+               offset += search_criteria_delimiter_add(search_criteria+offset,sizeof(search_criteria)-offset,(offset == 0));
+               offset += apr_snprintf(search_criteria+offset,sizeof(search_criteria)-offset,"speaker/name=%s",synth_header->voice_param.name.buf);
+       }
+       if(mrcp_resource_header_property_check(message,SYNTHESIZER_HEADER_VOICE_GENDER) == TRUE) {
+               switch(synth_header->voice_param.gender) {
+                       case VOICE_GENDER_MALE:
+                               offset += search_criteria_delimiter_add(search_criteria+offset,sizeof(search_criteria)-offset,offset == 0);
+                               offset += apr_snprintf(search_criteria+offset,sizeof(search_criteria)-offset,"speaker/gender=male");
+                               break;
+                       case VOICE_GENDER_FEMALE:
+                               offset += search_criteria_delimiter_add(search_criteria+offset,sizeof(search_criteria)-offset,offset == 0);
+                               offset += apr_snprintf(search_criteria+offset,sizeof(search_criteria)-offset,"speaker/gender=female");
+                               break;
+                       default:
+                               break;
+               }
+       }
+       if(mrcp_resource_header_property_check(message,SYNTHESIZER_HEADER_VOICE_AGE) == TRUE) {
+               offset += search_criteria_delimiter_add(search_criteria+offset,sizeof(search_criteria)-offset,offset == 0);
+               offset += apr_snprintf(search_criteria+offset,sizeof(search_criteria)-offset,"speaker/age=%d",synth_header->voice_param.age);
+       }
+       if(mrcp_resource_header_property_check(message,SYNTHESIZER_HEADER_SPEECH_LANGUAGE) == TRUE) {
+               const char *swift_lang_name = NULL;
+               if(swift_speech_language_table) {
+                       swift_lang_name = apr_table_get(swift_speech_language_table,synth_header->speech_language.buf);
+               }
+               if(!swift_lang_name) {
+                       swift_lang_name = synth_header->speech_language.buf;
+               }
+               offset += search_criteria_delimiter_add(search_criteria+offset,sizeof(search_criteria)-offset,offset == 0);
+               offset += apr_snprintf(search_criteria+offset,sizeof(search_criteria)-offset,"language/name=%s",swift_lang_name);
+       }
+
+       if(offset > 0) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Find Voices Matching the Criteria [%s]",search_criteria);
+               if((voice = swift_port_find_first_voice(synth_channel->port,search_criteria,NULL)) == NULL) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"No Swift Voice Available Matching the Criteria [%s]",search_criteria);
+                       voice = swift_port_find_first_voice(synth_channel->port,NULL,NULL);
+               }
+               if(SWIFT_FAILED(res = swift_port_set_voice(synth_channel->port,voice)) ) {
+                       const char *error_string = swift_strerror(res);
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,error_string);
+                       return FALSE;
+               } 
+       }
+       return TRUE;
+}
+
+apt_bool_t swift_prosody_volume_get(const mrcp_prosody_volume_t *prosody_volume, int *volume)
+{
+       apt_bool_t res = FALSE;
+       if(prosody_volume->type == PROSODY_VOLUME_TYPE_LABEL) {
+               if(prosody_volume->value.label < PROSODY_VOLUME_COUNT) {
+                       *volume = swift_prosody_volume_table[prosody_volume->value.label];
+                       res = TRUE;
+               }
+       }
+       else if(prosody_volume->type == PROSODY_VOLUME_TYPE_NUMERIC) {
+               *volume = (int)prosody_volume->value.numeric;
+               res = TRUE;
+       }
+       else if(prosody_volume->type == PROSODY_VOLUME_TYPE_RELATIVE_CHANGE) {
+               int def = swift_prosody_volume_table[PROSODY_VOLUME_DEFAULT];
+               *volume = (int)(prosody_volume->value.relative * def);
+               res = TRUE;
+       }
+       return res;
+}
+
+apt_bool_t swift_prosody_rate_get(const mrcp_prosody_rate_t *prosody_rate, int *rate)
+{
+       apt_bool_t res = FALSE;
+       if(prosody_rate->type == PROSODY_RATE_TYPE_LABEL) {
+               if(prosody_rate->value.label < PROSODY_RATE_COUNT) {
+                       *rate = swift_prosody_rate_table[prosody_rate->value.label];
+                       res = TRUE;
+               }
+       }
+       else if(prosody_rate->type == PROSODY_RATE_TYPE_RELATIVE_CHANGE) {
+               int def = swift_prosody_rate_table[PROSODY_RATE_DEFAULT];
+               *rate = (int)(prosody_rate->value.relative * def);
+               res = TRUE;
+       }
+       return res;
+}
+
+
+/** Set Swift port param */
+static apt_bool_t mrcp_swift_channel_param_set(mrcp_swift_channel_t *synth_channel, const char *name, swift_val *val)
+{
+       swift_result_t res;
+       if(SWIFT_FAILED(res = swift_port_set_param(synth_channel->port,name,val,synth_channel->tts_stream)) ) {
+               const char *error_string = swift_strerror(res);
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Swift Param %s: %s",name,error_string);
+               return FALSE;
+       }
+       return TRUE;
+}
+
+/** Set Swift port params */
+static apt_bool_t mrcp_swift_channel_params_set(mrcp_swift_channel_t *synth_channel, mrcp_message_t *message)
+{
+       const char *name;
+       mrcp_synth_header_t *synth_header = mrcp_resource_header_get(message);
+       mrcp_generic_header_t *generic_header = mrcp_generic_header_get(message);
+
+       if(synth_header) {
+               if(mrcp_resource_header_property_check(message,SYNTHESIZER_HEADER_PROSODY_VOLUME) == TRUE) {
+                       int volume = 0;
+                       if(swift_prosody_volume_get(&synth_header->prosody_param.volume,&volume) == TRUE) {
+                               name = "audio/volume";
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Swift Param %s=%d",name,volume);
+                               mrcp_swift_channel_param_set(synth_channel,name,swift_val_int(volume));
+                       }
+               }
+               if(mrcp_resource_header_property_check(message,SYNTHESIZER_HEADER_PROSODY_RATE) == TRUE) {
+                       int rate = 0;
+                       if(swift_prosody_rate_get(&synth_header->prosody_param.rate,&rate) == TRUE) {
+                               name = "speech/rate";
+                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Swift Param %s=%d",name,rate);
+                               mrcp_swift_channel_param_set(synth_channel,name,swift_val_int(rate));
+                       }
+               }
+       }
+
+       if(generic_header) {
+               if(mrcp_generic_header_property_check(message,GENERIC_HEADER_CONTENT_TYPE) == TRUE) {
+                       name = "tts/content-type";
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Swift Param %s=%s",name,generic_header->content_type);
+                       mrcp_swift_channel_param_set(synth_channel,name,swift_val_string(generic_header->content_type.buf));
+               }
+               if(mrcp_generic_header_property_check(message,GENERIC_HEADER_CONTENT_ENCODING) == TRUE) {
+                       name = "tts/text-encoding";
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Swift Param %s=%s",name,generic_header->content_encoding);
+                       mrcp_swift_channel_param_set(synth_channel,name,swift_val_string(generic_header->content_encoding.buf));
+               }
+       }
+       
+       return TRUE;
+}
+
+/** Show Swift available voices */
+static void mrcp_swift_voices_show(swift_engine *engine) 
+{
+       swift_port *port;
+       swift_voice *voice;
+       const char *license_status;
+
+       /* open swift port*/
+       if((port = swift_port_open(engine, NULL)) == NULL) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Open Swift Port");
+               return;    
+       }
+
+       /* find the first voice on the system */
+       if((voice = swift_port_find_first_voice(port, NULL, NULL)) == NULL) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Swift Voice Available");
+               swift_port_close(port);
+               return;
+       }
+       /* go through all of the voices on the system and print some info about each */
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Swift Available Voices:");
+       for(; voice; voice = swift_port_find_next_voice(port)) {
+               if(swift_voice_get_attribute(voice, "license/key")) {
+                       license_status = "licensed";
+               }
+               else {
+                       license_status = "unlicensed";
+               }
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"%s: %s, age %s, %s, %sHz, %s",
+                       swift_voice_get_attribute(voice, "name"),
+                       swift_voice_get_attribute(voice, "speaker/gender"),
+                       swift_voice_get_attribute(voice, "speaker/age"),
+                       swift_voice_get_attribute(voice, "language/name"),
+                       swift_voice_get_attribute(voice, "sample-rate"),
+                       license_status);
+       }
+
+       swift_port_close(port);
+}
+
+/** Create speech language lookup table */
+static apr_table_t* mrcp_swift_language_table_create(apr_pool_t *pool)
+{
+       apr_table_t *table = apr_table_make(pool,1);
+       if(!table) {
+               return NULL;
+       }
+
+       apr_table_setn(table,"en-US","US English");
+       apr_table_setn(table,"en-UK","UK English");
+       apr_table_setn(table,"fr-CA","Canadian French");
+       apr_table_setn(table,"es-MX","Americas Spanish");
+       apr_table_setn(table,"de-DE","German");
+       apr_table_setn(table,"it-IT","Italian");
+       return table;
+}
diff --git a/libs/unimrcp/tests/Makefile.am b/libs/unimrcp/tests/Makefile.am
new file mode 100644 (file)
index 0000000..fc52c02
--- /dev/null
@@ -0,0 +1,3 @@
+MAINTAINERCLEANFILES   = Makefile.in
+
+SUBDIRS                = apttest mpftest mrcptest rtsptest strtablegen
diff --git a/libs/unimrcp/tests/apttest/Makefile.am b/libs/unimrcp/tests/apttest/Makefile.am
new file mode 100644 (file)
index 0000000..8a80cd8
--- /dev/null
@@ -0,0 +1,11 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+INCLUDES             = -I$(top_srcdir)/libs/apr-toolkit/include \
+                       $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+noinst_PROGRAMS      = apttest
+apttest_LDADD        = $(top_builddir)/libs/apr-toolkit/libaprtoolkit.la \
+                       $(UNIMRCP_APR_LIBS) $(UNIMRCP_APU_LIBS)
+apttest_SOURCES      = src/main.c \
+                       src/task_suite.c \
+                       src/consumer_task_suite.c
diff --git a/libs/unimrcp/tests/apttest/apttest.vcproj b/libs/unimrcp/tests/apttest/apttest.vcproj
new file mode 100644 (file)
index 0000000..a9e6db5
--- /dev/null
@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="windows-1251"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="apttest"\r
+       ProjectGUID="{429C907B-97D1-4B2D-9B0E-A14A5BFDAD15}"\r
+       RootNamespace="apttest"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       ConfigurationType="1"\r
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\apt.vsprops"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="aprtoolkit.lib libaprutil-1.lib libapr-1.lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       ConfigurationType="1"\r
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\apt.vsprops"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="aprtoolkit.lib libaprutil-1.lib libapr-1.lib"\r
+                               LinkTimeCodeGeneration="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="src"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\src\consumer_task_suite.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\main.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\task_suite.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="include"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/libs/unimrcp/tests/apttest/src/consumer_task_suite.c b/libs/unimrcp/tests/apttest/src/consumer_task_suite.c
new file mode 100644 (file)
index 0000000..7dc3a27
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_time.h>
+#include "apt_test_suite.h"
+#include "apt_consumer_task.h"
+#include "apt_log.h"
+
+typedef struct {
+       apr_time_t timestamp;
+       int        number;
+} sample_msg_data_t;
+
+static void task_on_start_complete(apt_task_t *task)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"On Task Start");
+}
+
+static void task_on_terminate_complete(apt_task_t *task)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"On Task Terminate");
+}
+
+static apt_bool_t task_msg_process(apt_task_t *task, apt_task_msg_t *msg)
+{
+       sample_msg_data_t *data = (sample_msg_data_t*)msg->data;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process Message [%d]",data->number);
+       return TRUE;
+}
+
+
+static apt_bool_t consumer_task_test_run(apt_test_suite_t *suite, int argc, const char * const *argv)
+{
+       apt_consumer_task_t *consumer_task;
+       apt_task_t *task;
+       apt_task_vtable_t *vtable;
+       apt_task_msg_pool_t *msg_pool;
+       apt_task_msg_t *msg;
+       sample_msg_data_t *data;
+       int i;
+       
+       msg_pool = apt_task_msg_pool_create_dynamic(sizeof(sample_msg_data_t),suite->pool);
+
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create Consumer Task");
+       consumer_task = apt_consumer_task_create(NULL,msg_pool,suite->pool);
+       if(!consumer_task) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Consumer Task");
+               return FALSE;
+       }
+       task = apt_consumer_task_base_get(consumer_task);
+       vtable = apt_task_vtable_get(task);
+       if(vtable) {
+               vtable->process_msg = task_msg_process;
+               vtable->on_start_complete = task_on_start_complete;
+               vtable->on_terminate_complete = task_on_terminate_complete;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Start Task");
+       if(apt_task_start(task) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Start Task");
+               apt_task_destroy(task);
+               return FALSE;
+       }
+
+       for(i=0; i<10; i++) {
+               msg = apt_task_msg_acquire(msg_pool);
+               msg->type = TASK_MSG_USER;
+               data = (sample_msg_data_t*) msg->data;
+
+               data->number = i;
+               data->timestamp = apr_time_now();
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Signal Message [%d]",data->number);
+               apt_task_msg_signal(task,msg);
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Terminate Task [wait till complete]");
+       apt_task_terminate(task,TRUE);
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy Task");
+       apt_task_destroy(task);
+       return TRUE;
+}
+
+apt_test_suite_t* consumer_task_test_suite_create(apr_pool_t *pool)
+{
+       apt_test_suite_t *suite = apt_test_suite_create(pool,"consumer",NULL,consumer_task_test_run);
+       return suite;
+}
diff --git a/libs/unimrcp/tests/apttest/src/main.c b/libs/unimrcp/tests/apttest/src/main.c
new file mode 100644 (file)
index 0000000..291c5fe
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apt_test_suite.h"
+#include "apt_log.h"
+
+apt_test_suite_t* task_test_suite_create(apr_pool_t *pool);
+apt_test_suite_t* consumer_task_test_suite_create(apr_pool_t *pool);
+
+int main(int argc, const char * const *argv)
+{
+       apt_test_framework_t *test_framework;
+       apt_test_suite_t *test_suite;
+       apr_pool_t *pool;
+       
+       /* one time apr global initialization */
+       if(apr_initialize() != APR_SUCCESS) {
+               return 0;
+       }
+
+       /* create test framework */
+       test_framework = apt_test_framework_create();
+       pool = apt_test_framework_pool_get(test_framework);
+
+       /* create test suites and add them to test framework */
+       test_suite = task_test_suite_create(pool);
+       apt_test_framework_suite_add(test_framework,test_suite);
+
+       test_suite = consumer_task_test_suite_create(pool);
+       apt_test_framework_suite_add(test_framework,test_suite);
+
+       /* run tests */
+       apt_test_framework_run(test_framework,argc,argv);
+
+       /* destroy test framework */
+       apt_test_framework_destroy(test_framework);
+
+       /* final apr global termination */
+       apr_terminate();
+       return 0;
+}
diff --git a/libs/unimrcp/tests/apttest/src/task_suite.c b/libs/unimrcp/tests/apttest/src/task_suite.c
new file mode 100644 (file)
index 0000000..ae3a18b
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apt_test_suite.h"
+#include "apt_task.h"
+#include "apt_log.h"
+
+static apt_bool_t task_main(apt_task_t *task)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Do the Job");
+       apt_task_delay(3000);
+       return TRUE;
+}
+
+static apt_bool_t task_test_run(apt_test_suite_t *suite, int argc, const char * const *argv)
+{
+       apt_task_t *task;
+       apt_task_vtable_t *vtable;
+
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create Task");
+       task = apt_task_create(NULL,NULL,suite->pool);
+       if(!task) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Task");
+               return FALSE;
+       }
+       vtable = apt_task_vtable_get(task);
+       if(vtable) {
+               vtable->run = task_main;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Start Task");
+       if(apt_task_start(task) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Start Task");
+               apt_task_destroy(task);
+               return FALSE;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Wait for Task to Complete");
+       apt_task_wait_till_complete(task);
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy Task");
+       apt_task_destroy(task);
+       return TRUE;
+}
+
+apt_test_suite_t* task_test_suite_create(apr_pool_t *pool)
+{
+       apt_test_suite_t *suite = apt_test_suite_create(pool,"task",NULL,task_test_run);
+       return suite;
+}
diff --git a/libs/unimrcp/tests/mpftest/Makefile.am b/libs/unimrcp/tests/mpftest/Makefile.am
new file mode 100644 (file)
index 0000000..7f5c7b3
--- /dev/null
@@ -0,0 +1,12 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+INCLUDES             = -I$(top_srcdir)/libs/mpf/include \
+                       -I$(top_srcdir)/libs/apr-toolkit/include \
+                       $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+noinst_PROGRAMS      = mpftest
+mpftest_LDADD        = $(top_builddir)/libs/mpf/libmpf.la \
+                       $(top_builddir)/libs/apr-toolkit/libaprtoolkit.la \
+                       $(UNIMRCP_APR_LIBS) $(UNIMRCP_APU_LIBS)
+mpftest_SOURCES      = src/main.c \
+                       src/mpf_suite.c
diff --git a/libs/unimrcp/tests/mpftest/mpftest.vcproj b/libs/unimrcp/tests/mpftest/mpftest.vcproj
new file mode 100644 (file)
index 0000000..28f51e0
--- /dev/null
@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="mpftest"
+       ProjectGUID="{DCF01B1C-5268-44F3-9130-D647FABFB663}"
+       RootNamespace="mpftest"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\mpf.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="mpf.lib aprtoolkit.lib libaprutil-1.lib libapr-1.lib ws2_32.lib winmm.lib"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\mpf.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="mpf.lib aprtoolkit.lib libaprutil-1.lib libapr-1.lib ws2_32.lib winmm.lib "
+                               LinkTimeCodeGeneration="1"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+                       >
+                       <File
+                               RelativePath=".\src\main.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\mpf_suite.c"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/tests/mpftest/src/main.c b/libs/unimrcp/tests/mpftest/src/main.c
new file mode 100644 (file)
index 0000000..3b3e843
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apt_test_suite.h"
+#include "apt_log.h"
+
+apt_test_suite_t* mpf_suite_create(apr_pool_t *pool);
+
+int main(int argc, const char * const *argv)
+{
+       apt_test_framework_t *test_framework;
+       apt_test_suite_t *test_suite;
+       apr_pool_t *pool;
+       
+       /* one time apr global initialization */
+       if(apr_initialize() != APR_SUCCESS) {
+               return 0;
+       }
+
+       /* create test framework */
+       test_framework = apt_test_framework_create();
+       pool = apt_test_framework_pool_get(test_framework);
+
+       /* create test suites and add them to test framework */
+       test_suite = mpf_suite_create(pool);
+       apt_test_framework_suite_add(test_framework,test_suite);
+
+       /* run tests */
+       apt_test_framework_run(test_framework,argc,argv);
+
+       /* destroy test framework */
+       apt_test_framework_destroy(test_framework);
+
+       /* final apr global termination */
+       apr_terminate();
+       return 0;
+}
diff --git a/libs/unimrcp/tests/mpftest/src/mpf_suite.c b/libs/unimrcp/tests/mpftest/src/mpf_suite.c
new file mode 100644 (file)
index 0000000..af144b5
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_thread_cond.h>
+#include "apt_test_suite.h"
+#include "mpf_engine.h"
+#include "mpf_user.h"
+#include "mpf_termination.h"
+#include "mpf_rtp_termination_factory.h"
+#include "mpf_file_termination_factory.h"
+#include "mpf_audio_file_descriptor.h"
+#include "mpf_rtp_descriptor.h"
+#include "apt_pool.h"
+#include "apt_consumer_task.h"
+#include "apt_log.h"
+
+typedef struct mpf_suite_session_t mpf_suite_session_t;
+typedef struct mpf_suite_engine_t mpf_suite_engine_t;
+
+
+/** Test suite session */
+struct mpf_suite_session_t {
+       /** Pool to allocate memory from */
+       apr_pool_t        *pool;
+
+       /** Media context associated with the session */
+       mpf_context_t     *context;
+       /** The first termination in the context */
+       mpf_termination_t *termination1;
+       /** The second termination in the context */
+       mpf_termination_t *termination2;
+       /** RTP or file termination mode */
+       apt_bool_t         rtp_mode;
+};
+
+/** Test suite engine */
+struct mpf_suite_engine_t {
+       /** The main task of the test engine, which sends messages to MPF engine and 
+        * processes responses and events sent back from MPF engine */
+       apt_consumer_task_t       *consumer_task;
+       /** MPF engine task */
+       apt_task_t                *engine_task;
+       /** RTP termination factory */
+       mpf_termination_factory_t *rtp_termination_factory;
+       /** File termination factory */
+       mpf_termination_factory_t *file_termination_factory;
+
+       /** Wait object, which is signalled to indicate shutdown */
+       apr_thread_cond_t         *wait_object;
+       /** Mutex of the wait object */
+       apr_thread_mutex_t        *wait_object_mutex;
+};
+
+static apt_bool_t mpf_test_run(apt_test_suite_t *suite, int argc, const char * const *argv);
+
+static void mpf_suite_on_start_complete(apt_task_t *task);
+static void mpf_suite_on_terminate_complete(apt_task_t *task);
+static apt_bool_t mpf_suite_msg_process(apt_task_t *task, apt_task_msg_t *msg);
+
+static mpf_audio_file_descriptor_t* mpf_file_reader_descriptor_create(mpf_suite_session_t *session);
+static mpf_audio_file_descriptor_t* mpf_file_writer_descriptor_create(mpf_suite_session_t *session);
+static mpf_rtp_stream_descriptor_t* mpf_rtp_local_descriptor_create(mpf_suite_session_t *session);
+static mpf_rtp_stream_descriptor_t* mpf_rtp_remote_descriptor_create(mpf_suite_session_t *session);
+
+
+/** Create MPF test suite */
+apt_test_suite_t* mpf_suite_create(apr_pool_t *pool)
+{
+       apt_test_suite_t *suite = apt_test_suite_create(pool,"mpf",NULL,mpf_test_run);
+       return suite;
+}
+
+/** Run MPF test suite */
+static apt_bool_t mpf_test_run(apt_test_suite_t *suite, int argc, const char * const *argv)
+{
+       mpf_suite_engine_t *suite_engine;
+       mpf_codec_manager_t *codec_manager;
+       mpf_rtp_config_t *config;
+       mpf_engine_t *engine;
+
+       apt_task_t *task;
+       apt_task_vtable_t *vtable;
+       apt_task_msg_pool_t *msg_pool;
+
+       suite_engine = apr_palloc(suite->pool,sizeof(mpf_suite_engine_t));
+
+       engine = mpf_engine_create(suite->pool);
+       if(!engine) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create MPF Engine");
+               return FALSE;
+       }
+       codec_manager = mpf_engine_codec_manager_create(suite->pool);
+       if(codec_manager) {
+               mpf_engine_codec_manager_register(engine,codec_manager);
+       }
+       suite_engine->engine_task = mpf_task_get(engine);
+
+       config = mpf_rtp_config_create(suite->pool);
+       apt_string_set(&config->ip,"127.0.0.1");
+       config->rtp_port_min = 5000;
+       config->rtp_port_min = 6000;
+       suite_engine->rtp_termination_factory = mpf_rtp_termination_factory_create(config,suite->pool);
+       suite_engine->file_termination_factory = mpf_file_termination_factory_create(suite->pool);
+
+       msg_pool = apt_task_msg_pool_create_dynamic(sizeof(mpf_message_t),suite->pool);
+
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create Consumer Task");
+       suite_engine->consumer_task = apt_consumer_task_create(suite_engine,msg_pool,suite->pool);
+       if(!suite_engine->consumer_task) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Consumer Task");
+               return FALSE;
+       }
+       task = apt_consumer_task_base_get(suite_engine->consumer_task);
+       vtable = apt_task_vtable_get(task);
+       if(vtable) {
+               vtable->process_msg = mpf_suite_msg_process;
+               vtable->on_start_complete = mpf_suite_on_start_complete;
+               vtable->on_terminate_complete = mpf_suite_on_terminate_complete;
+       }
+
+       apt_task_add(task,suite_engine->engine_task);
+
+       apr_thread_mutex_create(&suite_engine->wait_object_mutex,APR_THREAD_MUTEX_UNNESTED,suite->pool);
+       apr_thread_cond_create(&suite_engine->wait_object,suite->pool);
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Start Task");
+       if(apt_task_start(task) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Start Task");
+               apt_task_destroy(task);
+               return FALSE;
+       }
+
+       apr_thread_mutex_lock(suite_engine->wait_object_mutex);
+       apr_thread_cond_wait(suite_engine->wait_object,suite_engine->wait_object_mutex);
+       apr_thread_mutex_unlock(suite_engine->wait_object_mutex);
+       
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Terminate Task [wait till complete]");
+       apt_task_terminate(task,TRUE);
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy Task");
+       apt_task_destroy(task);
+
+       apr_thread_cond_destroy(suite_engine->wait_object);
+       apr_thread_mutex_destroy(suite_engine->wait_object_mutex);
+       return TRUE;
+}
+
+/** Start execution of MPF test suite scenario  */
+static void mpf_suite_on_start_complete(apt_task_t *task)
+{
+       mpf_suite_session_t *session;
+       apt_task_t *consumer_task;
+       mpf_suite_engine_t *suite_engine;
+       apt_task_msg_t *msg;
+       mpf_message_t *mpf_message;
+       apr_pool_t *pool = NULL;
+
+       consumer_task = apt_task_object_get(task);
+       suite_engine = apt_task_object_get(consumer_task);
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"On MPF Suite Start");
+       pool = apt_pool_create();
+       session = apr_palloc(pool,sizeof(mpf_suite_session_t));
+       session->pool = pool;
+       session->context = NULL;
+       session->termination1 = NULL;
+       session->termination2 = NULL;
+       session->rtp_mode = TRUE;
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create MPF Context");
+       session->context = mpf_context_create(session,2,pool);
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create Termination [1]");
+       session->termination1 = mpf_termination_create(suite_engine->file_termination_factory,session,session->pool);
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Add Termination [1]");
+       msg = apt_task_msg_get(task);
+       msg->type = TASK_MSG_USER;
+       mpf_message = (mpf_message_t*) msg->data;
+
+       mpf_message->message_type = MPF_MESSAGE_TYPE_REQUEST;
+       mpf_message->command_id = MPF_COMMAND_ADD;
+       mpf_message->context = session->context;
+       mpf_message->termination = session->termination1;
+       mpf_message->descriptor = mpf_file_reader_descriptor_create(session);
+       apt_task_msg_signal(suite_engine->engine_task,msg);
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create Termination [2]");
+       if(session->rtp_mode == TRUE) {
+               session->termination2 = mpf_termination_create(suite_engine->rtp_termination_factory,session,session->pool);
+       }
+       else {
+               session->termination2 = mpf_termination_create(suite_engine->file_termination_factory,session,session->pool);
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Add Termination [2]");
+       msg = apt_task_msg_get(task);
+       msg->type = TASK_MSG_USER;
+       mpf_message = (mpf_message_t*) msg->data;
+
+       mpf_message->message_type = MPF_MESSAGE_TYPE_REQUEST;
+       mpf_message->command_id = MPF_COMMAND_ADD;
+       mpf_message->context = session->context;
+       mpf_message->termination = session->termination2;
+       if(session->rtp_mode == TRUE) {
+               mpf_message->descriptor = mpf_rtp_local_descriptor_create(session);
+       }
+       else {
+               mpf_message->descriptor = mpf_file_writer_descriptor_create(session);
+       }
+       apt_task_msg_signal(suite_engine->engine_task,msg);
+}
+
+/** Execution of MPF test suite scenario is terminated  */
+static void mpf_suite_on_terminate_complete(apt_task_t *task)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"On MPF Suite Terminate");
+}
+
+/** Process task messages  */
+static apt_bool_t mpf_suite_msg_process(apt_task_t *task, apt_task_msg_t *msg)
+{
+       const mpf_message_t *mpf_message = (const mpf_message_t*) msg->data;
+       if(mpf_message->message_type == MPF_MESSAGE_TYPE_RESPONSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process MPF Response");
+               if(mpf_message->command_id == MPF_COMMAND_ADD) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Add Termination");
+                       if(mpf_message->termination) {
+                               mpf_suite_session_t *session;
+                               session = mpf_termination_object_get(mpf_message->termination);
+                               if(session->termination2 == mpf_message->termination && session->rtp_mode == TRUE) {
+                                       apt_task_msg_t *msg;
+                                       mpf_message_t *request;
+                                       apt_task_t *consumer_task;
+                                       mpf_suite_engine_t *suite_engine;
+
+                                       consumer_task = apt_task_object_get(task);
+                                       suite_engine = apt_task_object_get(consumer_task);
+
+                                       msg = apt_task_msg_get(task);
+                                       msg->type = TASK_MSG_USER;
+                                       request = (mpf_message_t*) msg->data;
+
+                                       request->message_type = MPF_MESSAGE_TYPE_REQUEST;
+                                       request->command_id = MPF_COMMAND_MODIFY;
+                                       request->context = session->context;
+                                       request->termination = session->termination2;
+                                       request->descriptor = mpf_rtp_remote_descriptor_create(session);
+                                       apt_task_msg_signal(suite_engine->engine_task,msg);
+                               }
+                       }
+               }
+               else if(mpf_message->command_id == MPF_COMMAND_SUBTRACT) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Subtract Termination");
+                       if(mpf_message->termination) {
+                               mpf_suite_session_t *session;
+                               session = mpf_termination_object_get(mpf_message->termination);
+                               if(session->termination1 == mpf_message->termination) {
+                                       session->termination1 = NULL;
+                               }
+                               if(session->termination2 == mpf_message->termination) {
+                                       session->termination2 = NULL;
+                               }
+                               mpf_termination_destroy(mpf_message->termination);
+
+                               if(!session->termination1 && !session->termination2) {
+                                       apt_task_t *consumer_task;
+                                       mpf_suite_engine_t *suite_engine;
+
+                                       mpf_context_destroy(session->context);
+                                       session->context = NULL;
+                                       apr_pool_destroy(session->pool);
+
+                                       consumer_task = apt_task_object_get(task);
+                                       suite_engine = apt_task_object_get(consumer_task);
+
+                                       apr_thread_mutex_lock(suite_engine->wait_object_mutex);
+                                       apr_thread_cond_signal(suite_engine->wait_object);
+                                       apr_thread_mutex_unlock(suite_engine->wait_object_mutex);
+                               }
+                       }
+               }
+       }
+       else if(mpf_message->message_type == MPF_MESSAGE_TYPE_EVENT) {
+               apt_task_t *consumer_task;
+               mpf_suite_engine_t *suite_engine;
+               apt_task_msg_t *msg;
+               mpf_message_t *request;
+               mpf_suite_session_t *session;
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process MPF Event");
+               if(mpf_message->termination) {
+                       session = mpf_termination_object_get(mpf_message->termination);
+                       if(session->termination1) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Subtract Termination [1]");
+                               msg = apt_task_msg_get(task);
+                               msg->type = TASK_MSG_USER;
+                               request = (mpf_message_t*) msg->data;
+
+                               request->message_type = MPF_MESSAGE_TYPE_REQUEST;
+                               request->command_id = MPF_COMMAND_SUBTRACT;
+                               request->context = session->context;
+                               request->termination = session->termination1;
+
+                               consumer_task = apt_task_object_get(task);
+                               suite_engine = apt_task_object_get(consumer_task);
+                               apt_task_msg_signal(suite_engine->engine_task,msg);
+                       }
+                       if(session->termination2) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Subtract Termination [2]");
+                               msg = apt_task_msg_get(task);
+                               msg->type = TASK_MSG_USER;
+                               request = (mpf_message_t*) msg->data;
+
+                               request->message_type = MPF_MESSAGE_TYPE_REQUEST;
+                               request->command_id = MPF_COMMAND_SUBTRACT;
+                               request->context = session->context;
+                               request->termination = session->termination2;
+
+                               consumer_task = apt_task_object_get(task);
+                               suite_engine = apt_task_object_get(consumer_task);
+                               apt_task_msg_signal(suite_engine->engine_task,msg);
+                       }
+               }
+       }
+
+       return TRUE;
+}
+
+/** Create sample file reader descriptor */
+static mpf_audio_file_descriptor_t* mpf_file_reader_descriptor_create(mpf_suite_session_t *session)
+{
+       mpf_codec_descriptor_t *codec_descriptor;
+       mpf_audio_file_descriptor_t *descriptor = apr_palloc(session->pool,sizeof(mpf_audio_file_descriptor_t));
+       descriptor->mask = FILE_READER;
+       descriptor->read_handle = fopen("demo.pcm","rb");
+       descriptor->write_handle = NULL;
+
+       codec_descriptor = &descriptor->codec_descriptor;
+       codec_descriptor->payload_type = 11;
+       apt_string_set(&codec_descriptor->name,"L16");
+       codec_descriptor->sampling_rate = 8000;
+       codec_descriptor->channel_count = 1;
+       return descriptor;
+}
+
+/** Create sample file writer descriptor */
+static mpf_audio_file_descriptor_t* mpf_file_writer_descriptor_create(mpf_suite_session_t *session)
+{
+       mpf_codec_descriptor_t *codec_descriptor;
+       mpf_audio_file_descriptor_t *descriptor = apr_palloc(session->pool,sizeof(mpf_audio_file_descriptor_t));
+       descriptor->mask = FILE_WRITER;
+       descriptor->max_write_size = 500000; /* 500Kb */
+       descriptor->write_handle = fopen("demo_out.pcm","wb");
+       descriptor->read_handle = NULL;
+
+       codec_descriptor = &descriptor->codec_descriptor;
+       codec_descriptor->payload_type = 11;
+       apt_string_set(&codec_descriptor->name,"L16");
+       codec_descriptor->sampling_rate = 8000;
+       codec_descriptor->channel_count = 1;
+       return descriptor;
+}
+
+/** Create sample RTP local descriptor */
+static mpf_rtp_stream_descriptor_t* mpf_rtp_local_descriptor_create(mpf_suite_session_t *session)
+{
+       mpf_rtp_stream_descriptor_t *descriptor = apr_palloc(session->pool,sizeof(mpf_rtp_stream_descriptor_t));
+       mpf_rtp_stream_descriptor_init(descriptor);
+       descriptor->local = apr_palloc(session->pool,sizeof(mpf_rtp_media_descriptor_t));
+       mpf_rtp_media_descriptor_init(descriptor->local);
+       descriptor->local->mode = STREAM_MODE_NONE;
+       apt_string_set(&descriptor->local->base.ip,"127.0.0.1");
+       descriptor->local->base.port = 5000;
+       return descriptor;
+}
+
+/** Create sample RTP remote descriptor */
+static mpf_rtp_stream_descriptor_t* mpf_rtp_remote_descriptor_create(mpf_suite_session_t *session)
+{
+       mpf_codec_list_t *codec_list;
+       mpf_codec_descriptor_t *codec_descriptor;
+       mpf_rtp_stream_descriptor_t *descriptor = apr_palloc(session->pool,sizeof(mpf_rtp_stream_descriptor_t));
+       mpf_rtp_stream_descriptor_init(descriptor);
+       descriptor->remote = apr_palloc(session->pool,sizeof(mpf_rtp_media_descriptor_t));
+       mpf_rtp_media_descriptor_init(descriptor->remote);
+       descriptor->remote->mode = STREAM_MODE_SEND_RECEIVE;
+       apt_string_set(&descriptor->remote->base.ip,"127.0.0.1");
+       descriptor->remote->base.port = 5002;
+       codec_list = &descriptor->remote->codec_list;
+       mpf_codec_list_init(codec_list,2,session->pool);
+       codec_descriptor = mpf_codec_list_add(codec_list);
+       if(codec_descriptor) {
+               codec_descriptor->payload_type = 0;
+       }
+       codec_descriptor = mpf_codec_list_add(codec_list);
+       if(codec_descriptor) {
+               codec_descriptor->payload_type = 96;
+               apt_string_set(&codec_descriptor->name,"PCMU");
+               codec_descriptor->sampling_rate = 16000;
+               codec_descriptor->channel_count = 1;
+       }
+
+       return descriptor;
+}
diff --git a/libs/unimrcp/tests/mrcptest/Makefile.am b/libs/unimrcp/tests/mrcptest/Makefile.am
new file mode 100644 (file)
index 0000000..9a4c634
--- /dev/null
@@ -0,0 +1,16 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+INCLUDES             = -I$(top_srcdir)/libs/mrcp/include \
+                       -I$(top_srcdir)/libs/mrcp/message/include \
+                       -I$(top_srcdir)/libs/mrcp/control/include \
+                       -I$(top_srcdir)/libs/mrcp/resources/include \
+                       -I$(top_srcdir)/libs/apr-toolkit/include \
+                       $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+noinst_PROGRAMS      = mrcptest
+mrcptest_LDADD       = $(top_builddir)/libs/mrcp/libmrcp.la \
+                       $(top_builddir)/libs/apr-toolkit/libaprtoolkit.la \
+                       $(UNIMRCP_APR_LIBS) $(UNIMRCP_APU_LIBS)
+mrcptest_SOURCES     = src/main.c \
+                       src/parse_gen_suite.c \
+                       src/set_get_suite.c
diff --git a/libs/unimrcp/tests/mrcptest/mrcptest.vcproj b/libs/unimrcp/tests/mrcptest/mrcptest.vcproj
new file mode 100644 (file)
index 0000000..9a262bd
--- /dev/null
@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8,00"
+       Name="mrcptest"
+       ProjectGUID="{3CA97077-6210-4362-998A-D15A35EEAA08}"
+       RootNamespace="mrcptest"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\mrcp.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="mrcp.lib aprtoolkit.lib libaprutil-1.lib libapr-1.lib"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\mrcp.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="mrcp.lib aprtoolkit.lib libaprutil-1.lib libapr-1.lib"
+                               LinkTimeCodeGeneration="1"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+                       >
+                       <File
+                               RelativePath=".\src\main.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\parse_gen_suite.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\set_get_suite.c"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/tests/mrcptest/src/main.c b/libs/unimrcp/tests/mrcptest/src/main.c
new file mode 100644 (file)
index 0000000..a93fd33
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apt_test_suite.h"
+#include "apt_log.h"
+
+apt_test_suite_t* parse_gen_test_suite_create(apr_pool_t *pool);
+apt_test_suite_t* set_get_test_suite_create(apr_pool_t *pool);
+
+int main(int argc, const char * const *argv)
+{
+       apt_test_framework_t *test_framework;
+       apt_test_suite_t *test_suite;
+       apr_pool_t *pool;
+       
+       /* one time apr global initialization */
+       if(apr_initialize() != APR_SUCCESS) {
+               return 0;
+       }
+
+       /* create test framework */
+       test_framework = apt_test_framework_create();
+       pool = apt_test_framework_pool_get(test_framework);
+
+       /* create test suites and add them to test framework */
+       test_suite = set_get_test_suite_create(pool);
+       apt_test_framework_suite_add(test_framework,test_suite);
+       test_suite = parse_gen_test_suite_create(pool);
+       apt_test_framework_suite_add(test_framework,test_suite);
+
+       /* run tests */
+       apt_test_framework_run(test_framework,argc,argv);
+
+       /* destroy test framework */
+       apt_test_framework_destroy(test_framework);
+
+       /* final apr global termination */
+       apr_terminate();
+       return 0;
+}
diff --git a/libs/unimrcp/tests/mrcptest/src/parse_gen_suite.c b/libs/unimrcp/tests/mrcptest/src/parse_gen_suite.c
new file mode 100644 (file)
index 0000000..11aeb97
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_file_info.h>
+#include <apr_file_io.h>
+#include "apt_test_suite.h"
+#include "apt_log.h"
+#include "mrcp_default_factory.h"
+#include "mrcp_message.h"
+#include "mrcp_stream.h"
+
+static apt_bool_t test_stream_generate(mrcp_generator_t *generator, mrcp_message_t *message)
+{
+       char buffer[500];
+       apt_text_stream_t stream;
+       mrcp_stream_result_e result;
+       apt_bool_t continuation;
+
+       mrcp_generator_message_set(generator,message);
+       do {
+               apt_text_stream_init(&stream,buffer,sizeof(buffer)-1);
+               continuation = FALSE;
+               result = mrcp_generator_run(generator,&stream);
+               if(result == MRCP_STREAM_MESSAGE_COMPLETE) {
+                       stream.text.length = stream.pos - stream.text.buf;
+                       *stream.pos = '\0';
+                       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Generated MRCP Stream [%lu bytes]\n%s",stream.text.length,stream.text.buf);
+               }
+               else if(result == MRCP_STREAM_MESSAGE_TRUNCATED) {
+                       *stream.pos = '\0';
+                       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Generated MRCP Stream [%lu bytes] continuation awaiting\n%s",stream.text.length,stream.text.buf);
+                       continuation = TRUE;
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Generate MRCP Stream");
+               }
+       }
+       while(continuation == TRUE);
+       return TRUE;
+}
+
+static apt_bool_t mrcp_message_handler(void *obj, mrcp_message_t *message, mrcp_stream_result_e result)
+{
+       if(result == MRCP_STREAM_MESSAGE_COMPLETE) {
+               /* message is completely parsed */
+               mrcp_generator_t *generator = obj;
+               test_stream_generate(generator,message);
+       }
+       return TRUE;
+}
+
+static apt_bool_t resource_name_read(apr_file_t *file, mrcp_parser_t *parser)
+{
+       char buffer[100];
+       apt_text_stream_t stream;
+       apt_bool_t status = FALSE;
+       apt_text_stream_init(&stream,buffer,sizeof(buffer)-1);
+       if(apr_file_read(file,stream.pos,&stream.text.length) != APR_SUCCESS) {
+               return FALSE;
+       }
+
+       /* skip the first line in a test file, which indicates resource name */
+       if(*stream.pos =='/' && *(stream.pos+1)=='/') {
+               apt_str_t line;
+               stream.pos += 2;
+               if(apt_text_line_read(&stream,&line) == TRUE) {
+                       apr_off_t offset = stream.pos - stream.text.buf;
+                       apr_file_seek(file,APR_SET,&offset);
+                       mrcp_parser_resource_name_set(parser,&line);
+                       status = TRUE;
+               }
+       }
+       return status;
+}
+
+static apt_bool_t test_file_process(apt_test_suite_t *suite, mrcp_resource_factory_t *factory, mrcp_version_e version, const char *file_path)
+{
+       apr_file_t *file;
+       char buffer[500];
+       apt_text_stream_t stream;
+       mrcp_parser_t *parser;
+       mrcp_generator_t *generator;
+       apr_size_t length;
+       apr_size_t offset;
+       apt_str_t resource_name;
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open File [%s]",file_path);
+       if(apr_file_open(&file,file_path,APR_FOPEN_READ | APR_FOPEN_BINARY,APR_OS_DEFAULT,suite->pool) != APR_SUCCESS) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Open File");
+               return FALSE;
+       }
+
+       parser = mrcp_parser_create(factory,suite->pool);
+       generator = mrcp_generator_create(factory,suite->pool);
+
+       apt_string_reset(&resource_name);
+       if(version == MRCP_VERSION_1) {
+               resource_name_read(file,parser);
+       }
+
+       apt_text_stream_init(&stream,buffer,sizeof(buffer)-1);
+       do {
+               /* init length of the stream */
+               stream.text.length = sizeof(buffer)-1;
+               /* calculate offset remaining from the previous receive / if any */
+               offset = stream.pos - stream.text.buf;
+               /* calculate available length */
+               length = stream.text.length - offset;
+
+               if(apr_file_read(file,stream.pos,&length) != APR_SUCCESS) {
+                       break;
+               }
+               /* calculate actual length of the stream */
+               stream.text.length = offset + length;
+               stream.pos[length] = '\0';
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Parse MRCP Stream [%lu bytes]\n%s",length,stream.pos);
+               
+               /* reset pos */
+               stream.pos = stream.text.buf;
+               mrcp_stream_walk(parser,&stream,mrcp_message_handler,generator);
+       }
+       while(apr_file_eof(file) != APR_EOF);
+
+       apr_file_close(file);
+       return TRUE;
+}
+
+static apt_bool_t test_dir_process(apt_test_suite_t *suite, mrcp_resource_factory_t *factory, mrcp_version_e version)
+{
+       apr_status_t rv;
+       apr_dir_t *dir;
+
+       const char *dir_name = "v2";
+       if(version == MRCP_VERSION_1) {
+               dir_name = "v1";
+       }
+       if(apr_dir_open(&dir,dir_name,suite->pool) != APR_SUCCESS) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot Open Directory [%s]",dir_name);
+               return FALSE;
+       }
+
+       do {
+               apr_finfo_t finfo;
+               rv = apr_dir_read(&finfo,APR_FINFO_DIRENT,dir);
+               if(rv == APR_SUCCESS) {
+                       if(finfo.filetype == APR_REG && finfo.name) {
+                               char *file_path;
+                               apr_filepath_merge(&file_path,dir_name,finfo.name,0,suite->pool);
+                               test_file_process(suite,factory,version,file_path);
+                               printf("\nPress ENTER to continue\n");
+                               getchar();
+                       }
+               }
+       } 
+       while(rv == APR_SUCCESS);
+
+       apr_dir_close(dir);
+       return TRUE;
+}
+
+static apt_bool_t parse_gen_test_run(apt_test_suite_t *suite, int argc, const char * const *argv)
+{
+       mrcp_resource_factory_t *factory = mrcp_default_factory_create(suite->pool);
+       if(!factory) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Resource Factory");
+               return FALSE;
+       }
+
+       test_dir_process(suite,factory,MRCP_VERSION_2);
+       test_dir_process(suite,factory,MRCP_VERSION_1);
+
+       mrcp_resource_factory_destroy(factory);
+       return TRUE;
+}
+
+apt_test_suite_t* parse_gen_test_suite_create(apr_pool_t *pool)
+{
+       apt_test_suite_t *suite = apt_test_suite_create(pool,"parse-gen",NULL,parse_gen_test_run);
+       return suite;
+}
diff --git a/libs/unimrcp/tests/mrcptest/src/set_get_suite.c b/libs/unimrcp/tests/mrcptest/src/set_get_suite.c
new file mode 100644 (file)
index 0000000..830cba3
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apt_test_suite.h"
+#include "apt_log.h"
+/* common includes */
+#include "mrcp_default_factory.h"
+#include "mrcp_message.h"
+#include "mrcp_generic_header.h"
+/* synthesizer includes */
+#include "mrcp_synth_header.h"
+#include "mrcp_synth_resource.h"
+/* recognizer includes */
+#include "mrcp_recog_header.h"
+#include "mrcp_recog_resource.h"
+
+#define SAMPLE_VOICE_AGE 28
+#define SAMPLE_CONTENT_TYPE "application/synthesis+ssml"
+#define SAMPLE_CONTENT_ID "123456"
+#define SAMPLE_CONTENT "SSML content goes here"
+#define SAMPLE_PARAM_NAME "SampleParamName"
+#define SAMPLE_PARAM_VALUE "SampleParamValue"
+
+/* Create SPEAK request */
+static mrcp_message_t* speak_request_create(mrcp_resource_factory_t *factory, apr_pool_t *pool)
+{
+       mrcp_message_t *message;
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create SPEAK Request");
+       message = mrcp_request_create(MRCP_SYNTHESIZER_RESOURCE,SYNTHESIZER_SPEAK,pool);
+       mrcp_message_resourcify_by_id(factory,message);
+       if(message) {
+               mrcp_generic_header_t *generic_header;
+               mrcp_synth_header_t *synth_header;
+               /* get/allocate generic header */
+               generic_header = mrcp_generic_header_prepare(message);
+               if(generic_header) {
+                       /* set generic header fields */
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set Content-Type: %s",SAMPLE_CONTENT_TYPE);
+                       apt_string_assign(&generic_header->content_type,SAMPLE_CONTENT_TYPE,message->pool);
+                       mrcp_generic_header_property_add(message,GENERIC_HEADER_CONTENT_TYPE);
+               }
+               /* get/allocate synthesizer header */
+               synth_header = mrcp_resource_header_prepare(message);
+               if(synth_header) {
+                       /* set synthesizer header fields */
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set Voice-Age: %d",SAMPLE_VOICE_AGE);
+                       synth_header->voice_param.age = SAMPLE_VOICE_AGE;
+                       mrcp_resource_header_property_add(message,SYNTHESIZER_HEADER_VOICE_AGE);
+               }
+               /* set message body */
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set Body: %s",SAMPLE_CONTENT);
+               apt_string_assign(&message->body,SAMPLE_CONTENT,message->pool);
+       }
+       return message;
+}
+
+/* Test SPEAK request */
+static apt_bool_t speak_request_test(mrcp_resource_factory_t *factory, mrcp_message_t *message)
+{
+       apt_bool_t res;
+       mrcp_generic_header_t *generic_header;
+       mrcp_synth_header_t *synth_header;
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Test SPEAK Request");
+       res = FALSE;
+       /* get generic header */
+       generic_header = mrcp_generic_header_get(message);
+       if(generic_header) {
+               /* test content type header */
+               if(mrcp_generic_header_property_check(message,GENERIC_HEADER_CONTENT_TYPE) == TRUE) {
+                       if(strncasecmp(generic_header->content_type.buf,SAMPLE_CONTENT_TYPE,generic_header->content_type.length) == 0) {
+                               /* OK */
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Get Content-Type: %s",generic_header->content_type.buf);
+                               res = TRUE;
+                       }
+               }
+       }
+       if(res == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Test Generic Header");
+               return FALSE;
+       }
+
+       res = FALSE;
+       /* get synthesizer header */
+       synth_header = mrcp_resource_header_get(message);
+       if(synth_header) {
+               /* test voice age header */
+               if(mrcp_resource_header_property_check(message,SYNTHESIZER_HEADER_VOICE_AGE) == TRUE) {
+                       if(synth_header->voice_param.age == SAMPLE_VOICE_AGE) {
+                               /* OK */
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Get Voice-Age: %d",synth_header->voice_param.age);
+                               res = TRUE;
+                       }
+               }
+       }
+       if(res == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Test Synthesizer Header");
+               return FALSE;
+       }
+       
+       if(strncasecmp(message->body.buf,SAMPLE_CONTENT,message->body.length) != 0) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Test Message Body");
+               return FALSE;
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Get Body: %s",message->body.buf);
+       return TRUE;
+}
+
+/* Create SPEAK response */
+static mrcp_message_t* speak_response_create(mrcp_resource_factory_t *factory, const mrcp_message_t *request)
+{
+       mrcp_message_t *response;
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create SPEAK Response");
+       response = mrcp_response_create(request,request->pool);
+       if(response) {
+               /* set IN-PROGRESS state */
+               response->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS;
+       }
+       return response;
+}
+
+/* Create SPEAK-COMPLETE event */
+static mrcp_message_t* speak_event_create(mrcp_resource_factory_t *factory, const mrcp_message_t *request)
+{
+       mrcp_message_t *event_message;
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create SPEAK-COMPLETE Event");
+       event_message = mrcp_event_create(request,SYNTHESIZER_SPEAK_COMPLETE,request->pool);
+       if(event_message) {
+               /* get/allocate synthesizer header */
+               mrcp_synth_header_t *synth_header = mrcp_resource_header_prepare(event_message);
+               if(synth_header) {
+                       /* set completion cause */
+                       synth_header->completion_cause = SYNTHESIZER_COMPLETION_CAUSE_NORMAL;
+                       mrcp_resource_header_property_add(event_message,SYNTHESIZER_HEADER_COMPLETION_CAUSE);
+               }
+               /* set request state */
+               event_message->start_line.request_state = MRCP_REQUEST_STATE_COMPLETE;
+       }
+       return event_message;
+}
+
+
+/* Create GET-PARAMS request */
+static mrcp_message_t* get_params_request_create(mrcp_resource_factory_t *factory, apr_pool_t *pool)
+{
+       mrcp_message_t *message;
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create GET-PARAMS Request");
+       message = mrcp_request_create(MRCP_SYNTHESIZER_RESOURCE,SYNTHESIZER_GET_PARAMS,pool);
+       mrcp_message_resourcify_by_id(factory,message);
+       if(message) {
+               apt_str_t param_name;
+               apt_str_t param_value;
+               mrcp_generic_header_t *generic_header;
+               mrcp_synth_header_t *synth_header;
+               /* get/allocate generic header */
+               generic_header = mrcp_generic_header_prepare(message);
+               if(generic_header) {
+                       /* set content id empty header */
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set Content-ID: <empty>");
+                       mrcp_generic_header_name_property_add(message,GENERIC_HEADER_CONTENT_ID);
+                       
+                       /* set vendor specific params header */
+                       generic_header->vendor_specific_params = apt_pair_array_create(1,pool);
+                       apt_string_set(&param_name,SAMPLE_PARAM_NAME);
+                       apt_string_reset(&param_value);
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set Vendor-Specific-Params: %s",param_name.buf);
+                       apt_pair_array_append(generic_header->vendor_specific_params,&param_name,&param_value,pool);
+                       mrcp_generic_header_property_add(message,GENERIC_HEADER_VENDOR_SPECIFIC_PARAMS);
+               }
+               /* get/allocate synthesizer header */
+               synth_header = mrcp_resource_header_prepare(message);
+               if(synth_header) {
+                       /* set voice age empty header */
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set Voice-Age: <empty>");
+                       mrcp_resource_header_name_property_add(message,SYNTHESIZER_HEADER_VOICE_AGE);
+               }
+       }
+       return message;
+}
+
+/* Create GET-PARAMS response */
+static mrcp_message_t* get_params_response_create(mrcp_resource_factory_t *factory, mrcp_message_t *request)
+{
+       apt_bool_t res;
+       mrcp_message_t *response;
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create GET-PARAMS Response");
+       response = mrcp_response_create(request,request->pool);
+       if(response) {
+               mrcp_generic_header_t *generic_header;
+               mrcp_synth_header_t *synth_header;
+               res = FALSE;
+               /* get generic header */
+               generic_header = mrcp_generic_header_get(request);
+               if(generic_header) {
+                       mrcp_generic_header_t *res_generic_header = mrcp_generic_header_prepare(response);
+                       /* test content id header */
+                       if(mrcp_generic_header_property_check(request,GENERIC_HEADER_CONTENT_ID) == TRUE) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set Content-ID: %s",SAMPLE_CONTENT_ID);
+                               apt_string_assign(&res_generic_header->content_id,SAMPLE_CONTENT_ID,response->pool);
+                               mrcp_generic_header_property_add(response,GENERIC_HEADER_CONTENT_ID);
+                               res = TRUE;
+                       }
+                       /* test vendor specific header */
+                       if(mrcp_generic_header_property_check(request,GENERIC_HEADER_VENDOR_SPECIFIC_PARAMS) == TRUE) {
+                               apt_str_t name;
+                               const apt_pair_t *pair;
+                               res_generic_header->vendor_specific_params = apt_pair_array_create(1,response->pool);
+                               apt_string_set(&name,SAMPLE_PARAM_NAME);
+                               pair = apt_pair_array_find(generic_header->vendor_specific_params,&name);
+                               if(pair) {
+                                       apt_str_t value;
+                                       apt_string_set(&value,SAMPLE_PARAM_VALUE);
+                                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set Vendor-Specific-Params: %s=%s",name.buf,value.buf);
+                                       apt_pair_array_append(res_generic_header->vendor_specific_params,&name,&value,response->pool);
+                               }
+                               mrcp_generic_header_property_add(response,GENERIC_HEADER_VENDOR_SPECIFIC_PARAMS);
+                               res = TRUE;
+                       }
+               }
+
+               if(res == FALSE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Test Generic Header");
+                       return NULL;
+               }       
+
+               res = FALSE;
+               /* get synthesizer header */
+               synth_header = mrcp_resource_header_get(request);
+               if(synth_header) {
+                       mrcp_synth_header_t *res_synth_header = mrcp_resource_header_prepare(response);
+                       /* test voice age header */
+                       if(mrcp_resource_header_property_check(request,SYNTHESIZER_HEADER_VOICE_AGE) == TRUE) {
+                               res_synth_header->voice_param.age = SAMPLE_VOICE_AGE;
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set Voice-Age: %d",res_synth_header->voice_param.age);
+                               mrcp_resource_header_property_add(response,SYNTHESIZER_HEADER_VOICE_AGE);
+                               res = TRUE;
+                       }
+               }
+               if(res == FALSE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Test Synthesizer Header");
+                       return NULL;
+               }
+       
+       }
+       return response;
+}
+
+
+
+
+static apt_bool_t speak_test_run(apt_test_suite_t *suite, mrcp_resource_factory_t *factory)
+{
+       mrcp_message_t *message = speak_request_create(factory,suite->pool);
+       if(!message) {
+               return FALSE;
+       }
+       
+       if(speak_request_test(factory,message) != TRUE) {
+               return FALSE;
+       }
+
+       speak_response_create(factory,message);
+       speak_event_create(factory,message);
+       return TRUE;
+}
+
+static apt_bool_t get_params_test_run(apt_test_suite_t *suite, mrcp_resource_factory_t *factory)
+{
+       mrcp_message_t *message = get_params_request_create(factory,suite->pool);
+       if(!message) {
+               return FALSE;
+       }
+
+       get_params_response_create(factory,message);
+       return TRUE;
+}
+
+static apt_bool_t set_get_test_run(apt_test_suite_t *suite, int argc, const char * const *argv)
+{
+       mrcp_resource_factory_t *factory = mrcp_default_factory_create(suite->pool);
+       if(!factory) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Resource Factory");
+               return FALSE;
+       }
+
+       speak_test_run(suite,factory);
+       get_params_test_run(suite,factory);
+       
+       mrcp_resource_factory_destroy(factory);
+       return TRUE;
+}
+
+apt_test_suite_t* set_get_test_suite_create(apr_pool_t *pool)
+{
+       apt_test_suite_t *suite = apt_test_suite_create(pool,"set-gen",NULL,set_get_test_run);
+       return suite;
+}
diff --git a/libs/unimrcp/tests/mrcptest/v1/definegrammar.msg b/libs/unimrcp/tests/mrcptest/v1/definegrammar.msg
new file mode 100644 (file)
index 0000000..1ea7655
--- /dev/null
@@ -0,0 +1,18 @@
+//speechrecog\r
+DEFINE-GRAMMAR 543257 MRCP/1.0\r
+Content-Type:application/grammar+xml\r
+Content-Id:request1@form-level.store\r
+Content-Length:309\r
+\r
+<?xml version="1.0"?>\r
+\r
+<!-- the default grammar language is US English -->\r
+<grammar xml:lang="en-US" version="1.0">\r
+\r
+<!-- single language attachment to tokens -->\r
+<rule id="yes">\r
+    <one-of>\r
+        <item xml:lang="fr-CA">oui</item>\r
+        <item xml:lang="en-US">yes</item>\r
+     </one-of>\r
+</rule>
\ No newline at end of file
diff --git a/libs/unimrcp/tests/mrcptest/v1/getparams.msg b/libs/unimrcp/tests/mrcptest/v1/getparams.msg
new file mode 100644 (file)
index 0000000..61ef0b9
--- /dev/null
@@ -0,0 +1,5 @@
+//speechsynth\r
+GET-PARAMS 543256 MRCP/1.0\r
+Voice-gender:\r
+Voice-variant:\r
+\r
diff --git a/libs/unimrcp/tests/mrcptest/v1/multi.msg b/libs/unimrcp/tests/mrcptest/v1/multi.msg
new file mode 100644 (file)
index 0000000..8a1f44e
--- /dev/null
@@ -0,0 +1,27 @@
+//speechsynth\r
+GET-PARAMS 543256 MRCP/1.0\r
+Voice-gender:\r
+Voice-variant:\r
+\r
+SET-PARAMS 543256 MRCP/1.0\r
+Voice-gender:female\r
+Voice-variant:3\r
+\r
+SPEAK 543257 MRCP/1.0\r
+Kill-On-Barge-In:false\r
+Voice-gender:neutral\r
+Prosody-volume:medium\r
+Content-Type:application/synthesis+ssml\r
+Content-Length:412\r
+\r
+<?xml version="1.0"?>\r
+<speak>\r
+<paragraph>\r
+       <sentence>You have 4 new messages.</sentence>\r
+       <sentence>The first is from <say-as type="name">Stephanie Williams</say-as> \r
+       <mark name="Stephanie"/> and arrived at <break/>\r
+       <say-as type="time">3:45pm</say-as>.</sentence>\r
+       \r
+       <sentence>The subject is <prosody rate="-20%">ski trip</prosody></sentence>\r
+</paragraph>\r
+</speak>
\ No newline at end of file
diff --git a/libs/unimrcp/tests/mrcptest/v1/pause.msg b/libs/unimrcp/tests/mrcptest/v1/pause.msg
new file mode 100644 (file)
index 0000000..1ba3d79
--- /dev/null
@@ -0,0 +1,3 @@
+//speechsynth\r
+PAUSE 543258 MRCP/1.0\r
+\r
diff --git a/libs/unimrcp/tests/mrcptest/v1/recognitioncomplete.msg b/libs/unimrcp/tests/mrcptest/v1/recognitioncomplete.msg
new file mode 100644 (file)
index 0000000..054700a
--- /dev/null
@@ -0,0 +1,20 @@
+//speechrecog\r
+RECOGNITION-COMPLETE 543257 COMPLETE MRCP/1.0\r
+Completion-Cause:000 success\r
+Waveform-URL:http://web.media.com/session123/audio.wav\r
+Content-Type:application/x-nlsml\r
+Content-Length:446\r
+\r
+  <?xml version="1.0"?>\r
+  <result x-model="http://IdentityModel"\r
+    xmlns:xf="http://www.w3.org/2000/xforms"\r
+    grammar="session:request1@form-level.store">\r
+      <interpretation>\r
+          <xf:instance name="Person">\r
+              <Person>\r
+                  <Name> Andre Roy </Name>\r
+              </Person>\r
+          </xf:instance>\r
+                    <input>   may I speak to Andre Roy </input>\r
+      </interpretation>\r
+  </result>
\ No newline at end of file
diff --git a/libs/unimrcp/tests/mrcptest/v1/recognize.msg b/libs/unimrcp/tests/mrcptest/v1/recognize.msg
new file mode 100644 (file)
index 0000000..0f1c55d
--- /dev/null
@@ -0,0 +1,30 @@
+//speechrecog\r
+RECOGNIZE 543257 MRCP/1.0\r
+Confidence-Threshold:90\r
+Content-Type:application/grammar+xml\r
+Content-Id:request1@form-level.store\r
+Content-Length:608\r
+\r
+<?xml version="1.0"?>\r
+\r
+<!-- the default grammar language is US English -->\r
+<grammar xml:lang="en-US" version="1.0">\r
+\r
+<!-- single language attachment to tokens -->\r
+   <rule id="yes">\r
+       <one-of>\r
+                <item xml:lang="fr-CA">oui</item>\r
+                <item xml:lang="en-US">yes</item>\r
+       </one-of>\r
+   </rule>\r
+\r
+<!-- single language attachment to a rule expansion -->\r
+   <rule id="request">\r
+       may I speak to\r
+       <one-of xml:lang="fr-CA">\r
+                <item>Michel Tremblay</item>\r
+                <item>Andre Roy</item>\r
+       </one-of>\r
+   </rule>\r
+\r
+</grammar>
\ No newline at end of file
diff --git a/libs/unimrcp/tests/mrcptest/v1/response.msg b/libs/unimrcp/tests/mrcptest/v1/response.msg
new file mode 100644 (file)
index 0000000..744fe11
--- /dev/null
@@ -0,0 +1,3 @@
+//speechsynth\r
+MRCP/1.0 543257 200 IN-PROGRESS\r
+\r
diff --git a/libs/unimrcp/tests/mrcptest/v1/resume.msg b/libs/unimrcp/tests/mrcptest/v1/resume.msg
new file mode 100644 (file)
index 0000000..25bd8ab
--- /dev/null
@@ -0,0 +1,3 @@
+//speechsynth\r
+RESUME 543260 MRCP/1.0\r
+\r
diff --git a/libs/unimrcp/tests/mrcptest/v1/setparams.msg b/libs/unimrcp/tests/mrcptest/v1/setparams.msg
new file mode 100644 (file)
index 0000000..4fad0b2
--- /dev/null
@@ -0,0 +1,5 @@
+//speechsynth\r
+SET-PARAMS 543256 MRCP/1.0\r
+Voice-gender:female\r
+Voice-variant:3\r
+\r
diff --git a/libs/unimrcp/tests/mrcptest/v1/speak.msg b/libs/unimrcp/tests/mrcptest/v1/speak.msg
new file mode 100644 (file)
index 0000000..d0f7d38
--- /dev/null
@@ -0,0 +1,19 @@
+//speechsynth\r
+SPEAK 543257 MRCP/1.0\r
+Kill-On-Barge-In:false\r
+Voice-gender:neutral\r
+Prosody-volume:medium\r
+Content-Type:application/synthesis+ssml\r
+Content-Length:412\r
+\r
+<?xml version="1.0"?>\r
+<speak>\r
+<paragraph>\r
+       <sentence>You have 4 new messages.</sentence>\r
+       <sentence>The first is from <say-as type="name">Stephanie Williams</say-as> \r
+       <mark name="Stephanie"/> and arrived at <break/>\r
+       <say-as type="time">3:45pm</say-as>.</sentence>\r
+       \r
+       <sentence>The subject is <prosody rate="-20%">ski trip</prosody></sentence>\r
+</paragraph>\r
+</speak>
\ No newline at end of file
diff --git a/libs/unimrcp/tests/mrcptest/v1/speakcomplete.msg b/libs/unimrcp/tests/mrcptest/v1/speakcomplete.msg
new file mode 100644 (file)
index 0000000..52cadad
--- /dev/null
@@ -0,0 +1,4 @@
+//speechsynth\r
+SPEAK-COMPLETE 543260 COMPLETE MRCP/1.0\r
+Completion-Cause:000 normal\r
+\r
diff --git a/libs/unimrcp/tests/mrcptest/v1/stop.msg b/libs/unimrcp/tests/mrcptest/v1/stop.msg
new file mode 100644 (file)
index 0000000..2f44e1f
--- /dev/null
@@ -0,0 +1,3 @@
+//speechsynth\r
+STOP 543258 MRCP/1.0\r
+\r
diff --git a/libs/unimrcp/tests/mrcptest/v2/definegrammar.msg b/libs/unimrcp/tests/mrcptest/v2/definegrammar.msg
new file mode 100644 (file)
index 0000000..e96d3d3
--- /dev/null
@@ -0,0 +1,30 @@
+MRCP/2.0 865 DEFINE-GRAMMAR 543257\r
+Channel-Identifier:32AECB23433801@speechrecog\r
+Content-Type:application/srgs+xml\r
+Content-ID:<request1@form-level.store>\r
+Content-Length:685\r
+\r
+<?xml version="1.0"?>\r
+\r
+<!-- the default grammar language is US English -->\r
+<grammar xmlns="http://www.w3.org/2001/06/grammar"\r
+        xml:lang="en-US" version="1.0">\r
+\r
+<!-- single language attachment to tokens -->\r
+       <rule id="yes">\r
+           <one-of>\r
+                 <item xml:lang="fr-CA">oui</item>\r
+                 <item xml:lang="en-US">yes</item>\r
+           </one-of>\r
+     </rule>\r
+\r
+<!-- single language attachment to a rule expansion -->\r
+     <rule id="request">\r
+           may I speak to\r
+           <one-of xml:lang="fr-CA">\r
+                 <item>Michel Tremblay</item>\r
+                 <item>Andre Roy</item>\r
+           </one-of>\r
+     </rule>\r
+\r
+</grammar>
\ No newline at end of file
diff --git a/libs/unimrcp/tests/mrcptest/v2/getparams.msg b/libs/unimrcp/tests/mrcptest/v2/getparams.msg
new file mode 100644 (file)
index 0000000..9b02a76
--- /dev/null
@@ -0,0 +1,5 @@
+MRCP/2.0 112 GET-PARAMS 543256\r
+Channel-Identifier:32AECB23433802@speechsynth\r
+Voice-gender:\r
+Voice-variant:\r
+\r
diff --git a/libs/unimrcp/tests/mrcptest/v2/recognitioncomplete.msg b/libs/unimrcp/tests/mrcptest/v2/recognitioncomplete.msg
new file mode 100644 (file)
index 0000000..e68d28f
--- /dev/null
@@ -0,0 +1,20 @@
+MRCP/2.0 616 RECOGNITION-COMPLETE 543257 COMPLETE\r
+Channel-Identifier:32AECB23433801@speechrecog\r
+Completion-Cause:000 success\r
+Waveform-URI:<http://web.media.com/session123/audio.wav>;size=342456;duration=25435\r
+Content-Type:application/nlsml+xml\r
+Content-Length:430\r
+\r
+<?xml version="1.0"?>\r
+<result xmlns="http://www.ietf.org/xml/ns/mrcpv2"\r
+       xmlns:ex="http://www.example.com/example"\r
+       grammar="session:request1@form-level.store">\r
+   <interpretation>\r
+       <instance name="Person">\r
+           <ex:Person>\r
+               <ex:Name> Andre Roy </ex:Name>\r
+           </ex:Person>\r
+       </instance>\r
+       <input>   may I speak to Andre Roy </input>\r
+   </interpretation>\r
+</result>
\ No newline at end of file
diff --git a/libs/unimrcp/tests/mrcptest/v2/recognize.msg b/libs/unimrcp/tests/mrcptest/v2/recognize.msg
new file mode 100644 (file)
index 0000000..e378491
--- /dev/null
@@ -0,0 +1,30 @@
+MRCP/2.0 903 RECOGNIZE 543257\r
+Channel-Identifier:32AECB23433801@speechrecog\r
+Confidence-Threshold:0.9\r
+Content-Type:application/srgs+xml\r
+Content-ID:<request1@form-level.store>\r
+Content-Length:702\r
+\r
+<?xml version="1.0"?>\r
+\r
+<!-- the default grammar language is US English -->\r
+<grammar xmlns="http://www.w3.org/2001/06/grammar"\r
+        xml:lang="en-US" version="1.0" root="request">\r
+\r
+<!-- single language attachment to tokens -->\r
+     <rule id="yes">\r
+           <one-of>\r
+                 <item xml:lang="fr-CA">oui</item>\r
+                 <item xml:lang="en-US">yes</item>\r
+           </one-of>\r
+     </rule>\r
+\r
+<!-- single language attachment to a rule expansion -->\r
+     <rule id="request">\r
+           may I speak to\r
+           <one-of xml:lang="fr-CA">\r
+                 <item>Michel Tremblay</item>\r
+                 <item>Andre Roy</item>\r
+           </one-of>\r
+     </rule>\r
+</grammar>
\ No newline at end of file
diff --git a/libs/unimrcp/tests/mrcptest/v2/setparams.msg b/libs/unimrcp/tests/mrcptest/v2/setparams.msg
new file mode 100644 (file)
index 0000000..02db19e
--- /dev/null
@@ -0,0 +1,5 @@
+MRCP/2.0 119 SET-PARAMS 543256\r
+Channel-Identifier:32AECB23433802@speechsynth\r
+Voice-gender:female\r
+Voice-variant:3\r
+\r
diff --git a/libs/unimrcp/tests/mrcptest/v2/speak.msg b/libs/unimrcp/tests/mrcptest/v2/speak.msg
new file mode 100644 (file)
index 0000000..4c54032
--- /dev/null
@@ -0,0 +1,26 @@
+MRCP/2.0 732 SPEAK 543257\r
+Channel-Identifier:32AECB23433802@speechsynth\r
+Voice-gender:neutral\r
+Voice-Age:25\r
+Prosody-volume:medium\r
+Content-Type:application/ssml+xml\r
+Content-Length:542\r
+\r
+<?xml version="1.0"?>\r
+<speak version="1.0"\r
+       xmlns="http://www.w3.org/2001/10/synthesis"\r
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+       xsi:schemaLocation="http://www.w3.org/2001/10/synthesis\r
+          http://www.w3.org/TR/speech-synthesis/synthesis.xsd"\r
+       xml:lang="en-US">\r
+       <p>\r
+        <s>You have 4 new messages.</s>\r
+        <s>The first is from Stephanie Williams and arrived at\r
+               <break/>\r
+               <say-as interpret-as="vxml:time">0345p</say-as>.\r
+               </s>\r
+        <s>The subject is\r
+                       <prosody rate="-20%">ski trip</prosody>\r
+        </s>\r
+       </p>\r
+</speak>
\ No newline at end of file
diff --git a/libs/unimrcp/tests/mrcptest/v2/speakcomplete.msg b/libs/unimrcp/tests/mrcptest/v2/speakcomplete.msg
new file mode 100644 (file)
index 0000000..2f1cf96
--- /dev/null
@@ -0,0 +1,5 @@
+MRCP/2.0 161 SPEAK-COMPLETE 543257 COMPLETE\r
+Channel-Identifier:32AECB23433802@speechsynth\r
+Completion-Cause:000 normal\r
+Speech-Marker:timestamp=857206027059\r
+\r
diff --git a/libs/unimrcp/tests/mrcptest/v2/stop.msg b/libs/unimrcp/tests/mrcptest/v2/stop.msg
new file mode 100644 (file)
index 0000000..003c767
--- /dev/null
@@ -0,0 +1,3 @@
+MRCP/2.0 74 STOP 543258\r
+Channel-Identifier:32AECB23433802@speechsynth\r
+\r
diff --git a/libs/unimrcp/tests/rtsptest/Makefile.am b/libs/unimrcp/tests/rtsptest/Makefile.am
new file mode 100644 (file)
index 0000000..4821917
--- /dev/null
@@ -0,0 +1,12 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+INCLUDES             = -I$(top_srcdir)/libs/uni-rtsp/include \
+                       -I$(top_srcdir)/libs/apr-toolkit/include \
+                       $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+noinst_PROGRAMS      = rtsptest
+rtsptest_LDADD       = $(top_builddir)/libs/uni-rtsp/libunirtsp.la \
+                       $(top_builddir)/libs/apr-toolkit/libaprtoolkit.la \
+                       $(UNIMRCP_APR_LIBS) $(UNIMRCP_APU_LIBS)
+rtsptest_SOURCES     = src/main.c \
+                       src/parse_gen_suite.c
diff --git a/libs/unimrcp/tests/rtsptest/msg/announce.msg b/libs/unimrcp/tests/rtsptest/msg/announce.msg
new file mode 100644 (file)
index 0000000..142f16c
--- /dev/null
@@ -0,0 +1,24 @@
+ANNOUNCE rtsp://media.server.com/media/synthesizer RTSP/1.0\r
+CSeq:4\r
+Session:12345678\r
+Content-Type:application/mrcp\r
+Content-Length:567\r
+\r
+SPEAK 543257 MRCP/1.0\r
+Kill-On-Barge-In:false\r
+Voice-gender:neutral\r
+Prosody-volume:medium\r
+Content-Type:application/synthesis+ssml\r
+Content-Length:412\r
+\r
+<?xml version="1.0"?>\r
+<speak>\r
+<paragraph>\r
+       <sentence>You have 4 new messages.</sentence>\r
+       <sentence>The first is from <say-as type="name">Stephanie Williams</say-as> \r
+       <mark name="Stephanie"/> and arrived at <break/>\r
+       <say-as type="time">3:45pm</say-as>.</sentence>\r
+       \r
+       <sentence>The subject is <prosody rate="-20%">ski trip</prosody></sentence>\r
+</paragraph>\r
+</speak>
\ No newline at end of file
diff --git a/libs/unimrcp/tests/rtsptest/msg/ok.msg b/libs/unimrcp/tests/rtsptest/msg/ok.msg
new file mode 100644 (file)
index 0000000..b88ac1c
--- /dev/null
@@ -0,0 +1,16 @@
+RTSP/1.0 200 OK\r
+CSeq:2\r
+Transport:RTP/AVP;unicast;client_port=46456-46457;server_port=46460-46461\r
+Session:12345678\r
+Content-Length:188\r
+Content-Type:application/sdp\r
+\r
+v=0\r
+o=- 3211724219 3211724219 IN IP4 10.3.2.88\r
+s=Media Server\r
+c=IN IP4 0.0.0.0\r
+t=0 0\r
+m=audio 46460 RTP/AVP 0 96\r
+a=rtpmap:0 pcmu/8000\r
+a=rtpmap:96 telephone-event/8000\r
+a=fmtp:96 0-15
\ No newline at end of file
diff --git a/libs/unimrcp/tests/rtsptest/msg/re-ok.msg b/libs/unimrcp/tests/rtsptest/msg/re-ok.msg
new file mode 100644 (file)
index 0000000..2b8dd75
--- /dev/null
@@ -0,0 +1,6 @@
+RTSP/1.0 200 OK\r
+CSeq:3\r
+Transport:RTP/AVP;unicast;client_port=46456-46457;\r
+         server_port=46460-46461;mode=record;ttl=127\r
+Session:12345678\r
+\r
diff --git a/libs/unimrcp/tests/rtsptest/msg/re-setup.msg b/libs/unimrcp/tests/rtsptest/msg/re-setup.msg
new file mode 100644 (file)
index 0000000..288ef23
--- /dev/null
@@ -0,0 +1,6 @@
+SETUP rtsp://media.server.com/media/recognizer RTSP/1.0\r
+CSeq:3\r
+Transport:RTP/AVP;unicast;client_port=46456-46457;\r
+         mode=record;ttl=127\r
+Session:12345678;timeout=200\r
+\r
diff --git a/libs/unimrcp/tests/rtsptest/msg/setup.msg b/libs/unimrcp/tests/rtsptest/msg/setup.msg
new file mode 100644 (file)
index 0000000..1606500
--- /dev/null
@@ -0,0 +1,16 @@
+SETUP rtsp://media.server.com/media/synthesizer RTSP/1.0\r
+CSeq:2\r
+Transport:RTP/AVP;unicast;client_port=46456-46457\r
+Content-Type:application/sdp\r
+Content-Length:188\r
+\r
+v=0\r
+o=- 123 456 IN IP4 10.0.0.1\r
+s=Media Server\r
+p=+1-888-555-1212\r
+c=IN IP4 0.0.0.0\r
+t=0 0\r
+m=audio 0 RTP/AVP 0 96\r
+a=rtpmap:0 pcmu/8000\r
+a=rtpmap:96 telephone-event/8000\r
+a=fmtp:96 0-15
\ No newline at end of file
diff --git a/libs/unimrcp/tests/rtsptest/msg/teardown.msg b/libs/unimrcp/tests/rtsptest/msg/teardown.msg
new file mode 100644 (file)
index 0000000..f673a0c
--- /dev/null
@@ -0,0 +1,4 @@
+TEARDOWN rtsp://media.server.com/media/synthesizer RTSP/1.0\r
+CSeq:12\r
+Session:12345678\r
+\r
diff --git a/libs/unimrcp/tests/rtsptest/msg/ultimate.msg b/libs/unimrcp/tests/rtsptest/msg/ultimate.msg
new file mode 100644 (file)
index 0000000..bac7ffe
--- /dev/null
@@ -0,0 +1,46 @@
+RTSP/1.0 200 OK\r
+CSeq:3\r
+Transport:RTP/AVP;unicast;client_port=46456-46457;\r
+         server_port=46460-46461;mode=record;ttl=127\r
+Session:12345678\r
+\r
+SETUP rtsp://media.server.com/media/synthesizer RTSP/1.0\r
+CSeq:2\r
+Transport:RTP/AVP;unicast;client_port=46456-46457\r
+Content-Type:application/sdp\r
+Content-Length:190\r
+\r
+v=0\r
+o=- 123 456 IN IP4 10.0.0.1\r
+s=Media Server\r
+p=+1-888-555-1212\r
+c=IN IP4 0.0.0.0\r
+t=0 0\r
+m=audio 0 RTP/AVP 0 96\r
+a=rtpmap:0 pcmu/8000\r
+a=rtpmap:96 telephone-event/8000\r
+a=fmtp:96 0-15\r
+ANNOUNCE rtsp://media.server.com/media/synthesizer RTSP/1.0\r
+CSeq:4\r
+Session:12345678\r
+Content-Type:application/mrcp\r
+Content-Length:567\r
+\r
+SPEAK 543257 MRCP/1.0\r
+Kill-On-Barge-In:false\r
+Voice-gender:neutral\r
+Prosody-volume:medium\r
+Content-Type:application/synthesis+ssml\r
+Content-Length:412\r
+\r
+<?xml version="1.0"?>\r
+<speak>\r
+<paragraph>\r
+       <sentence>You have 4 new messages.</sentence>\r
+       <sentence>The first is from <say-as type="name">Stephanie Williams</say-as> \r
+       <mark name="Stephanie"/> and arrived at <break/>\r
+       <say-as type="time">3:45pm</say-as>.</sentence>\r
+       \r
+       <sentence>The subject is <prosody rate="-20%">ski trip</prosody></sentence>\r
+</paragraph>\r
+</speak>
\ No newline at end of file
diff --git a/libs/unimrcp/tests/rtsptest/rtsptest.vcproj b/libs/unimrcp/tests/rtsptest/rtsptest.vcproj
new file mode 100644 (file)
index 0000000..b5ebf45
--- /dev/null
@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="rtsptest"
+       ProjectGUID="{17A33F3F-BAF5-403F-8EF4-FECDA7D9A335}"
+       RootNamespace="rtsptest"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\unirtsp.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="unirtsp.lib aprtoolkit.lib libaprutil-1.lib libapr-1.lib"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\unirtsp.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="unirtsp.lib aprtoolkit.lib libaprutil-1.lib libapr-1.lib"
+                               LinkTimeCodeGeneration="1"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+                       >
+                       <File
+                               RelativePath=".\src\main.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\parse_gen_suite.c"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/tests/rtsptest/src/main.c b/libs/unimrcp/tests/rtsptest/src/main.c
new file mode 100644 (file)
index 0000000..9627085
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apt_test_suite.h"
+#include "apt_log.h"
+
+apt_test_suite_t* parse_gen_test_suite_create(apr_pool_t *pool);
+
+int main(int argc, const char * const *argv)
+{
+       apt_test_framework_t *test_framework;
+       apt_test_suite_t *test_suite;
+       apr_pool_t *pool;
+       
+       /* one time apr global initialization */
+       if(apr_initialize() != APR_SUCCESS) {
+               return 0;
+       }
+
+       /* create test framework */
+       test_framework = apt_test_framework_create();
+       pool = apt_test_framework_pool_get(test_framework);
+
+       /* create test suites and add them to test framework */
+       test_suite = parse_gen_test_suite_create(pool);
+       apt_test_framework_suite_add(test_framework,test_suite);
+
+       /* run tests */
+       apt_test_framework_run(test_framework,argc,argv);
+
+       /* destroy test framework */
+       apt_test_framework_destroy(test_framework);
+
+       /* final apr global termination */
+       apr_terminate();
+       return 0;
+}
diff --git a/libs/unimrcp/tests/rtsptest/src/parse_gen_suite.c b/libs/unimrcp/tests/rtsptest/src/parse_gen_suite.c
new file mode 100644 (file)
index 0000000..c88ac6f
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr_file_info.h>
+#include <apr_file_io.h>
+#include "apt_test_suite.h"
+#include "apt_log.h"
+#include "rtsp_stream.h"
+
+static apt_bool_t test_stream_generate(rtsp_generator_t *generator, rtsp_message_t *message)
+{
+       char buffer[500];
+       apt_text_stream_t stream;
+       rtsp_stream_result_e result;
+       apt_bool_t continuation;
+
+       rtsp_generator_message_set(generator,message);
+       do {
+               apt_text_stream_init(&stream,buffer,sizeof(buffer)-1);
+               continuation = FALSE;
+               result = rtsp_generator_run(generator,&stream);
+               if(result == RTSP_STREAM_MESSAGE_COMPLETE) {
+                       stream.text.length = stream.pos - stream.text.buf;
+                       *stream.pos = '\0';
+                       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Generated RTSP Stream [%lu bytes]\n%s",stream.text.length,stream.text.buf);
+               }
+               else if(result == RTSP_STREAM_MESSAGE_TRUNCATED) {
+                       *stream.pos = '\0';
+                       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Generated RTSP Stream [%lu bytes] continuation awaiting\n%s",stream.text.length,stream.text.buf);
+                       continuation = TRUE;
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Generate RTSP Stream");
+               }
+       }
+       while(continuation == TRUE);
+       return TRUE;
+}
+
+static apt_bool_t rtsp_message_handler(void *obj, rtsp_message_t *message, rtsp_stream_result_e result)
+{
+       if(result == RTSP_STREAM_MESSAGE_COMPLETE) {
+               /* message is completely parsed */
+               rtsp_generator_t *generator = obj;
+               test_stream_generate(generator,message);
+       }
+       return TRUE;
+}
+
+static apt_bool_t test_file_process(apt_test_suite_t *suite, const char *file_path)
+{
+       apr_file_t *file;
+       char buffer[500];
+       apt_text_stream_t stream;
+       rtsp_parser_t *parser;
+       rtsp_generator_t *generator;
+       apr_size_t length;
+       apr_size_t offset;
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open File [%s]",file_path);
+       if(apr_file_open(&file,file_path,APR_FOPEN_READ | APR_FOPEN_BINARY,APR_OS_DEFAULT,suite->pool) != APR_SUCCESS) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Open File");
+               return FALSE;
+       }
+
+       parser = rtsp_parser_create(suite->pool);
+       generator = rtsp_generator_create(suite->pool);
+
+       apt_text_stream_init(&stream,buffer,sizeof(buffer)-1);
+
+       do {
+               /* init length of the stream */
+               stream.text.length = sizeof(buffer)-1;
+               /* calculate offset remaining from the previous receive / if any */
+               offset = stream.pos - stream.text.buf;
+               /* calculate available length */
+               length = stream.text.length - offset;
+
+               if(apr_file_read(file,stream.pos,&length) != APR_SUCCESS) {
+                       break;
+               }
+               /* calculate actual length of the stream */
+               stream.text.length = offset + length;
+               stream.pos[length] = '\0';
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Parse RTSP Stream [%lu bytes]\n%s",length,stream.pos);
+               
+               /* reset pos */
+               stream.pos = stream.text.buf;
+               rtsp_stream_walk(parser,&stream,rtsp_message_handler,generator);
+       }
+       while(apr_file_eof(file) != APR_EOF);
+
+       apr_file_close(file);
+       return TRUE;
+}
+
+static apt_bool_t test_dir_process(apt_test_suite_t *suite)
+{
+       apr_status_t rv;
+       apr_dir_t *dir;
+
+       const char *dir_name = "msg";
+       if(apr_dir_open(&dir,dir_name,suite->pool) != APR_SUCCESS) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot Open Directory [%s]",dir_name);
+               return FALSE;
+       }
+
+       do {
+               apr_finfo_t finfo;
+               rv = apr_dir_read(&finfo,APR_FINFO_DIRENT,dir);
+               if(rv == APR_SUCCESS) {
+                       if(finfo.filetype == APR_REG && finfo.name) {
+                               char *file_path;
+                               apr_filepath_merge(&file_path,dir_name,finfo.name,0,suite->pool);
+                               test_file_process(suite,file_path);
+                               printf("\nPress ENTER to continue\n");
+                               getchar();
+                       }
+               }
+       } 
+       while(rv == APR_SUCCESS);
+
+       apr_dir_close(dir);
+       return TRUE;
+}
+
+static apt_bool_t parse_gen_test_run(apt_test_suite_t *suite, int argc, const char * const *argv)
+{
+       test_dir_process(suite);
+       return TRUE;
+}
+
+apt_test_suite_t* parse_gen_test_suite_create(apr_pool_t *pool)
+{
+       apt_test_suite_t *suite = apt_test_suite_create(pool,"parse-gen",NULL,parse_gen_test_run);
+       return suite;
+}
diff --git a/libs/unimrcp/tests/sipp/mrcp_uac_multi b/libs/unimrcp/tests/sipp/mrcp_uac_multi
new file mode 100644 (file)
index 0000000..5b2cbda
--- /dev/null
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+
+<scenario name="MRCP Multiple Resources UAC">
+  <!-- In client mode (sipp placing calls), the Call-ID MUST be         -->
+  <!-- generated by sipp. To do so, use [call_id] token.                -->
+  <send retrans="500">
+    <![CDATA[
+
+      INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+      From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+      To: sut <sip:[service]@[remote_ip]:[remote_port]>
+      Call-ID: [call_id]
+      CSeq: 1 INVITE
+      Contact: sip:sipp@[local_ip]:[local_port]
+      Max-Forwards: 70
+      Subject: Performance Test
+      Content-Type: application/sdp
+      Content-Length: [len]
+
+      v=0
+      o=user1 53655765 2353687637 IN IP4 [local_ip]
+      s=-
+      c=IN IP4 [media_ip]
+      t=0 0
+      m=application 9 TCP/MRCPv2 1
+      a=setup:active
+      a=connection:new
+      a=resource:speechsynth
+      a=cmid:1
+      m=application 9 TCP/MRCPv2 1
+      a=setup:active
+      a=connection:new
+      a=resource:speechrecog
+      a=cmid:1
+      m=audio [media_port] RTP/AVP 0 8
+      a=sendrecv
+      a=mid:1
+
+       ]]>
+  </send>
+
+  <recv response="100"
+        optional="true">
+  </recv>
+
+  <recv response="180" optional="true">
+  </recv>
+
+  <!-- By adding rrs="true" (Record Route Sets), the route sets         -->
+  <!-- are saved and used for following messages sent. Useful to test   -->
+  <!-- against stateful SIP proxies/B2BUAs.                             -->
+  <recv response="200" rtd="true">
+  </recv>
+
+  <!-- Packet lost can be simulated in any send/recv message by         -->
+  <!-- by adding the 'lost = "10"'. Value can be [1-100] percent.       -->
+  <send>
+    <![CDATA[
+
+      ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+      From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+      To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+      Call-ID: [call_id]
+      CSeq: 1 ACK
+      Contact: sip:sipp@[local_ip]:[local_port]
+      Max-Forwards: 70
+      Subject: Performance Test
+      Content-Length: 0
+
+    ]]>
+  </send>
+
+  <!-- This delay can be customized by the -d command-line option       -->
+  <!-- or by adding a 'milliseconds = "value"' option here.             -->
+  <pause/>
+
+  <!-- The 'crlf' option inserts a blank line in the statistics report. -->
+  <send retrans="500">
+    <![CDATA[
+
+      BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+      From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+      To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+      Call-ID: [call_id]
+      CSeq: 2 BYE
+      Contact: sip:sipp@[local_ip]:[local_port]
+      Max-Forwards: 70
+      Subject: Performance Test
+      Content-Length: 0
+
+    ]]>
+  </send>
+
+  <recv response="200" crlf="true">
+  </recv>
+
+  <!-- definition of the response time repartition table (unit is ms)   -->
+  <ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
+
+  <!-- definition of the call length repartition table (unit is ms)     -->
+  <CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
+
+</scenario>
diff --git a/libs/unimrcp/tests/sipp/mrcp_uac_recog b/libs/unimrcp/tests/sipp/mrcp_uac_recog
new file mode 100644 (file)
index 0000000..13ea1f4
--- /dev/null
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+
+<scenario name="MRCP Recognizer Resource UAC">
+  <!-- In client mode (sipp placing calls), the Call-ID MUST be         -->
+  <!-- generated by sipp. To do so, use [call_id] token.                -->
+  <send retrans="500">
+    <![CDATA[
+
+      INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+      From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+      To: sut <sip:[service]@[remote_ip]:[remote_port]>
+      Call-ID: [call_id]
+      CSeq: 1 INVITE
+      Contact: sip:sipp@[local_ip]:[local_port]
+      Max-Forwards: 70
+      Subject: Performance Test
+      Content-Type: application/sdp
+      Content-Length: [len]
+
+      v=0
+      o=user1 53655765 2353687637 IN IP4 [local_ip]
+      s=-
+      c=IN IP4 [media_ip]
+      t=0 0
+      m=application 9 TCP/MRCPv2 1
+      a=setup:active
+      a=connection:new
+      a=resource:speechrecog
+      a=cmid:1
+      m=audio [media_port] RTP/AVP 0 8
+      a=sendonly
+      a=mid:1
+
+       ]]>
+  </send>
+
+  <recv response="100"
+        optional="true">
+  </recv>
+
+  <recv response="180" optional="true">
+  </recv>
+
+  <!-- By adding rrs="true" (Record Route Sets), the route sets         -->
+  <!-- are saved and used for following messages sent. Useful to test   -->
+  <!-- against stateful SIP proxies/B2BUAs.                             -->
+  <recv response="200" rtd="true">
+  </recv>
+
+  <!-- Packet lost can be simulated in any send/recv message by         -->
+  <!-- by adding the 'lost = "10"'. Value can be [1-100] percent.       -->
+  <send>
+    <![CDATA[
+
+      ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+      From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+      To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+      Call-ID: [call_id]
+      CSeq: 1 ACK
+      Contact: sip:sipp@[local_ip]:[local_port]
+      Max-Forwards: 70
+      Subject: Performance Test
+      Content-Length: 0
+
+    ]]>
+  </send>
+
+  <!-- This delay can be customized by the -d command-line option       -->
+  <!-- or by adding a 'milliseconds = "value"' option here.             -->
+  <pause/>
+
+  <!-- The 'crlf' option inserts a blank line in the statistics report. -->
+  <send retrans="500">
+    <![CDATA[
+
+      BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+      From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+      To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+      Call-ID: [call_id]
+      CSeq: 2 BYE
+      Contact: sip:sipp@[local_ip]:[local_port]
+      Max-Forwards: 70
+      Subject: Performance Test
+      Content-Length: 0
+
+    ]]>
+  </send>
+
+  <recv response="200" crlf="true">
+  </recv>
+
+  <!-- definition of the response time repartition table (unit is ms)   -->
+  <ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
+
+  <!-- definition of the call length repartition table (unit is ms)     -->
+  <CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
+
+</scenario>
diff --git a/libs/unimrcp/tests/sipp/mrcp_uac_synth b/libs/unimrcp/tests/sipp/mrcp_uac_synth
new file mode 100644 (file)
index 0000000..627c889
--- /dev/null
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+
+<scenario name="MRCP Synthesizer Resource UAC">
+  <!-- In client mode (sipp placing calls), the Call-ID MUST be         -->
+  <!-- generated by sipp. To do so, use [call_id] token.                -->
+  <send retrans="500">
+    <![CDATA[
+
+      INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+      From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+      To: sut <sip:[service]@[remote_ip]:[remote_port]>
+      Call-ID: [call_id]
+      CSeq: 1 INVITE
+      Contact: sip:sipp@[local_ip]:[local_port]
+      Max-Forwards: 70
+      Subject: Performance Test
+      Content-Type: application/sdp
+      Content-Length: [len]
+
+      v=0
+      o=user1 53655765 2353687637 IN IP4 [local_ip]
+      s=-
+      c=IN IP4 [media_ip]
+      t=0 0
+      m=application 9 TCP/MRCPv2 1
+      a=setup:active
+      a=connection:new
+      a=resource:speechsynth
+      a=cmid:1
+      m=audio [media_port] RTP/AVP 0 8
+      a=recvonly
+      a=mid:1
+
+       ]]>
+  </send>
+
+  <recv response="100"
+        optional="true">
+  </recv>
+
+  <recv response="180" optional="true">
+  </recv>
+
+  <!-- By adding rrs="true" (Record Route Sets), the route sets         -->
+  <!-- are saved and used for following messages sent. Useful to test   -->
+  <!-- against stateful SIP proxies/B2BUAs.                             -->
+  <recv response="200" rtd="true">
+  </recv>
+
+  <!-- Packet lost can be simulated in any send/recv message by         -->
+  <!-- by adding the 'lost = "10"'. Value can be [1-100] percent.       -->
+  <send>
+    <![CDATA[
+
+      ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+      From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+      To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+      Call-ID: [call_id]
+      CSeq: 1 ACK
+      Contact: sip:sipp@[local_ip]:[local_port]
+      Max-Forwards: 70
+      Subject: Performance Test
+      Content-Length: 0
+
+    ]]>
+  </send>
+
+  <!-- This delay can be customized by the -d command-line option       -->
+  <!-- or by adding a 'milliseconds = "value"' option here.             -->
+  <pause/>
+
+  <!-- The 'crlf' option inserts a blank line in the statistics report. -->
+  <send retrans="500">
+    <![CDATA[
+
+      BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+      From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+      To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+      Call-ID: [call_id]
+      CSeq: 2 BYE
+      Contact: sip:sipp@[local_ip]:[local_port]
+      Max-Forwards: 70
+      Subject: Performance Test
+      Content-Length: 0
+
+    ]]>
+  </send>
+
+  <recv response="200" crlf="true">
+  </recv>
+
+  <!-- definition of the response time repartition table (unit is ms)   -->
+  <ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
+
+  <!-- definition of the call length repartition table (unit is ms)     -->
+  <CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
+
+</scenario>
diff --git a/libs/unimrcp/tests/sipp/mrcp_uac_unknown b/libs/unimrcp/tests/sipp/mrcp_uac_unknown
new file mode 100644 (file)
index 0000000..190d924
--- /dev/null
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+
+<scenario name="MRCP Unknown Resource UAC">
+  <!-- In client mode (sipp placing calls), the Call-ID MUST be         -->
+  <!-- generated by sipp. To do so, use [call_id] token.                -->
+  <send retrans="500">
+    <![CDATA[
+
+      INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+      From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+      To: sut <sip:[service]@[remote_ip]:[remote_port]>
+      Call-ID: [call_id]
+      CSeq: 1 INVITE
+      Contact: sip:sipp@[local_ip]:[local_port]
+      Max-Forwards: 70
+      Subject: Performance Test
+      Content-Type: application/sdp
+      Content-Length: [len]
+
+      v=0
+      o=user1 53655765 2353687637 IN IP4 [local_ip]
+      s=-
+      c=IN IP4 [media_ip]
+      t=0 0
+      m=application 9 TCP/MRCPv2 1
+      a=setup:active
+      a=connection:new
+      a=resource:unknown
+      a=cmid:1
+      m=audio [media_port] RTP/AVP 0 8
+      a=mid:1
+
+       ]]>
+  </send>
+
+  <recv response="100"
+        optional="true">
+  </recv>
+
+  <recv response="180" optional="true">
+  </recv>
+
+  <!-- By adding rrs="true" (Record Route Sets), the route sets         -->
+  <!-- are saved and used for following messages sent. Useful to test   -->
+  <!-- against stateful SIP proxies/B2BUAs.                             -->
+  <recv response="200" rtd="true">
+  </recv>
+
+  <!-- Packet lost can be simulated in any send/recv message by         -->
+  <!-- by adding the 'lost = "10"'. Value can be [1-100] percent.       -->
+  <send>
+    <![CDATA[
+
+      ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+      From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+      To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+      Call-ID: [call_id]
+      CSeq: 1 ACK
+      Contact: sip:sipp@[local_ip]:[local_port]
+      Max-Forwards: 70
+      Subject: Performance Test
+      Content-Length: 0
+
+    ]]>
+  </send>
+
+  <!-- This delay can be customized by the -d command-line option       -->
+  <!-- or by adding a 'milliseconds = "value"' option here.             -->
+  <pause/>
+
+  <!-- The 'crlf' option inserts a blank line in the statistics report. -->
+  <send retrans="500">
+    <![CDATA[
+
+      BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+      From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+      To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+      Call-ID: [call_id]
+      CSeq: 2 BYE
+      Contact: sip:sipp@[local_ip]:[local_port]
+      Max-Forwards: 70
+      Subject: Performance Test
+      Content-Length: 0
+
+    ]]>
+  </send>
+
+  <recv response="200" crlf="true">
+  </recv>
+
+  <!-- definition of the response time repartition table (unit is ms)   -->
+  <ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
+
+  <!-- definition of the call length repartition table (unit is ms)     -->
+  <CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
+
+</scenario>
diff --git a/libs/unimrcp/tests/sipp/mrcp_uac_update b/libs/unimrcp/tests/sipp/mrcp_uac_update
new file mode 100644 (file)
index 0000000..da91fee
--- /dev/null
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+
+<scenario name="MRCP Synthesizer/Recognizer Resources UAC">
+  <!-- In client mode (sipp placing calls), the Call-ID MUST be         -->
+  <!-- generated by sipp. To do so, use [call_id] token.                -->
+  <send retrans="500">
+    <![CDATA[
+
+      INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+      From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+      To: sut <sip:[service]@[remote_ip]:[remote_port]>
+      Call-ID: [call_id]
+      CSeq: 1 INVITE
+      Contact: sip:sipp@[local_ip]:[local_port]
+      Max-Forwards: 70
+      Subject: Performance Test
+      Content-Type: application/sdp
+      Content-Length: [len]
+
+      v=0
+      o=user1 53655765 2353687637 IN IP4 [local_ip]
+      s=-
+      c=IN IP4 [media_ip]
+      t=0 0
+      m=application 9 TCP/MRCPv2 1
+      a=setup:active
+      a=connection:new
+      a=resource:speechsynth
+      a=cmid:1
+      m=audio [media_port] RTP/AVP 0 8
+      a=recvonly
+      a=mid:1
+
+       ]]>
+  </send>
+
+  <recv response="100"
+        optional="true">
+  </recv>
+
+  <recv response="180" optional="true">
+  </recv>
+
+  <!-- By adding rrs="true" (Record Route Sets), the route sets         -->
+  <!-- are saved and used for following messages sent. Useful to test   -->
+  <!-- against stateful SIP proxies/B2BUAs.                             -->
+  <recv response="200" rtd="true">
+  </recv>
+
+  <!-- Packet lost can be simulated in any send/recv message by         -->
+  <!-- by adding the 'lost = "10"'. Value can be [1-100] percent.       -->
+  <send>
+    <![CDATA[
+
+      ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+      From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+      To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+      Call-ID: [call_id]
+      CSeq: 1 ACK
+      Contact: sip:sipp@[local_ip]:[local_port]
+      Max-Forwards: 70
+      Subject: Performance Test
+      Content-Length: 0
+
+    ]]>
+  </send>
+
+  <!-- This delay can be customized by the -d command-line option       -->
+  <!-- or by adding a 'milliseconds = "value"' option here.             -->
+  <pause/>
+
+  <!-- In client mode (sipp placing calls), the Call-ID MUST be         -->
+  <!-- generated by sipp. To do so, use [call_id] token.                -->
+  <send retrans="500">
+    <![CDATA[
+
+      INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+      From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+      To: sut <sip:[service]@[remote_ip]:[remote_port]>
+      Call-ID: [call_id]
+      CSeq: 1 INVITE
+      Contact: sip:sipp@[local_ip]:[local_port]
+      Max-Forwards: 70
+      Subject: Performance Test
+      Content-Type: application/sdp
+      Content-Length: [len]
+
+      v=0
+      o=user1 53655765 2353687637 IN IP4 [local_ip]
+      s=-
+      c=IN IP4 [media_ip]
+      t=0 0
+      m=application 9 TCP/MRCPv2 1
+      a=setup:active
+      a=connection:new
+      a=resource:speechsynth
+      a=cmid:1
+      m=audio [media_port] RTP/AVP 0 8
+      a=sendrecv
+      a=mid:1
+      m=application 9 TCP/MRCPv2 1
+      a=setup:active
+      a=connection:existing
+      a=resource:speechrecog
+      a=cmid:1
+
+       ]]>
+  </send>
+
+  <recv response="100"
+        optional="true">
+  </recv>
+
+  <recv response="180" optional="true">
+  </recv>
+
+  <!-- By adding rrs="true" (Record Route Sets), the route sets         -->
+  <!-- are saved and used for following messages sent. Useful to test   -->
+  <!-- against stateful SIP proxies/B2BUAs.                             -->
+  <recv response="200" rtd="true">
+  </recv>
+
+  <!-- Packet lost can be simulated in any send/recv message by         -->
+  <!-- by adding the 'lost = "10"'. Value can be [1-100] percent.       -->
+  <send>
+    <![CDATA[
+
+      ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+      From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+      To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+      Call-ID: [call_id]
+      CSeq: 1 ACK
+      Contact: sip:sipp@[local_ip]:[local_port]
+      Max-Forwards: 70
+      Subject: Performance Test
+      Content-Length: 0
+
+    ]]>
+  </send>
+
+  <!-- This delay can be customized by the -d command-line option       -->
+  <!-- or by adding a 'milliseconds = "value"' option here.             -->
+  <pause/>
+
+
+  <!-- The 'crlf' option inserts a blank line in the statistics report. -->
+  <send retrans="500">
+    <![CDATA[
+
+      BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+      From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+      To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+      Call-ID: [call_id]
+      CSeq: 2 BYE
+      Contact: sip:sipp@[local_ip]:[local_port]
+      Max-Forwards: 70
+      Subject: Performance Test
+      Content-Length: 0
+
+    ]]>
+  </send>
+
+  <recv response="200" crlf="true">
+  </recv>
+
+  <!-- definition of the response time repartition table (unit is ms)   -->
+  <ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
+
+  <!-- definition of the call length repartition table (unit is ms)     -->
+  <CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
+
+</scenario>
diff --git a/libs/unimrcp/tests/sipp/mrcp_uas_recog b/libs/unimrcp/tests/sipp/mrcp_uas_recog
new file mode 100644 (file)
index 0000000..27bc361
--- /dev/null
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+
+<scenario name="MRCP Recognizer Resource UAS">
+  <!-- By adding rrs="true" (Record Route Sets), the route sets         -->
+  <!-- are saved and used for following messages sent. Useful to test   -->
+  <!-- against stateful SIP proxies/B2BUAs.                             -->
+  <recv request="INVITE" crlf="true">
+  </recv>
+
+  <!-- The '[last_*]' keyword is replaced automatically by the          -->
+  <!-- specified header if it was present in the last message received  -->
+  <!-- (except if it was a retransmission). If the header was not       -->
+  <!-- present or if no message has been received, the '[last_*]'       -->
+  <!-- keyword is discarded, and all bytes until the end of the line    -->
+  <!-- are also discarded.                                              -->
+  <!--                                                                  -->
+  <!-- If the specified header was present several times in the         -->
+  <!-- message, all occurences are concatenated (CRLF seperated)        -->
+  <!-- to be used in place of the '[last_*]' keyword.                   -->
+
+  <send retrans="500">
+    <![CDATA[
+
+      SIP/2.0 200 OK
+      [last_Via:]
+      [last_From:]
+      [last_To:];tag=[call_number]
+      [last_Call-ID:]
+      [last_CSeq:]
+      Contact: <sip:[local_ip]:[local_port];transport=[transport]>
+      Content-Type: application/sdp
+      Content-Length: [len]
+
+      v=0
+      o=user1 53655765 2353687637 IN IP4 [local_ip]
+      s=-
+      c=IN IP4 [media_ip]
+      t=0 0
+      m=application 1050 TCP/MRCPv2 1
+      a=setup:passive
+      a=connection:new
+      a=channel:dca48cf082dd584b@speechrecog
+      a=cmid:1
+      m=audio [media_port] RTP/AVP 0 8
+      a=recvonly
+      a=mid:1
+
+    ]]>
+  </send>
+
+  <recv request="ACK"
+        optional="true"
+        rtd="true"
+        crlf="true">
+  </recv>
+
+  <recv request="INVITE" crlf="true">
+  </recv>
+
+  <send retrans="500">
+    <![CDATA[
+
+      SIP/2.0 200 OK
+      [last_Via:]
+      [last_From:]
+      [last_To:];tag=[call_number]
+      [last_Call-ID:]
+      [last_CSeq:]
+      Contact: <sip:[local_ip]:[local_port];transport=[transport]>
+      Content-Type: application/sdp
+      Content-Length: [len]
+
+      v=0
+      o=user1 53655765 2353687637 IN IP4 [local_ip]
+      s=-
+      c=IN IP4 [media_ip]
+      t=0 0
+      m=application 0 TCP/MRCPv2 1
+      a=setup:passive
+      a=connection:existing
+      a=channel:dca48cf082dd584b@speechrecog
+      a=cmid:1
+      m=audio 0 RTP/AVP 0 8
+      a=recvonly
+      a=mid:1
+
+    ]]>
+  </send>
+
+  <recv request="ACK"
+        optional="true"
+        rtd="true"
+        crlf="true">
+  </recv>
+
+  <recv request="BYE">
+  </recv>
+
+  <send>
+    <![CDATA[
+
+      SIP/2.0 200 OK
+      [last_Via:]
+      [last_From:]
+      [last_To:]
+      [last_Call-ID:]
+      [last_CSeq:]
+      Contact: <sip:[local_ip]:[local_port];transport=[transport]>
+      Content-Length: 0
+
+    ]]>
+  </send>
+
+  <!-- Keep the call open for a while in case the 200 is lost to be     -->
+  <!-- able to retransmit it if we receive the BYE again.               -->
+  <pause milliseconds="4000"/>
+
+
+  <!-- definition of the response time repartition table (unit is ms)   -->
+  <ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
+
+  <!-- definition of the call length repartition table (unit is ms)     -->
+  <CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
+
+</scenario>
diff --git a/libs/unimrcp/tests/sipp/mrcp_uas_reject b/libs/unimrcp/tests/sipp/mrcp_uas_reject
new file mode 100644 (file)
index 0000000..5f6af6b
--- /dev/null
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+
+<scenario name="MRCP Rejected Offer UAS">
+  <!-- By adding rrs="true" (Record Route Sets), the route sets         -->
+  <!-- are saved and used for following messages sent. Useful to test   -->
+  <!-- against stateful SIP proxies/B2BUAs.                             -->
+  <recv request="INVITE" crlf="true">
+  </recv>
+
+  <!-- The '[last_*]' keyword is replaced automatically by the          -->
+  <!-- specified header if it was present in the last message received  -->
+  <!-- (except if it was a retransmission). If the header was not       -->
+  <!-- present or if no message has been received, the '[last_*]'       -->
+  <!-- keyword is discarded, and all bytes until the end of the line    -->
+  <!-- are also discarded.                                              -->
+  <!--                                                                  -->
+  <!-- If the specified header was present several times in the         -->
+  <!-- message, all occurences are concatenated (CRLF seperated)        -->
+  <!-- to be used in place of the '[last_*]' keyword.                   -->
+
+  <send retrans="500">
+    <![CDATA[
+
+      SIP/2.0 404 OK
+      [last_Via:]
+      [last_From:]
+      [last_To:];tag=[call_number]
+      [last_Call-ID:]
+      [last_CSeq:]
+      Contact: <sip:[local_ip]:[local_port];transport=[transport]>
+      Content-Length: 0
+    ]]>
+  </send>
+
+  <recv request="ACK"
+        optional="true"
+        rtd="true"
+        crlf="true">
+  </recv>
+
+  <!-- definition of the response time repartition table (unit is ms)   -->
+  <ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
+
+  <!-- definition of the call length repartition table (unit is ms)     -->
+  <CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
+
+</scenario>
diff --git a/libs/unimrcp/tests/sipp/mrcp_uas_synth b/libs/unimrcp/tests/sipp/mrcp_uas_synth
new file mode 100644 (file)
index 0000000..b2400aa
--- /dev/null
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+
+<scenario name="MRCP Synthesizer Resource UAS">
+  <!-- By adding rrs="true" (Record Route Sets), the route sets         -->
+  <!-- are saved and used for following messages sent. Useful to test   -->
+  <!-- against stateful SIP proxies/B2BUAs.                             -->
+  <recv request="INVITE" crlf="true">
+  </recv>
+
+  <!-- The '[last_*]' keyword is replaced automatically by the          -->
+  <!-- specified header if it was present in the last message received  -->
+  <!-- (except if it was a retransmission). If the header was not       -->
+  <!-- present or if no message has been received, the '[last_*]'       -->
+  <!-- keyword is discarded, and all bytes until the end of the line    -->
+  <!-- are also discarded.                                              -->
+  <!--                                                                  -->
+  <!-- If the specified header was present several times in the         -->
+  <!-- message, all occurences are concatenated (CRLF seperated)        -->
+  <!-- to be used in place of the '[last_*]' keyword.                   -->
+
+  <send retrans="500">
+    <![CDATA[
+
+      SIP/2.0 200 OK
+      [last_Via:]
+      [last_From:]
+      [last_To:];tag=[call_number]
+      [last_Call-ID:]
+      [last_CSeq:]
+      Contact: <sip:[local_ip]:[local_port];transport=[transport]>
+      Content-Type: application/sdp
+      Content-Length: [len]
+
+      v=0
+      o=user1 53655765 2353687637 IN IP4 [local_ip]
+      s=-
+      c=IN IP4 [media_ip]
+      t=0 0
+      m=application 1050 TCP/MRCPv2 1
+      a=setup:passive
+      a=connection:new
+      a=channel:dca48cf082dd584b@speechsynth
+      a=cmid:1
+      m=audio [media_port] RTP/AVP 0 8
+      a=sendonly
+      a=mid:1
+
+    ]]>
+  </send>
+
+  <recv request="ACK"
+        optional="true"
+        rtd="true"
+        crlf="true">
+  </recv>
+
+  <recv request="INVITE" crlf="true">
+  </recv>
+
+  <send retrans="500">
+    <![CDATA[
+
+      SIP/2.0 200 OK
+      [last_Via:]
+      [last_From:]
+      [last_To:];tag=[call_number]
+      [last_Call-ID:]
+      [last_CSeq:]
+      Contact: <sip:[local_ip]:[local_port];transport=[transport]>
+      Content-Type: application/sdp
+      Content-Length: [len]
+
+      v=0
+      o=user1 53655765 2353687637 IN IP4 [local_ip]
+      s=-
+      c=IN IP4 [media_ip]
+      t=0 0
+      m=application 0 TCP/MRCPv2 1
+      a=setup:passive
+      a=connection:existing
+      a=channel:dca48cf082dd584b@speechsynth
+      a=cmid:1
+      m=audio 0 RTP/AVP 0 8
+      a=sendonly
+      a=mid:1
+
+    ]]>
+  </send>
+
+  <recv request="ACK"
+        optional="true"
+        rtd="true"
+        crlf="true">
+  </recv>
+
+  <recv request="BYE">
+  </recv>
+
+  <send>
+    <![CDATA[
+
+      SIP/2.0 200 OK
+      [last_Via:]
+      [last_From:]
+      [last_To:]
+      [last_Call-ID:]
+      [last_CSeq:]
+      Contact: <sip:[local_ip]:[local_port];transport=[transport]>
+      Content-Length: 0
+
+    ]]>
+  </send>
+
+  <!-- Keep the call open for a while in case the 200 is lost to be     -->
+  <!-- able to retransmit it if we receive the BYE again.               -->
+  <pause milliseconds="4000"/>
+
+
+  <!-- definition of the response time repartition table (unit is ms)   -->
+  <ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
+
+  <!-- definition of the call length repartition table (unit is ms)     -->
+  <CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
+
+</scenario>
diff --git a/libs/unimrcp/tests/sipp/mrcp_uas_unknown b/libs/unimrcp/tests/sipp/mrcp_uas_unknown
new file mode 100644 (file)
index 0000000..e3a1b1e
--- /dev/null
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+
+<scenario name="MRCP Unknown Resource UAS">
+  <!-- By adding rrs="true" (Record Route Sets), the route sets         -->
+  <!-- are saved and used for following messages sent. Useful to test   -->
+  <!-- against stateful SIP proxies/B2BUAs.                             -->
+  <recv request="INVITE" crlf="true">
+  </recv>
+
+  <!-- The '[last_*]' keyword is replaced automatically by the          -->
+  <!-- specified header if it was present in the last message received  -->
+  <!-- (except if it was a retransmission). If the header was not       -->
+  <!-- present or if no message has been received, the '[last_*]'       -->
+  <!-- keyword is discarded, and all bytes until the end of the line    -->
+  <!-- are also discarded.                                              -->
+  <!--                                                                  -->
+  <!-- If the specified header was present several times in the         -->
+  <!-- message, all occurences are concatenated (CRLF seperated)        -->
+  <!-- to be used in place of the '[last_*]' keyword.                   -->
+
+  <send retrans="500">
+    <![CDATA[
+
+      SIP/2.0 200 OK
+      [last_Via:]
+      [last_From:]
+      [last_To:];tag=[call_number]
+      [last_Call-ID:]
+      [last_CSeq:]
+      Contact: <sip:[local_ip]:[local_port];transport=[transport]>
+      Content-Type: application/sdp
+      Content-Length: [len]
+
+      v=0
+      o=user1 53655765 2353687637 IN IP4 [local_ip]
+      s=-
+      c=IN IP4 [media_ip]
+      t=0 0
+      m=application 0 TCP/MRCPv2 1
+      a=setup:passive
+      a=connection:new
+      a=channel:dca48cf082dd584b@unknown
+      a=cmid:1
+      m=audio 0 RTP/AVP 0 8
+      a=sendonly
+      a=mid:1
+
+    ]]>
+  </send>
+
+  <recv request="ACK"
+        optional="true"
+        rtd="true"
+        crlf="true">
+  </recv>
+
+  <recv request="BYE">
+  </recv>
+
+  <send>
+    <![CDATA[
+
+      SIP/2.0 200 OK
+      [last_Via:]
+      [last_From:]
+      [last_To:]
+      [last_Call-ID:]
+      [last_CSeq:]
+      Contact: <sip:[local_ip]:[local_port];transport=[transport]>
+      Content-Length: 0
+
+    ]]>
+  </send>
+
+  <!-- Keep the call open for a while in case the 200 is lost to be     -->
+  <!-- able to retransmit it if we receive the BYE again.               -->
+  <pause milliseconds="4000"/>
+
+
+  <!-- definition of the response time repartition table (unit is ms)   -->
+  <ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
+
+  <!-- definition of the call length repartition table (unit is ms)     -->
+  <CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
+
+</scenario>
diff --git a/libs/unimrcp/tests/strtablegen/Makefile.am b/libs/unimrcp/tests/strtablegen/Makefile.am
new file mode 100644 (file)
index 0000000..b3508c2
--- /dev/null
@@ -0,0 +1,9 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+INCLUDES             = -I$(top_srcdir)/libs/apr-toolkit/include \
+                       $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+noinst_PROGRAMS      = strtablegen
+strtablegen_LDADD    = $(top_builddir)/libs/apr-toolkit/libaprtoolkit.la \
+                       $(UNIMRCP_APR_LIBS) $(UNIMRCP_APU_LIBS)
+strtablegen_SOURCES  = src/main.c
diff --git a/libs/unimrcp/tests/strtablegen/src/main.c b/libs/unimrcp/tests/strtablegen/src/main.c
new file mode 100644 (file)
index 0000000..e547b9b
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2008 Arsen Chaloyan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include "apt_pool.h"
+#include "apt_string_table.h"
+#include "apt_text_stream.h"
+
+static apt_bool_t is_unique(const apt_str_table_item_t table[], apr_size_t count, 
+                                                       apr_size_t item_index, apr_size_t char_index, char value)
+{
+       size_t i;
+       const char *buf;
+       for(i=0; i<count; i++) {
+               buf = table[i].value.buf;
+               if(i != item_index && char_index < table[i].value.length && 
+                       tolower(value) == tolower(buf[char_index])) {
+                       return FALSE;
+               }
+       }
+       return TRUE;
+}
+
+static apt_bool_t string_table_key_generate(apt_str_table_item_t table[], apr_size_t count)
+{
+       size_t i,j;
+       size_t length;
+       for(i=0; i<count; i++) {
+               length = table[i].value.length;
+               table[i].key = length;
+               for(j=0; j<length; j++) {
+                       if(is_unique(table,count,i,j,table[i].value.buf[j]) == TRUE) {
+                               table[i].key = j;
+                               break;
+                       }
+               }
+       }
+       return TRUE;
+}
+
+#define TEST_BUFFER_SIZE 2048
+static char parse_buffer[TEST_BUFFER_SIZE];
+
+static size_t string_table_read(apt_str_table_item_t table[], apr_size_t max_count, FILE *file, apr_pool_t *pool)
+{
+       apt_str_table_item_t *item;
+       size_t count = 0;
+       apt_str_t line;
+       apt_text_stream_t text_stream;
+
+       text_stream.text.length = fread(parse_buffer, 1, sizeof(parse_buffer)-1, file);
+       parse_buffer[text_stream.text.length] = '\0';
+       text_stream.text.buf = parse_buffer;
+       text_stream.pos = parse_buffer;
+
+       do {
+               if(apt_text_line_read(&text_stream,&line) == FALSE || !line.length) {
+                       break;
+               }
+               item = &table[count];
+               apt_string_copy(&item->value,&line,pool);
+               item->key = 0;
+               count++;
+       }
+       while(count < max_count);
+
+       return count;
+}
+
+static apt_bool_t string_table_write(const apt_str_table_item_t table[], apr_size_t count, FILE *file)
+{
+       size_t i;
+       const apt_str_table_item_t *item;
+       for(i=0; i<count; i++) {
+               item = &table[i];
+               fprintf(file,"{{\"%s\",%"APR_SIZE_T_FMT"},%"APR_SIZE_T_FMT"},\r\n",
+                       item->value.buf, item->value.length, item->key);
+       }
+       return TRUE;
+}
+
+int main(int argc, char *argv[])
+{
+       apr_pool_t *pool = NULL;
+       apt_str_table_item_t table[100];
+       size_t count;
+       FILE *file_in, *file_out;
+
+       /* one time apr global initialization */
+       if(apr_initialize() != APR_SUCCESS) {
+               return 0;
+       }
+       pool = apt_pool_create();
+
+       if(argc < 2) {
+               printf("usage: stringtablegen stringtable.in [stringtable.out]\n");
+               return 0;
+       }
+       file_in = fopen(argv[1], "rb");
+       if(file_in == NULL) {
+               printf("cannot open file %s\n", argv[1]);
+               return 0;
+       }
+
+       if(argc > 2) {
+               file_out = fopen(argv[2], "wb");
+       }
+       else {
+               file_out = stdout;
+       }
+
+       /* read items (strings) from the file */
+       count = string_table_read(table,100,file_in,pool);
+
+       /* generate string table */
+       string_table_key_generate(table,count);
+       
+       /* dump string table to the file */
+       string_table_write(table,count,file_out);
+
+       fclose(file_in);
+       if(file_out != stdout) {
+               fclose(file_out);
+       }
+
+       apr_pool_destroy(pool);
+       /* final apr global termination */
+       apr_terminate();
+       return 0;
+}
diff --git a/libs/unimrcp/tests/strtablegen/stringtable.in b/libs/unimrcp/tests/strtablegen/stringtable.in
new file mode 100644 (file)
index 0000000..7f04594
--- /dev/null
@@ -0,0 +1,12 @@
+Channel-Identifier
+Active-Request-Id-List
+Proxy-Sync-Id
+Accept-Charset
+Content-Type
+Content-Id
+Content-Base
+Content-Encoding
+Content-Location
+Content-Length
+Cache-Control
+Logging-Tag
diff --git a/libs/unimrcp/tests/strtablegen/strtablegen.vcproj b/libs/unimrcp/tests/strtablegen/strtablegen.vcproj
new file mode 100644 (file)
index 0000000..f19a36f
--- /dev/null
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="strtablegen"
+       ProjectGUID="{79EF9F1D-E211-4ED1-91D2-FC935AB3A872}"
+       RootNamespace="strtablegen"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unidebug.vsprops;$(SolutionDir)build\vsprops\apt.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="aprtoolkit.lib libaprutil-1.lib libapr-1.lib"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(SolutionDir)build\vsprops\unirelease.vsprops;$(SolutionDir)build\vsprops\apt.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="aprtoolkit.lib libaprutil-1.lib libapr-1.lib"
+                               LinkTimeCodeGeneration="1"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+                       >
+                       <File
+                               RelativePath=".\src\main.c"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/unimrcp.sln b/libs/unimrcp/unimrcp.sln
new file mode 100644 (file)
index 0000000..de17c86
--- /dev/null
@@ -0,0 +1,272 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libs", "libs", "{5377DC3A-DB96-4819-8AAF-2A75F3A69119}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "modules", "modules", "{493A1DB9-6E7C-48C7-93B5-F75C3C25B9DF}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "platforms", "platforms", "{8E282AE2-038C-49FE-AC67-BC9615AFD800}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "plugins", "plugins", "{09BABD45-8F30-4F99-B8B8-8DD78F6804DB}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{AC4356E8-48A1-4D2D-AFB1-11CF30B974CD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unimrcpserver", "platforms\unimrcp-server\unimrcpserver.vcproj", "{592CF22D-3F8F-4A77-A174-130D77B7623B}"
+       ProjectSection(ProjectDependencies) = postProject
+               {C98AF157-352E-4737-BD30-A24E2647F5AE} = {C98AF157-352E-4737-BD30-A24E2647F5AE}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aprtoolkit", "libs\apr-toolkit\aprtoolkit.vcproj", "{13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mpf", "libs\mpf\mpf.vcproj", "{B5A00BFA-6083-4FAE-A097-71642D6473B5}"
+       ProjectSection(ProjectDependencies) = postProject
+               {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2} = {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcp", "libs\mrcp\mrcp.vcproj", "{1C320193-46A6-4B34-9C56-8AB584FC1B56}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpsignaling", "libs\mrcp-signaling\mrcpsignaling.vcproj", "{12A49562-BAB9-43A3-A21D-15B60BBB4C31}"
+       ProjectSection(ProjectDependencies) = postProject
+               {B5A00BFA-6083-4FAE-A097-71642D6473B5} = {B5A00BFA-6083-4FAE-A097-71642D6473B5}
+               {1C320193-46A6-4B34-9C56-8AB584FC1B56} = {1C320193-46A6-4B34-9C56-8AB584FC1B56}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpserver", "libs\mrcp-server\mrcpserver.vcproj", "{18B1F35A-10F8-4287-9B37-2D10501B0B38}"
+       ProjectSection(ProjectDependencies) = postProject
+               {12A49562-BAB9-43A3-A21D-15B60BBB4C31} = {12A49562-BAB9-43A3-A21D-15B60BBB4C31}
+               {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA} = {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libunimrcpserver", "platforms\libunimrcp-server\libunimrcpserver.vcproj", "{C98AF157-352E-4737-BD30-A24E2647F5AE}"
+       ProjectSection(ProjectDependencies) = postProject
+               {DEB01ACB-D65F-4A62-AED9-58C1054499E9} = {DEB01ACB-D65F-4A62-AED9-58C1054499E9}
+               {18B1F35A-10F8-4287-9B37-2D10501B0B38} = {18B1F35A-10F8-4287-9B37-2D10501B0B38}
+               {746F3632-5BB2-4570-9453-31D6D58A7D8E} = {746F3632-5BB2-4570-9453-31D6D58A7D8E}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpsofiasip", "modules\mrcp-sofiasip\mrcpsofiasip.vcproj", "{746F3632-5BB2-4570-9453-31D6D58A7D8E}"
+       ProjectSection(ProjectDependencies) = postProject
+               {12A49562-BAB9-43A3-A21D-15B60BBB4C31} = {12A49562-BAB9-43A3-A21D-15B60BBB4C31}
+               {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA} = {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpclient", "libs\mrcp-client\mrcpclient.vcproj", "{72782932-37CC-46AE-8C7F-9A7B1A6EE108}"
+       ProjectSection(ProjectDependencies) = postProject
+               {12A49562-BAB9-43A3-A21D-15B60BBB4C31} = {12A49562-BAB9-43A3-A21D-15B60BBB4C31}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libunimrcpclient", "platforms\libunimrcp-client\libunimrcpclient.vcproj", "{EE157390-1E85-416C-946E-620E32C9AD33}"
+       ProjectSection(ProjectDependencies) = postProject
+               {DEB01ACB-D65F-4A62-AED9-58C1054499E9} = {DEB01ACB-D65F-4A62-AED9-58C1054499E9}
+               {746F3632-5BB2-4570-9453-31D6D58A7D8E} = {746F3632-5BB2-4570-9453-31D6D58A7D8E}
+               {72782932-37CC-46AE-8C7F-9A7B1A6EE108} = {72782932-37CC-46AE-8C7F-9A7B1A6EE108}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unimrcpclient", "platforms\unimrcp-client\unimrcpclient.vcproj", "{57FAF32E-49FD-491F-895D-132D0D5EFE0A}"
+       ProjectSection(ProjectDependencies) = postProject
+               {EE157390-1E85-416C-946E-620E32C9AD33} = {EE157390-1E85-416C-946E-620E32C9AD33}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpv2transport", "libs\mrcpv2-transport\mrcpv2transport.vcproj", "{A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}"
+       ProjectSection(ProjectDependencies) = postProject
+               {1C320193-46A6-4B34-9C56-8AB584FC1B56} = {1C320193-46A6-4B34-9C56-8AB584FC1B56}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpengine", "libs\mrcp-engine\mrcpengine.vcproj", "{843425BE-9A9A-44F4-A4E3-4B57D6ABD53C}"
+       ProjectSection(ProjectDependencies) = postProject
+               {B5A00BFA-6083-4FAE-A097-71642D6473B5} = {B5A00BFA-6083-4FAE-A097-71642D6473B5}
+               {1C320193-46A6-4B34-9C56-8AB584FC1B56} = {1C320193-46A6-4B34-9C56-8AB584FC1B56}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demosynth", "plugins\demo-synth\demosynth.vcproj", "{92BFA534-C419-4EB2-AAA3-510653F38F08}"
+       ProjectSection(ProjectDependencies) = postProject
+               {843425BE-9A9A-44F4-A4E3-4B57D6ABD53C} = {843425BE-9A9A-44F4-A4E3-4B57D6ABD53C}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demorecog", "plugins\demo-recog\demorecog.vcproj", "{B495B6D9-AF84-479D-B30A-313C16EF8BFD}"
+       ProjectSection(ProjectDependencies) = postProject
+               {843425BE-9A9A-44F4-A4E3-4B57D6ABD53C} = {843425BE-9A9A-44F4-A4E3-4B57D6ABD53C}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "strtablegen", "tests\strtablegen\strtablegen.vcproj", "{79EF9F1D-E211-4ED1-91D2-FC935AB3A872}"
+       ProjectSection(ProjectDependencies) = postProject
+               {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2} = {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "apttest", "tests\apttest\apttest.vcproj", "{429C907B-97D1-4B2D-9B0E-A14A5BFDAD15}"
+       ProjectSection(ProjectDependencies) = postProject
+               {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2} = {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mpftest", "tests\mpftest\mpftest.vcproj", "{DCF01B1C-5268-44F3-9130-D647FABFB663}"
+       ProjectSection(ProjectDependencies) = postProject
+               {B5A00BFA-6083-4FAE-A097-71642D6473B5} = {B5A00BFA-6083-4FAE-A097-71642D6473B5}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcptest", "tests\mrcptest\mrcptest.vcproj", "{3CA97077-6210-4362-998A-D15A35EEAA08}"
+       ProjectSection(ProjectDependencies) = postProject
+               {1C320193-46A6-4B34-9C56-8AB584FC1B56} = {1C320193-46A6-4B34-9C56-8AB584FC1B56}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpcepstral", "plugins\mrcp-cepstral\mrcpcepstral.vcproj", "{729EF28E-38C9-40DE-A138-87785F021411}"
+       ProjectSection(ProjectDependencies) = postProject
+               {843425BE-9A9A-44F4-A4E3-4B57D6ABD53C} = {843425BE-9A9A-44F4-A4E3-4B57D6ABD53C}
+       EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{62083CC3-13BF-49EA-BFE8-4C9337C0D82C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unirtsp", "libs\uni-rtsp\unirtsp.vcproj", "{504B3154-7A4F-459D-9877-B951021C3F1F}"
+       ProjectSection(ProjectDependencies) = postProject
+               {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2} = {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rtsptest", "tests\rtsptest\rtsptest.vcproj", "{17A33F3F-BAF5-403F-8EF4-FECDA7D9A335}"
+       ProjectSection(ProjectDependencies) = postProject
+               {504B3154-7A4F-459D-9877-B951021C3F1F} = {504B3154-7A4F-459D-9877-B951021C3F1F}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpunirtsp", "modules\mrcp-unirtsp\mrcpunirtsp.vcproj", "{DEB01ACB-D65F-4A62-AED9-58C1054499E9}"
+       ProjectSection(ProjectDependencies) = postProject
+               {12A49562-BAB9-43A3-A21D-15B60BBB4C31} = {12A49562-BAB9-43A3-A21D-15B60BBB4C31}
+               {504B3154-7A4F-459D-9877-B951021C3F1F} = {504B3154-7A4F-459D-9877-B951021C3F1F}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "prepare", "build\tools\prepare.vcproj", "{01D63BF5-7798-4746-852A-4B45229BB735}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unimrcpservice", "build\tools\unimrcpservice.vcproj", "{4714EF49-BFD5-4B22-95F7-95A07F1EAC25}"
+       ProjectSection(ProjectDependencies) = postProject
+               {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2} = {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}
+       EndProjectSection
+EndProject
+Global
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Win32 = Debug|Win32
+               Release|Win32 = Release|Win32
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {592CF22D-3F8F-4A77-A174-130D77B7623B}.Debug|Win32.ActiveCfg = Debug|Win32
+               {592CF22D-3F8F-4A77-A174-130D77B7623B}.Debug|Win32.Build.0 = Debug|Win32
+               {592CF22D-3F8F-4A77-A174-130D77B7623B}.Release|Win32.ActiveCfg = Release|Win32
+               {592CF22D-3F8F-4A77-A174-130D77B7623B}.Release|Win32.Build.0 = Release|Win32
+               {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Debug|Win32.ActiveCfg = Debug|Win32
+               {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Debug|Win32.Build.0 = Debug|Win32
+               {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Release|Win32.ActiveCfg = Release|Win32
+               {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2}.Release|Win32.Build.0 = Release|Win32
+               {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Debug|Win32.ActiveCfg = Debug|Win32
+               {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Debug|Win32.Build.0 = Debug|Win32
+               {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Release|Win32.ActiveCfg = Release|Win32
+               {B5A00BFA-6083-4FAE-A097-71642D6473B5}.Release|Win32.Build.0 = Release|Win32
+               {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Debug|Win32.ActiveCfg = Debug|Win32
+               {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Debug|Win32.Build.0 = Debug|Win32
+               {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Release|Win32.ActiveCfg = Release|Win32
+               {1C320193-46A6-4B34-9C56-8AB584FC1B56}.Release|Win32.Build.0 = Release|Win32
+               {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Debug|Win32.ActiveCfg = Debug|Win32
+               {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Debug|Win32.Build.0 = Debug|Win32
+               {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Release|Win32.ActiveCfg = Release|Win32
+               {12A49562-BAB9-43A3-A21D-15B60BBB4C31}.Release|Win32.Build.0 = Release|Win32
+               {18B1F35A-10F8-4287-9B37-2D10501B0B38}.Debug|Win32.ActiveCfg = Debug|Win32
+               {18B1F35A-10F8-4287-9B37-2D10501B0B38}.Debug|Win32.Build.0 = Debug|Win32
+               {18B1F35A-10F8-4287-9B37-2D10501B0B38}.Release|Win32.ActiveCfg = Release|Win32
+               {18B1F35A-10F8-4287-9B37-2D10501B0B38}.Release|Win32.Build.0 = Release|Win32
+               {C98AF157-352E-4737-BD30-A24E2647F5AE}.Debug|Win32.ActiveCfg = Debug|Win32
+               {C98AF157-352E-4737-BD30-A24E2647F5AE}.Debug|Win32.Build.0 = Debug|Win32
+               {C98AF157-352E-4737-BD30-A24E2647F5AE}.Release|Win32.ActiveCfg = Release|Win32
+               {C98AF157-352E-4737-BD30-A24E2647F5AE}.Release|Win32.Build.0 = Release|Win32
+               {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Debug|Win32.ActiveCfg = Debug|Win32
+               {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Debug|Win32.Build.0 = Debug|Win32
+               {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Release|Win32.ActiveCfg = Release|Win32
+               {746F3632-5BB2-4570-9453-31D6D58A7D8E}.Release|Win32.Build.0 = Release|Win32
+               {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Debug|Win32.ActiveCfg = Debug|Win32
+               {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Debug|Win32.Build.0 = Debug|Win32
+               {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Release|Win32.ActiveCfg = Release|Win32
+               {72782932-37CC-46AE-8C7F-9A7B1A6EE108}.Release|Win32.Build.0 = Release|Win32
+               {EE157390-1E85-416C-946E-620E32C9AD33}.Debug|Win32.ActiveCfg = Debug|Win32
+               {EE157390-1E85-416C-946E-620E32C9AD33}.Debug|Win32.Build.0 = Debug|Win32
+               {EE157390-1E85-416C-946E-620E32C9AD33}.Release|Win32.ActiveCfg = Release|Win32
+               {EE157390-1E85-416C-946E-620E32C9AD33}.Release|Win32.Build.0 = Release|Win32
+               {57FAF32E-49FD-491F-895D-132D0D5EFE0A}.Debug|Win32.ActiveCfg = Debug|Win32
+               {57FAF32E-49FD-491F-895D-132D0D5EFE0A}.Debug|Win32.Build.0 = Debug|Win32
+               {57FAF32E-49FD-491F-895D-132D0D5EFE0A}.Release|Win32.ActiveCfg = Release|Win32
+               {57FAF32E-49FD-491F-895D-132D0D5EFE0A}.Release|Win32.Build.0 = Release|Win32
+               {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Debug|Win32.ActiveCfg = Debug|Win32
+               {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Debug|Win32.Build.0 = Debug|Win32
+               {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Release|Win32.ActiveCfg = Release|Win32
+               {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}.Release|Win32.Build.0 = Release|Win32
+               {843425BE-9A9A-44F4-A4E3-4B57D6ABD53C}.Debug|Win32.ActiveCfg = Debug|Win32
+               {843425BE-9A9A-44F4-A4E3-4B57D6ABD53C}.Debug|Win32.Build.0 = Debug|Win32
+               {843425BE-9A9A-44F4-A4E3-4B57D6ABD53C}.Release|Win32.ActiveCfg = Release|Win32
+               {843425BE-9A9A-44F4-A4E3-4B57D6ABD53C}.Release|Win32.Build.0 = Release|Win32
+               {92BFA534-C419-4EB2-AAA3-510653F38F08}.Debug|Win32.ActiveCfg = Debug|Win32
+               {92BFA534-C419-4EB2-AAA3-510653F38F08}.Debug|Win32.Build.0 = Debug|Win32
+               {92BFA534-C419-4EB2-AAA3-510653F38F08}.Release|Win32.ActiveCfg = Release|Win32
+               {92BFA534-C419-4EB2-AAA3-510653F38F08}.Release|Win32.Build.0 = Release|Win32
+               {B495B6D9-AF84-479D-B30A-313C16EF8BFD}.Debug|Win32.ActiveCfg = Debug|Win32
+               {B495B6D9-AF84-479D-B30A-313C16EF8BFD}.Debug|Win32.Build.0 = Debug|Win32
+               {B495B6D9-AF84-479D-B30A-313C16EF8BFD}.Release|Win32.ActiveCfg = Release|Win32
+               {B495B6D9-AF84-479D-B30A-313C16EF8BFD}.Release|Win32.Build.0 = Release|Win32
+               {79EF9F1D-E211-4ED1-91D2-FC935AB3A872}.Debug|Win32.ActiveCfg = Debug|Win32
+               {79EF9F1D-E211-4ED1-91D2-FC935AB3A872}.Debug|Win32.Build.0 = Debug|Win32
+               {79EF9F1D-E211-4ED1-91D2-FC935AB3A872}.Release|Win32.ActiveCfg = Release|Win32
+               {79EF9F1D-E211-4ED1-91D2-FC935AB3A872}.Release|Win32.Build.0 = Release|Win32
+               {429C907B-97D1-4B2D-9B0E-A14A5BFDAD15}.Debug|Win32.ActiveCfg = Debug|Win32
+               {429C907B-97D1-4B2D-9B0E-A14A5BFDAD15}.Debug|Win32.Build.0 = Debug|Win32
+               {429C907B-97D1-4B2D-9B0E-A14A5BFDAD15}.Release|Win32.ActiveCfg = Release|Win32
+               {429C907B-97D1-4B2D-9B0E-A14A5BFDAD15}.Release|Win32.Build.0 = Release|Win32
+               {DCF01B1C-5268-44F3-9130-D647FABFB663}.Debug|Win32.ActiveCfg = Debug|Win32
+               {DCF01B1C-5268-44F3-9130-D647FABFB663}.Debug|Win32.Build.0 = Debug|Win32
+               {DCF01B1C-5268-44F3-9130-D647FABFB663}.Release|Win32.ActiveCfg = Release|Win32
+               {DCF01B1C-5268-44F3-9130-D647FABFB663}.Release|Win32.Build.0 = Release|Win32
+               {3CA97077-6210-4362-998A-D15A35EEAA08}.Debug|Win32.ActiveCfg = Debug|Win32
+               {3CA97077-6210-4362-998A-D15A35EEAA08}.Debug|Win32.Build.0 = Debug|Win32
+               {3CA97077-6210-4362-998A-D15A35EEAA08}.Release|Win32.ActiveCfg = Release|Win32
+               {3CA97077-6210-4362-998A-D15A35EEAA08}.Release|Win32.Build.0 = Release|Win32
+               {729EF28E-38C9-40DE-A138-87785F021411}.Debug|Win32.ActiveCfg = Debug|Win32
+               {729EF28E-38C9-40DE-A138-87785F021411}.Release|Win32.ActiveCfg = Release|Win32
+               {504B3154-7A4F-459D-9877-B951021C3F1F}.Debug|Win32.ActiveCfg = Debug|Win32
+               {504B3154-7A4F-459D-9877-B951021C3F1F}.Debug|Win32.Build.0 = Debug|Win32
+               {504B3154-7A4F-459D-9877-B951021C3F1F}.Release|Win32.ActiveCfg = Release|Win32
+               {504B3154-7A4F-459D-9877-B951021C3F1F}.Release|Win32.Build.0 = Release|Win32
+               {17A33F3F-BAF5-403F-8EF4-FECDA7D9A335}.Debug|Win32.ActiveCfg = Debug|Win32
+               {17A33F3F-BAF5-403F-8EF4-FECDA7D9A335}.Debug|Win32.Build.0 = Debug|Win32
+               {17A33F3F-BAF5-403F-8EF4-FECDA7D9A335}.Release|Win32.ActiveCfg = Release|Win32
+               {17A33F3F-BAF5-403F-8EF4-FECDA7D9A335}.Release|Win32.Build.0 = Release|Win32
+               {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Debug|Win32.ActiveCfg = Debug|Win32
+               {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Debug|Win32.Build.0 = Debug|Win32
+               {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Release|Win32.ActiveCfg = Release|Win32
+               {DEB01ACB-D65F-4A62-AED9-58C1054499E9}.Release|Win32.Build.0 = Release|Win32
+               {01D63BF5-7798-4746-852A-4B45229BB735}.Debug|Win32.ActiveCfg = Debug|Win32
+               {01D63BF5-7798-4746-852A-4B45229BB735}.Release|Win32.ActiveCfg = Release|Win32
+               {4714EF49-BFD5-4B22-95F7-95A07F1EAC25}.Debug|Win32.ActiveCfg = Debug|Win32
+               {4714EF49-BFD5-4B22-95F7-95A07F1EAC25}.Release|Win32.ActiveCfg = Release|Win32
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+       GlobalSection(NestedProjects) = preSolution
+               {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2} = {5377DC3A-DB96-4819-8AAF-2A75F3A69119}
+               {B5A00BFA-6083-4FAE-A097-71642D6473B5} = {5377DC3A-DB96-4819-8AAF-2A75F3A69119}
+               {1C320193-46A6-4B34-9C56-8AB584FC1B56} = {5377DC3A-DB96-4819-8AAF-2A75F3A69119}
+               {12A49562-BAB9-43A3-A21D-15B60BBB4C31} = {5377DC3A-DB96-4819-8AAF-2A75F3A69119}
+               {18B1F35A-10F8-4287-9B37-2D10501B0B38} = {5377DC3A-DB96-4819-8AAF-2A75F3A69119}
+               {72782932-37CC-46AE-8C7F-9A7B1A6EE108} = {5377DC3A-DB96-4819-8AAF-2A75F3A69119}
+               {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA} = {5377DC3A-DB96-4819-8AAF-2A75F3A69119}
+               {843425BE-9A9A-44F4-A4E3-4B57D6ABD53C} = {5377DC3A-DB96-4819-8AAF-2A75F3A69119}
+               {504B3154-7A4F-459D-9877-B951021C3F1F} = {5377DC3A-DB96-4819-8AAF-2A75F3A69119}
+               {746F3632-5BB2-4570-9453-31D6D58A7D8E} = {493A1DB9-6E7C-48C7-93B5-F75C3C25B9DF}
+               {DEB01ACB-D65F-4A62-AED9-58C1054499E9} = {493A1DB9-6E7C-48C7-93B5-F75C3C25B9DF}
+               {592CF22D-3F8F-4A77-A174-130D77B7623B} = {8E282AE2-038C-49FE-AC67-BC9615AFD800}
+               {C98AF157-352E-4737-BD30-A24E2647F5AE} = {8E282AE2-038C-49FE-AC67-BC9615AFD800}
+               {EE157390-1E85-416C-946E-620E32C9AD33} = {8E282AE2-038C-49FE-AC67-BC9615AFD800}
+               {57FAF32E-49FD-491F-895D-132D0D5EFE0A} = {8E282AE2-038C-49FE-AC67-BC9615AFD800}
+               {92BFA534-C419-4EB2-AAA3-510653F38F08} = {09BABD45-8F30-4F99-B8B8-8DD78F6804DB}
+               {B495B6D9-AF84-479D-B30A-313C16EF8BFD} = {09BABD45-8F30-4F99-B8B8-8DD78F6804DB}
+               {729EF28E-38C9-40DE-A138-87785F021411} = {09BABD45-8F30-4F99-B8B8-8DD78F6804DB}
+               {79EF9F1D-E211-4ED1-91D2-FC935AB3A872} = {AC4356E8-48A1-4D2D-AFB1-11CF30B974CD}
+               {429C907B-97D1-4B2D-9B0E-A14A5BFDAD15} = {AC4356E8-48A1-4D2D-AFB1-11CF30B974CD}
+               {DCF01B1C-5268-44F3-9130-D647FABFB663} = {AC4356E8-48A1-4D2D-AFB1-11CF30B974CD}
+               {3CA97077-6210-4362-998A-D15A35EEAA08} = {AC4356E8-48A1-4D2D-AFB1-11CF30B974CD}
+               {17A33F3F-BAF5-403F-8EF4-FECDA7D9A335} = {AC4356E8-48A1-4D2D-AFB1-11CF30B974CD}
+               {01D63BF5-7798-4746-852A-4B45229BB735} = {62083CC3-13BF-49EA-BFE8-4C9337C0D82C}
+               {4714EF49-BFD5-4B22-95F7-95A07F1EAC25} = {62083CC3-13BF-49EA-BFE8-4C9337C0D82C}
+       EndGlobalSection
+EndGlobal