From 17099473a3a8b1347b13331f260bd8ea9fd90804 Mon Sep 17 00:00:00 2001 From: Christopher Rienzo Date: Thu, 16 Jun 2011 16:25:00 +0000 Subject: [PATCH] Update to latest UniMRCP version. MRCP requests can no timeout if there is no server response. --- conf/autoload_configs/unimrcp.conf.xml | 1 + libs/unimrcp/.update | 2 +- libs/unimrcp/AUTHORS | 1 + libs/unimrcp/Makefile.am | 2 +- libs/unimrcp/NOTICE | 2 +- libs/unimrcp/acinclude.m4 | 1 - libs/unimrcp/build/Makefile.am | 8 +- libs/unimrcp/build/acmacros/flite.m4 | 33 +- libs/unimrcp/build/acmacros/swift.m4 | 28 - libs/unimrcp/build/init.d/unimrcp-server | 271 ++++ libs/unimrcp/build/svnrev/Makefile.am | 10 + libs/unimrcp/build/svnrev/svnrev.c | 381 +++++ libs/unimrcp/build/svnrev/svnrev.input | 32 + libs/unimrcp/build/svnrev/svnrev.vcproj | 345 +++++ libs/unimrcp/build/tools/prepare.2008.vcproj | 68 - libs/unimrcp/build/tools/prepare.vcproj | 26 +- .../build/tools/preparesphinx.2008.vcproj | 68 - libs/unimrcp/build/tools/unimrcp_service.c | 4 +- .../build/tools/unimrcpservice.2008.vcproj | 158 -- .../unimrcp/build/tools/unimrcpservice.vcproj | 8 +- libs/unimrcp/build/uni_version.h | 52 +- libs/unimrcp/build/vsprops/apr.props | 30 - libs/unimrcp/build/vsprops/apt.props | 15 - libs/unimrcp/build/vsprops/cepstral.vsprops | 20 - libs/unimrcp/build/vsprops/mpf.props | 15 - libs/unimrcp/build/vsprops/mrcp.props | 15 - libs/unimrcp/build/vsprops/mrcpclient.props | 15 - .../unimrcp/build/vsprops/mrcpsignaling.props | 15 - .../build/vsprops/mrcpv2transport.props | 14 - libs/unimrcp/build/vsprops/sofiasip.props | 22 - libs/unimrcp/build/vsprops/unibase.props | 26 - libs/unimrcp/build/vsprops/unidebug.props | 21 - .../build/vsprops/unimrcpclient.vsprops | 2 +- .../build/vsprops/unimrcpplugin.vsprops | 17 - .../build/vsprops/unimrcpserver.vsprops | 2 +- libs/unimrcp/build/vsprops/unirelease.props | 18 - libs/unimrcp/build/vsprops/unirtsp.props | 15 - libs/unimrcp/conf/Makefile.am | 9 +- .../unimrcp/conf/client-profiles/lumenvox.xml | 50 + libs/unimrcp/conf/client-profiles/nuance.xml | 76 + .../conf/client-profiles/speechpro.xml | 33 + libs/unimrcp/conf/client-profiles/unimrcp.xml | 51 + libs/unimrcp/conf/logger.xml | 38 + libs/unimrcp/conf/umcscenarios.xml | 30 +- libs/unimrcp/conf/unimrcpclient.xml | 182 +-- libs/unimrcp/conf/unimrcpclient.xsd | 266 ++++ libs/unimrcp/conf/unimrcpserver.xml | 232 +-- libs/unimrcp/conf/unimrcpserver.xsd | 266 ++++ libs/unimrcp/configure.ac | 35 +- libs/unimrcp/data/demo-16kHz.pcm | Bin 115200 -> 70444 bytes libs/unimrcp/data/demo-8kHz.pcm | Bin 58636 -> 35200 bytes libs/unimrcp/data/grammar.mixed | 19 + libs/unimrcp/data/johnsmith-16kHz.pcm | Bin 0 -> 33214 bytes libs/unimrcp/data/johnsmith-8kHz.pcm | Bin 0 -> 16000 bytes libs/unimrcp/data/result-verification.xml | 21 + libs/unimrcp/data/speak.txt | 2 +- libs/unimrcp/data/speak.xml | 8 +- .../docs/{doxygen.conf => doxygen.conf.in} | 3 +- libs/unimrcp/docs/mainpage.docs | 92 ++ libs/unimrcp/libs/apr-toolkit/Makefile.am | 19 +- .../libs/apr-toolkit/aprtoolkit.2008.vcproj | 409 ----- .../libs/apr-toolkit/aprtoolkit.2010.vcxproj | 157 -- .../aprtoolkit.2010.vcxproj.filters | 125 -- .../libs/apr-toolkit/aprtoolkit.vcproj | 40 +- libs/unimrcp/libs/apr-toolkit/include/apt.h | 10 +- .../apr-toolkit/include/apt_consumer_task.h | 14 +- .../apr-toolkit/include/apt_cyclic_queue.h | 12 +- .../libs/apr-toolkit/include/apt_dir_layout.h | 17 +- .../apr-toolkit/include/apt_header_field.h | 178 +++ .../libs/apr-toolkit/include/apt_log.h | 107 +- .../include/apt_multipart_content.h | 108 ++ .../libs/apr-toolkit/include/apt_net.h | 10 +- .../apr-toolkit/include/apt_net_client_task.h | 127 -- .../apr-toolkit/include/apt_net_server_task.h | 132 -- .../libs/apr-toolkit/include/apt_nlsml_doc.h | 10 +- .../libs/apr-toolkit/include/apt_obj_list.h | 26 +- .../libs/apr-toolkit/include/apt_pair.h | 10 +- .../apr-toolkit/include/apt_poller_task.h | 122 ++ .../libs/apr-toolkit/include/apt_pollset.h | 14 +- .../libs/apr-toolkit/include/apt_pool.h | 10 +- .../libs/apr-toolkit/include/apt_string.h | 12 +- .../apr-toolkit/include/apt_string_table.h | 10 +- .../libs/apr-toolkit/include/apt_task.h | 66 +- .../libs/apr-toolkit/include/apt_task_msg.h | 10 +- .../libs/apr-toolkit/include/apt_test_suite.h | 12 +- .../apr-toolkit/include/apt_text_message.h | 125 ++ .../apr-toolkit/include/apt_text_stream.h | 145 +- .../apr-toolkit/include/apt_timer_queue.h | 68 + .../libs/apr-toolkit/src/apt_consumer_task.c | 23 +- .../libs/apr-toolkit/src/apt_cyclic_queue.c | 6 +- .../libs/apr-toolkit/src/apt_dir_layout.c | 15 +- .../libs/apr-toolkit/src/apt_header_field.c | 183 +++ libs/unimrcp/libs/apr-toolkit/src/apt_log.c | 319 +++- .../apr-toolkit/src/apt_multipart_content.c | 312 ++++ libs/unimrcp/libs/apr-toolkit/src/apt_net.c | 4 +- .../apr-toolkit/src/apt_net_client_task.c | 322 ---- .../apr-toolkit/src/apt_net_server_task.c | 393 ----- .../libs/apr-toolkit/src/apt_nlsml_doc.c | 9 +- .../libs/apr-toolkit/src/apt_obj_list.c | 20 +- libs/unimrcp/libs/apr-toolkit/src/apt_pair.c | 4 +- .../libs/apr-toolkit/src/apt_poller_task.c | 271 ++++ .../libs/apr-toolkit/src/apt_pollset.c | 4 +- libs/unimrcp/libs/apr-toolkit/src/apt_pool.c | 4 +- .../libs/apr-toolkit/src/apt_string_table.c | 4 +- libs/unimrcp/libs/apr-toolkit/src/apt_task.c | 213 ++- .../libs/apr-toolkit/src/apt_task_msg.c | 4 +- .../libs/apr-toolkit/src/apt_test_suite.c | 6 +- .../libs/apr-toolkit/src/apt_text_message.c | 448 ++++++ .../libs/apr-toolkit/src/apt_text_stream.c | 173 ++- .../libs/apr-toolkit/src/apt_timer_queue.c | 211 +++ libs/unimrcp/libs/mpf/Makefile.am | 2 - libs/unimrcp/libs/mpf/include/mpf.h | 10 +- .../libs/mpf/include/mpf_activity_detector.h | 10 +- .../mpf/include/mpf_audio_file_descriptor.h | 10 +- .../libs/mpf/include/mpf_audio_file_stream.h | 10 +- libs/unimrcp/libs/mpf/include/mpf_bridge.h | 12 +- libs/unimrcp/libs/mpf/include/mpf_buffer.h | 12 +- libs/unimrcp/libs/mpf/include/mpf_codec.h | 26 +- .../libs/mpf/include/mpf_codec_descriptor.h | 10 +- .../libs/mpf/include/mpf_codec_manager.h | 10 +- libs/unimrcp/libs/mpf/include/mpf_context.h | 14 +- libs/unimrcp/libs/mpf/include/mpf_decoder.h | 10 +- .../libs/mpf/include/mpf_dtmf_detector.h | 12 +- .../libs/mpf/include/mpf_dtmf_generator.h | 12 +- libs/unimrcp/libs/mpf/include/mpf_encoder.h | 10 +- libs/unimrcp/libs/mpf/include/mpf_engine.h | 27 +- .../include/mpf_file_termination_factory.h | 10 +- libs/unimrcp/libs/mpf/include/mpf_frame.h | 10 +- .../libs/mpf/include/mpf_frame_buffer.h | 10 +- .../libs/mpf/include/mpf_jitter_buffer.h | 12 +- libs/unimrcp/libs/mpf/include/mpf_message.h | 10 +- libs/unimrcp/libs/mpf/include/mpf_mixer.h | 12 +- .../unimrcp/libs/mpf/include/mpf_multiplier.h | 12 +- .../libs/mpf/include/mpf_named_event.h | 10 +- libs/unimrcp/libs/mpf/include/mpf_object.h | 15 +- libs/unimrcp/libs/mpf/include/mpf_resampler.h | 10 +- .../libs/mpf/include/mpf_rtcp_packet.h | 10 +- .../libs/mpf/include/mpf_rtp_attribs.h | 10 +- libs/unimrcp/libs/mpf/include/mpf_rtp_defs.h | 10 +- .../libs/mpf/include/mpf_rtp_descriptor.h | 49 +- .../unimrcp/libs/mpf/include/mpf_rtp_header.h | 10 +- libs/unimrcp/libs/mpf/include/mpf_rtp_pt.h | 10 +- libs/unimrcp/libs/mpf/include/mpf_rtp_stat.h | 10 +- .../unimrcp/libs/mpf/include/mpf_rtp_stream.h | 15 +- .../mpf/include/mpf_rtp_termination_factory.h | 10 +- libs/unimrcp/libs/mpf/include/mpf_scheduler.h | 10 +- libs/unimrcp/libs/mpf/include/mpf_stream.h | 10 +- .../libs/mpf/include/mpf_stream_descriptor.h | 10 +- .../libs/mpf/include/mpf_termination.h | 17 +- .../mpf/include/mpf_termination_factory.h | 22 +- .../libs/mpf/include/mpf_timer_manager.h | 53 - libs/unimrcp/libs/mpf/include/mpf_types.h | 16 +- libs/unimrcp/libs/mpf/mpf.2008.vcproj | 567 ------- libs/unimrcp/libs/mpf/mpf.2010.vcxproj | 193 --- .../unimrcp/libs/mpf/mpf.2010.vcxproj.filters | 239 --- libs/unimrcp/libs/mpf/mpf.vcproj | 8 - .../libs/mpf/src/mpf_activity_detector.c | 4 +- .../libs/mpf/src/mpf_audio_file_stream.c | 4 +- libs/unimrcp/libs/mpf/src/mpf_bridge.c | 47 +- libs/unimrcp/libs/mpf/src/mpf_buffer.c | 6 +- .../libs/mpf/src/mpf_codec_descriptor.c | 4 +- libs/unimrcp/libs/mpf/src/mpf_codec_g711.c | 32 +- libs/unimrcp/libs/mpf/src/mpf_codec_linear.c | 5 +- libs/unimrcp/libs/mpf/src/mpf_codec_manager.c | 4 +- libs/unimrcp/libs/mpf/src/mpf_context.c | 22 +- libs/unimrcp/libs/mpf/src/mpf_decoder.c | 6 +- libs/unimrcp/libs/mpf/src/mpf_dtmf_detector.c | 10 +- .../unimrcp/libs/mpf/src/mpf_dtmf_generator.c | 4 +- libs/unimrcp/libs/mpf/src/mpf_encoder.c | 6 +- libs/unimrcp/libs/mpf/src/mpf_engine.c | 56 +- .../mpf/src/mpf_file_termination_factory.c | 4 +- libs/unimrcp/libs/mpf/src/mpf_frame_buffer.c | 4 +- libs/unimrcp/libs/mpf/src/mpf_jitter_buffer.c | 23 +- libs/unimrcp/libs/mpf/src/mpf_mixer.c | 13 +- libs/unimrcp/libs/mpf/src/mpf_multiplier.c | 13 +- libs/unimrcp/libs/mpf/src/mpf_named_event.c | 4 +- libs/unimrcp/libs/mpf/src/mpf_resampler.c | 4 +- libs/unimrcp/libs/mpf/src/mpf_rtp_attribs.c | 4 +- libs/unimrcp/libs/mpf/src/mpf_rtp_stream.c | 127 +- .../mpf/src/mpf_rtp_termination_factory.c | 16 +- libs/unimrcp/libs/mpf/src/mpf_scheduler.c | 4 +- libs/unimrcp/libs/mpf/src/mpf_stream.c | 4 +- libs/unimrcp/libs/mpf/src/mpf_termination.c | 7 +- .../libs/mpf/src/mpf_termination_factory.c | 16 +- libs/unimrcp/libs/mpf/src/mpf_timer_manager.c | 188 --- libs/unimrcp/libs/mrcp-client/Makefile.am | 3 +- .../mrcp-client/include/mrcp_application.h | 41 +- .../libs/mrcp-client/include/mrcp_client.h | 70 +- .../mrcp-client/include/mrcp_client_session.h | 25 +- .../mrcp-client/include/mrcp_client_types.h | 10 +- .../libs/mrcp-client/mrcpclient.2008.vcproj | 289 ---- .../libs/mrcp-client/mrcpclient.2010.vcxproj | 121 -- .../mrcpclient.2010.vcxproj.filters | 35 - .../libs/mrcp-client/mrcpclient.vcproj | 4 + .../libs/mrcp-client/src/mrcp_application.c | 538 +++++++ .../libs/mrcp-client/src/mrcp_client.c | 558 ++----- .../mrcp-client/src/mrcp_client_session.c | 282 ++-- libs/unimrcp/libs/mrcp-engine/Makefile.am | 7 +- .../mrcp-engine/include/mrcp_engine_factory.h | 19 +- .../mrcp-engine/include/mrcp_engine_iface.h | 40 +- .../mrcp-engine/include/mrcp_engine_impl.h | 28 +- .../mrcp-engine/include/mrcp_engine_loader.h | 16 +- .../mrcp-engine/include/mrcp_engine_plugin.h | 14 +- .../mrcp-engine/include/mrcp_engine_types.h | 29 +- .../mrcp-engine/include/mrcp_recog_engine.h | 10 +- .../include/mrcp_recog_state_machine.h | 10 +- .../include/mrcp_recorder_engine.h | 10 +- .../include/mrcp_recorder_state_machine.h | 10 +- .../include/mrcp_resource_engine.h | 10 +- .../mrcp-engine/include/mrcp_state_machine.h | 10 +- .../mrcp-engine/include/mrcp_synth_engine.h | 10 +- .../include/mrcp_synth_state_machine.h | 10 +- .../include/mrcp_verifier_engine.h | 35 + .../include/mrcp_verifier_state_machine.h | 36 + .../libs/mrcp-engine/mrcpengine.2008.vcproj | 154 -- .../libs/mrcp-engine/mrcpengine.vcproj | 12 + .../mrcp-engine/src/mrcp_engine_factory.c | 26 +- .../libs/mrcp-engine/src/mrcp_engine_iface.c | 49 +- .../libs/mrcp-engine/src/mrcp_engine_impl.c | 11 +- .../libs/mrcp-engine/src/mrcp_engine_loader.c | 16 +- .../src/mrcp_recog_state_machine.c | 151 +- .../src/mrcp_recorder_state_machine.c | 96 +- .../src/mrcp_synth_state_machine.c | 133 +- .../src/mrcp_verifier_state_machine.c | 525 +++++++ .../libs/mrcp-server/include/mrcp_server.h | 105 +- .../mrcp-server/include/mrcp_server_session.h | 14 +- .../mrcp-server/include/mrcp_server_types.h | 10 +- .../libs/mrcp-server/mrcpserver.2008.vcproj | 162 -- .../libs/mrcp-server/src/mrcp_server.c | 282 +++- .../mrcp-server/src/mrcp_server_session.c | 121 +- .../mrcp-signaling/include/mrcp_session.h | 14 +- .../include/mrcp_session_descriptor.h | 10 +- .../mrcp-signaling/include/mrcp_sig_agent.h | 54 +- .../mrcp-signaling/include/mrcp_sig_types.h | 13 +- .../mrcp-signaling/mrcpsignaling.2008.vcproj | 289 ---- .../mrcp-signaling/mrcpsignaling.2010.vcxproj | 121 -- .../mrcpsignaling.2010.vcxproj.filters | 35 - .../src/mrcp_session_descriptor.c | 4 +- .../libs/mrcp-signaling/src/mrcp_sig_agent.c | 24 +- libs/unimrcp/libs/mrcp/Makefile.am | 14 +- .../libs/mrcp/control/include/mrcp_resource.h | 10 +- .../control/include/mrcp_resource_factory.h | 14 +- .../control/include/mrcp_resource_loader.h | 12 +- .../libs/mrcp/control/include/mrcp_stream.h | 54 +- .../mrcp/control/src/mrcp_resource_factory.c | 8 +- .../mrcp/control/src/mrcp_resource_loader.c | 15 +- .../libs/mrcp/control/src/mrcp_stream.c | 455 ++---- libs/unimrcp/libs/mrcp/include/mrcp.h | 10 +- libs/unimrcp/libs/mrcp/include/mrcp_types.h | 11 +- .../message/include/mrcp_generic_header.h | 20 +- .../libs/mrcp/message/include/mrcp_header.h | 121 ++ .../message/include/mrcp_header_accessor.h | 81 +- .../libs/mrcp/message/include/mrcp_message.h | 292 ++-- .../mrcp/message/include/mrcp_start_line.h | 13 +- .../mrcp/message/src/mrcp_generic_header.c | 107 +- .../libs/mrcp/message/src/mrcp_header.c | 267 ++++ .../mrcp/message/src/mrcp_header_accessor.c | 191 +-- .../libs/mrcp/message/src/mrcp_message.c | 314 ++-- .../libs/mrcp/message/src/mrcp_start_line.c | 36 +- libs/unimrcp/libs/mrcp/mrcp.2008.vcproj | 422 ------ libs/unimrcp/libs/mrcp/mrcp.2010.vcxproj | 148 -- .../libs/mrcp/mrcp.2010.vcxproj.filters | 133 -- libs/unimrcp/libs/mrcp/mrcp.vcproj | 24 + .../resources/include/mrcp_recog_header.h | 75 +- .../resources/include/mrcp_recog_resource.h | 17 +- .../resources/include/mrcp_recorder_header.h | 10 +- .../include/mrcp_recorder_resource.h | 10 +- .../resources/include/mrcp_synth_header.h | 18 +- .../resources/include/mrcp_synth_resource.h | 10 +- .../resources/include/mrcp_verifier_header.h | 162 ++ .../include/mrcp_verifier_resource.h | 63 + .../mrcp/resources/src/mrcp_recog_header.c | 436 ++++-- .../mrcp/resources/src/mrcp_recog_resource.c | 42 +- .../mrcp/resources/src/mrcp_recorder_header.c | 63 +- .../resources/src/mrcp_recorder_resource.c | 4 +- .../mrcp/resources/src/mrcp_synth_header.c | 157 +- .../mrcp/resources/src/mrcp_synth_resource.c | 4 +- .../mrcp/resources/src/mrcp_verifier_header.c | 352 +++++ .../resources/src/mrcp_verifier_resource.c | 68 + .../include/mrcp_client_connection.h | 73 +- .../include/mrcp_connection.h | 29 +- .../include/mrcp_connection_types.h | 17 +- .../include/mrcp_control_descriptor.h | 12 +- .../include/mrcp_server_connection.h | 63 +- .../mrcpv2transport.2008.vcproj | 301 ---- .../mrcpv2transport.2010.vcxproj | 124 -- .../mrcpv2transport.2010.vcxproj.filters | 44 - .../src/mrcp_client_connection.c | 495 ++++--- .../mrcpv2-transport/src/mrcp_connection.c | 14 +- .../src/mrcp_control_descriptor.c | 6 +- .../src/mrcp_server_connection.c | 484 +++--- libs/unimrcp/libs/uni-rtsp/include/rtsp.h | 10 +- .../libs/uni-rtsp/include/rtsp_client.h | 16 +- .../libs/uni-rtsp/include/rtsp_header.h | 60 +- .../libs/uni-rtsp/include/rtsp_message.h | 10 +- .../libs/uni-rtsp/include/rtsp_server.h | 14 +- .../libs/uni-rtsp/include/rtsp_start_line.h | 16 +- .../libs/uni-rtsp/include/rtsp_stream.h | 33 +- libs/unimrcp/libs/uni-rtsp/src/rtsp_client.c | 365 +++-- libs/unimrcp/libs/uni-rtsp/src/rtsp_header.c | 165 ++- libs/unimrcp/libs/uni-rtsp/src/rtsp_message.c | 13 +- libs/unimrcp/libs/uni-rtsp/src/rtsp_server.c | 415 ++++-- .../libs/uni-rtsp/src/rtsp_start_line.c | 74 +- libs/unimrcp/libs/uni-rtsp/src/rtsp_stream.c | 287 +--- .../unimrcp/libs/uni-rtsp/unirtsp.2008.vcproj | 321 ---- .../libs/uni-rtsp/unirtsp.2010.vcxproj | 132 -- .../uni-rtsp/unirtsp.2010.vcxproj.filters | 56 - .../modules/mrcp-sofiasip/include/mrcp_sdp.h | 10 +- .../include/mrcp_sofiasip_client_agent.h | 32 +- .../include/mrcp_sofiasip_server_agent.h | 22 +- .../mrcp-sofiasip/mrcpsofiasip.2008.vcproj | 293 ---- .../mrcp-sofiasip/mrcpsofiasip.2010.vcxproj | 138 -- .../mrcpsofiasip.2010.vcxproj.filters | 35 - .../modules/mrcp-sofiasip/src/mrcp_sdp.c | 6 +- .../src/mrcp_sofiasip_client_agent.c | 186 ++- .../src/mrcp_sofiasip_server_agent.c | 52 +- .../include/mrcp_unirtsp_client_agent.h | 33 +- .../mrcp-unirtsp/include/mrcp_unirtsp_sdp.h | 10 +- .../include/mrcp_unirtsp_server_agent.h | 12 +- .../mrcp-unirtsp/mrcpunirtsp.2008.vcproj | 293 ---- .../mrcp-unirtsp/mrcpunirtsp.2010.vcxproj | 133 -- .../mrcpunirtsp.2010.vcxproj.filters | 35 - .../src/mrcp_unirtsp_client_agent.c | 88 +- .../mrcp-unirtsp/src/mrcp_unirtsp_sdp.c | 52 +- .../src/mrcp_unirtsp_server_agent.c | 35 +- libs/unimrcp/packages/inno-setup/setup.iss | 14 - libs/unimrcp/packages/inno-setup/setup.txt | 2 +- libs/unimrcp/packages/inno-setup/unimrcp.iss | 1 + libs/unimrcp/platforms/asr-client/src/main.c | 12 +- .../libasr-client/include/asr_engine.h | 43 +- .../platforms/libasr-client/src/asr_engine.c | 217 ++- .../include/unimrcp_client.h | 10 +- .../libunimrcpclient.2008.vcproj | 156 -- .../libunimrcp-client/libunimrcpclient.vcproj | 4 + .../libunimrcp-client/src/unimrcp_client.c | 1270 +++++++++++----- .../include/unimrcp_server.h | 10 +- .../libunimrcpserver.2008.vcproj | 156 -- .../libunimrcp-server/libunimrcpserver.vcproj | 4 + .../libunimrcp-server/src/unimrcp_server.c | 1314 +++++++++++------ libs/unimrcp/platforms/umc/Makefile.am | 5 +- .../platforms/umc/include/dtmfscenario.h | 10 +- .../platforms/umc/include/dtmfsession.h | 10 +- .../platforms/umc/include/recogscenario.h | 10 +- .../platforms/umc/include/recogsession.h | 11 +- .../platforms/umc/include/recorderscenario.h | 10 +- .../platforms/umc/include/recordersession.h | 10 +- .../platforms/umc/include/setparamscenario.h | 10 +- .../platforms/umc/include/setparamsession.h | 10 +- .../platforms/umc/include/synthscenario.h | 10 +- .../platforms/umc/include/synthsession.h | 13 +- .../platforms/umc/include/umcconsole.h | 14 +- .../platforms/umc/include/umcframework.h | 12 +- .../platforms/umc/include/umcscenario.h | 10 +- .../platforms/umc/include/umcsession.h | 18 +- .../platforms/umc/include/verifierscenario.h | 75 + .../platforms/umc/include/verifiersession.h | 74 + .../platforms/umc/src/dtmfscenario.cpp | 4 +- .../unimrcp/platforms/umc/src/dtmfsession.cpp | 22 +- libs/unimrcp/platforms/umc/src/main.cpp | 4 +- .../platforms/umc/src/recogscenario.cpp | 4 +- .../platforms/umc/src/recogsession.cpp | 63 +- .../platforms/umc/src/recorderscenario.cpp | 4 +- .../platforms/umc/src/recordersession.cpp | 4 +- .../platforms/umc/src/setparamscenario.cpp | 4 +- .../platforms/umc/src/setparamsession.cpp | 4 +- .../platforms/umc/src/synthscenario.cpp | 4 +- .../platforms/umc/src/synthsession.cpp | 51 +- libs/unimrcp/platforms/umc/src/umcconsole.cpp | 55 +- .../platforms/umc/src/umcframework.cpp | 51 +- .../unimrcp/platforms/umc/src/umcscenario.cpp | 40 +- libs/unimrcp/platforms/umc/src/umcsession.cpp | 30 +- .../platforms/umc/src/verifierscenario.cpp | 82 + .../platforms/umc/src/verifiersession.cpp | 389 +++++ libs/unimrcp/platforms/umc/umc.rc | 39 + libs/unimrcp/platforms/umc/umc.vcproj | 52 + .../unimrcp-client/include/demo_application.h | 10 +- .../unimrcp-client/include/demo_framework.h | 10 +- .../unimrcp-client/include/demo_util.h | 10 +- .../src/demo_bypass_application.c | 4 +- .../src/demo_discover_application.c | 4 +- .../unimrcp-client/src/demo_framework.c | 6 +- .../src/demo_recog_application.c | 4 +- .../src/demo_synth_application.c | 4 +- .../platforms/unimrcp-client/src/demo_util.c | 4 +- .../platforms/unimrcp-client/src/main.c | 51 +- .../unimrcp-client/unimrcpclient.2008.vcproj | 200 --- .../platforms/unimrcp-client/unimrcpclient.rc | 39 + .../unimrcp-client/unimrcpclient.vcproj | 36 + .../platforms/unimrcp-server/src/main.c | 45 +- .../unimrcp-server/src/uni_cmdline.c | 4 +- .../platforms/unimrcp-server/src/uni_daemon.c | 4 +- .../unimrcp-server/src/uni_service.c | 4 +- .../unimrcp-server/unimrcpserver.2008.vcproj | 174 --- .../platforms/unimrcp-server/unimrcpserver.rc | 39 + .../unimrcp-server/unimrcpserver.vcproj | 36 + libs/unimrcp/plugins/Makefile.am | 8 +- .../plugins/demo-recog/demorecog.2008.vcproj | 164 -- .../demo-recog/src/demo_recog_engine.c | 23 +- .../plugins/demo-synth/demosynth.2008.vcproj | 164 -- .../demo-synth/src/demo_synth_engine.c | 16 +- .../Makefile.am | 9 +- .../demoverifier.vcproj} | 16 +- .../demo-verifier/src/demo_verifier_engine.c | 577 ++++++++ .../mrcp-cepstral/mrcpcepstral.2008.vcproj | 164 -- .../plugins/mrcp-cepstral/src/mrcp_swift.c | 774 ---------- .../plugins/mrcp-flite/include/flite_voices.h | 10 +- .../plugins/mrcp-flite/mrcpflite.2008.vcproj | 172 --- .../plugins/mrcp-flite/src/flite_voices.c | 4 +- .../plugins/mrcp-flite/src/mrcp_flite.c | 8 +- .../mrcp-pocketsphinx/conf/pocketsphinx.xml | 3 +- .../include/pocketsphinx_properties.h | 16 +- .../mrcppocketsphinx.2008.vcproj | 172 --- .../mrcp-pocketsphinx/src/mrcp_pocketsphinx.c | 76 +- .../src/pocketsphinx_properties.c | 11 +- .../mrcp-recorder/src/mrcp_recorder_engine.c | 17 +- libs/unimrcp/tests/apttest/Makefile.am | 3 +- .../unimrcp/tests/apttest/apttest.2008.vcproj | 170 --- libs/unimrcp/tests/apttest/apttest.vcproj | 4 + .../tests/apttest/src/consumer_task_suite.c | 4 +- libs/unimrcp/tests/apttest/src/main.c | 8 +- .../tests/apttest/src/multipart_suite.c | 98 ++ libs/unimrcp/tests/apttest/src/task_suite.c | 4 +- .../unimrcp/tests/mpftest/mpftest.2008.vcproj | 166 --- libs/unimrcp/tests/mpftest/src/main.c | 4 +- libs/unimrcp/tests/mpftest/src/mpf_suite.c | 10 +- libs/unimrcp/tests/mrcptest/Makefile.am | 3 +- .../tests/mrcptest/mrcptest.2008.vcproj | 170 --- libs/unimrcp/tests/mrcptest/mrcptest.vcproj | 4 + libs/unimrcp/tests/mrcptest/src/main.c | 7 +- .../tests/mrcptest/src/parse_gen_suite.c | 47 +- .../tests/mrcptest/src/set_get_suite.c | 6 +- .../mrcptest/src/transparent_set_get_suite.c | 252 ++++ .../tests/rtsptest/rtsptest.2008.vcproj | 166 --- libs/unimrcp/tests/rtsptest/src/main.c | 4 +- .../tests/rtsptest/src/parse_gen_suite.c | 40 +- libs/unimrcp/tests/strtablegen/src/main.c | 4 +- .../tests/strtablegen/strtablegen.2008.vcproj | 162 -- libs/unimrcp/unimrcp.2008.sln | 292 ---- libs/unimrcp/unimrcp.sln | 64 +- src/mod/asr_tts/mod_unimrcp/Makefile.am | 2 +- src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c | 193 ++- 441 files changed, 17157 insertions(+), 16798 deletions(-) delete mode 100644 libs/unimrcp/build/acmacros/swift.m4 create mode 100755 libs/unimrcp/build/init.d/unimrcp-server create mode 100644 libs/unimrcp/build/svnrev/Makefile.am create mode 100644 libs/unimrcp/build/svnrev/svnrev.c create mode 100644 libs/unimrcp/build/svnrev/svnrev.input create mode 100644 libs/unimrcp/build/svnrev/svnrev.vcproj delete mode 100644 libs/unimrcp/build/tools/prepare.2008.vcproj delete mode 100644 libs/unimrcp/build/tools/preparesphinx.2008.vcproj delete mode 100644 libs/unimrcp/build/tools/unimrcpservice.2008.vcproj delete mode 100644 libs/unimrcp/build/vsprops/apr.props delete mode 100644 libs/unimrcp/build/vsprops/apt.props delete mode 100644 libs/unimrcp/build/vsprops/cepstral.vsprops delete mode 100644 libs/unimrcp/build/vsprops/mpf.props delete mode 100644 libs/unimrcp/build/vsprops/mrcp.props delete mode 100644 libs/unimrcp/build/vsprops/mrcpclient.props delete mode 100644 libs/unimrcp/build/vsprops/mrcpsignaling.props delete mode 100644 libs/unimrcp/build/vsprops/mrcpv2transport.props delete mode 100644 libs/unimrcp/build/vsprops/sofiasip.props delete mode 100644 libs/unimrcp/build/vsprops/unibase.props delete mode 100644 libs/unimrcp/build/vsprops/unidebug.props delete mode 100644 libs/unimrcp/build/vsprops/unimrcpplugin.vsprops delete mode 100644 libs/unimrcp/build/vsprops/unirelease.props delete mode 100644 libs/unimrcp/build/vsprops/unirtsp.props create mode 100644 libs/unimrcp/conf/client-profiles/lumenvox.xml create mode 100644 libs/unimrcp/conf/client-profiles/nuance.xml create mode 100644 libs/unimrcp/conf/client-profiles/speechpro.xml create mode 100644 libs/unimrcp/conf/client-profiles/unimrcp.xml create mode 100644 libs/unimrcp/conf/logger.xml create mode 100644 libs/unimrcp/conf/unimrcpclient.xsd create mode 100644 libs/unimrcp/conf/unimrcpserver.xsd create mode 100644 libs/unimrcp/data/grammar.mixed create mode 100644 libs/unimrcp/data/johnsmith-16kHz.pcm create mode 100644 libs/unimrcp/data/johnsmith-8kHz.pcm create mode 100644 libs/unimrcp/data/result-verification.xml rename libs/unimrcp/docs/{doxygen.conf => doxygen.conf.in} (91%) create mode 100644 libs/unimrcp/docs/mainpage.docs delete mode 100644 libs/unimrcp/libs/apr-toolkit/aprtoolkit.2008.vcproj delete mode 100644 libs/unimrcp/libs/apr-toolkit/aprtoolkit.2010.vcxproj delete mode 100644 libs/unimrcp/libs/apr-toolkit/aprtoolkit.2010.vcxproj.filters create mode 100644 libs/unimrcp/libs/apr-toolkit/include/apt_header_field.h create mode 100644 libs/unimrcp/libs/apr-toolkit/include/apt_multipart_content.h delete mode 100644 libs/unimrcp/libs/apr-toolkit/include/apt_net_client_task.h delete mode 100644 libs/unimrcp/libs/apr-toolkit/include/apt_net_server_task.h create mode 100644 libs/unimrcp/libs/apr-toolkit/include/apt_poller_task.h create mode 100644 libs/unimrcp/libs/apr-toolkit/include/apt_text_message.h create mode 100644 libs/unimrcp/libs/apr-toolkit/include/apt_timer_queue.h create mode 100644 libs/unimrcp/libs/apr-toolkit/src/apt_header_field.c create mode 100644 libs/unimrcp/libs/apr-toolkit/src/apt_multipart_content.c delete mode 100644 libs/unimrcp/libs/apr-toolkit/src/apt_net_client_task.c delete mode 100644 libs/unimrcp/libs/apr-toolkit/src/apt_net_server_task.c create mode 100644 libs/unimrcp/libs/apr-toolkit/src/apt_poller_task.c create mode 100644 libs/unimrcp/libs/apr-toolkit/src/apt_text_message.c create mode 100644 libs/unimrcp/libs/apr-toolkit/src/apt_timer_queue.c delete mode 100644 libs/unimrcp/libs/mpf/include/mpf_timer_manager.h delete mode 100644 libs/unimrcp/libs/mpf/mpf.2008.vcproj delete mode 100644 libs/unimrcp/libs/mpf/mpf.2010.vcxproj delete mode 100644 libs/unimrcp/libs/mpf/mpf.2010.vcxproj.filters delete mode 100644 libs/unimrcp/libs/mpf/src/mpf_timer_manager.c delete mode 100644 libs/unimrcp/libs/mrcp-client/mrcpclient.2008.vcproj delete mode 100644 libs/unimrcp/libs/mrcp-client/mrcpclient.2010.vcxproj delete mode 100644 libs/unimrcp/libs/mrcp-client/mrcpclient.2010.vcxproj.filters create mode 100644 libs/unimrcp/libs/mrcp-client/src/mrcp_application.c create mode 100644 libs/unimrcp/libs/mrcp-engine/include/mrcp_verifier_engine.h create mode 100644 libs/unimrcp/libs/mrcp-engine/include/mrcp_verifier_state_machine.h delete mode 100644 libs/unimrcp/libs/mrcp-engine/mrcpengine.2008.vcproj create mode 100644 libs/unimrcp/libs/mrcp-engine/src/mrcp_verifier_state_machine.c delete mode 100644 libs/unimrcp/libs/mrcp-server/mrcpserver.2008.vcproj delete mode 100644 libs/unimrcp/libs/mrcp-signaling/mrcpsignaling.2008.vcproj delete mode 100644 libs/unimrcp/libs/mrcp-signaling/mrcpsignaling.2010.vcxproj delete mode 100644 libs/unimrcp/libs/mrcp-signaling/mrcpsignaling.2010.vcxproj.filters create mode 100644 libs/unimrcp/libs/mrcp/message/include/mrcp_header.h create mode 100644 libs/unimrcp/libs/mrcp/message/src/mrcp_header.c delete mode 100644 libs/unimrcp/libs/mrcp/mrcp.2008.vcproj delete mode 100644 libs/unimrcp/libs/mrcp/mrcp.2010.vcxproj delete mode 100644 libs/unimrcp/libs/mrcp/mrcp.2010.vcxproj.filters create mode 100644 libs/unimrcp/libs/mrcp/resources/include/mrcp_verifier_header.h create mode 100644 libs/unimrcp/libs/mrcp/resources/include/mrcp_verifier_resource.h create mode 100644 libs/unimrcp/libs/mrcp/resources/src/mrcp_verifier_header.c create mode 100644 libs/unimrcp/libs/mrcp/resources/src/mrcp_verifier_resource.c delete mode 100644 libs/unimrcp/libs/mrcpv2-transport/mrcpv2transport.2008.vcproj delete mode 100644 libs/unimrcp/libs/mrcpv2-transport/mrcpv2transport.2010.vcxproj delete mode 100644 libs/unimrcp/libs/mrcpv2-transport/mrcpv2transport.2010.vcxproj.filters delete mode 100644 libs/unimrcp/libs/uni-rtsp/unirtsp.2008.vcproj delete mode 100644 libs/unimrcp/libs/uni-rtsp/unirtsp.2010.vcxproj delete mode 100644 libs/unimrcp/libs/uni-rtsp/unirtsp.2010.vcxproj.filters delete mode 100644 libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.2008.vcproj delete mode 100644 libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.2010.vcxproj delete mode 100644 libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.2010.vcxproj.filters delete mode 100644 libs/unimrcp/modules/mrcp-unirtsp/mrcpunirtsp.2008.vcproj delete mode 100644 libs/unimrcp/modules/mrcp-unirtsp/mrcpunirtsp.2010.vcxproj delete mode 100644 libs/unimrcp/modules/mrcp-unirtsp/mrcpunirtsp.2010.vcxproj.filters delete mode 100644 libs/unimrcp/packages/inno-setup/setup.iss delete mode 100644 libs/unimrcp/platforms/libunimrcp-client/libunimrcpclient.2008.vcproj delete mode 100644 libs/unimrcp/platforms/libunimrcp-server/libunimrcpserver.2008.vcproj create mode 100644 libs/unimrcp/platforms/umc/include/verifierscenario.h create mode 100644 libs/unimrcp/platforms/umc/include/verifiersession.h create mode 100644 libs/unimrcp/platforms/umc/src/verifierscenario.cpp create mode 100644 libs/unimrcp/platforms/umc/src/verifiersession.cpp create mode 100644 libs/unimrcp/platforms/umc/umc.rc delete mode 100644 libs/unimrcp/platforms/unimrcp-client/unimrcpclient.2008.vcproj create mode 100644 libs/unimrcp/platforms/unimrcp-client/unimrcpclient.rc delete mode 100644 libs/unimrcp/platforms/unimrcp-server/unimrcpserver.2008.vcproj create mode 100644 libs/unimrcp/platforms/unimrcp-server/unimrcpserver.rc delete mode 100644 libs/unimrcp/plugins/demo-recog/demorecog.2008.vcproj delete mode 100644 libs/unimrcp/plugins/demo-synth/demosynth.2008.vcproj rename libs/unimrcp/plugins/{mrcp-cepstral => demo-verifier}/Makefile.am (70%) rename libs/unimrcp/plugins/{mrcp-cepstral/mrcpcepstral.vcproj => demo-verifier/demoverifier.vcproj} (93%) create mode 100644 libs/unimrcp/plugins/demo-verifier/src/demo_verifier_engine.c delete mode 100644 libs/unimrcp/plugins/mrcp-cepstral/mrcpcepstral.2008.vcproj delete mode 100644 libs/unimrcp/plugins/mrcp-cepstral/src/mrcp_swift.c delete mode 100644 libs/unimrcp/plugins/mrcp-flite/mrcpflite.2008.vcproj delete mode 100644 libs/unimrcp/plugins/mrcp-pocketsphinx/mrcppocketsphinx.2008.vcproj delete mode 100644 libs/unimrcp/tests/apttest/apttest.2008.vcproj create mode 100644 libs/unimrcp/tests/apttest/src/multipart_suite.c delete mode 100644 libs/unimrcp/tests/mpftest/mpftest.2008.vcproj delete mode 100644 libs/unimrcp/tests/mrcptest/mrcptest.2008.vcproj create mode 100644 libs/unimrcp/tests/mrcptest/src/transparent_set_get_suite.c delete mode 100644 libs/unimrcp/tests/rtsptest/rtsptest.2008.vcproj delete mode 100644 libs/unimrcp/tests/strtablegen/strtablegen.2008.vcproj delete mode 100644 libs/unimrcp/unimrcp.2008.sln diff --git a/conf/autoload_configs/unimrcp.conf.xml b/conf/autoload_configs/unimrcp.conf.xml index 452936bf7c..45dda798a1 100644 --- a/conf/autoload_configs/unimrcp.conf.xml +++ b/conf/autoload_configs/unimrcp.conf.xml @@ -12,6 +12,7 @@ + diff --git a/libs/unimrcp/.update b/libs/unimrcp/.update index 2c9225f323..05e080f0c9 100644 --- a/libs/unimrcp/.update +++ b/libs/unimrcp/.update @@ -1 +1 @@ -Mon Feb 22 09:40:01 CST 2010 +Thu Jun 16 15:02:31 UTC 2011 diff --git a/libs/unimrcp/AUTHORS b/libs/unimrcp/AUTHORS index d032c9e71a..6c7b0eee09 100644 --- a/libs/unimrcp/AUTHORS +++ b/libs/unimrcp/AUTHORS @@ -14,3 +14,4 @@ Contributor(s): Carlos Pina Soares Chaitanya Chokkareddy Tomas Valenta + Danijel Korzinek diff --git a/libs/unimrcp/Makefile.am b/libs/unimrcp/Makefile.am index eeb00cecb4..0421198eb9 100644 --- a/libs/unimrcp/Makefile.am +++ b/libs/unimrcp/Makefile.am @@ -14,7 +14,7 @@ MAINTAINERCLEANFILES = Makefile.in aclocal.m4 configure $(AUX_DIST) ACLOCAL = aclocal -I $(macrodir) -SUBDIRS = conf data libs modules plugins platforms build +SUBDIRS = build conf data libs modules plugins platforms if TEST_SUITES SUBDIRS += tests endif diff --git a/libs/unimrcp/NOTICE b/libs/unimrcp/NOTICE index bcd5c17ac5..37f1bf3c01 100644 --- a/libs/unimrcp/NOTICE +++ b/libs/unimrcp/NOTICE @@ -1,5 +1,5 @@ The UniMRCP Project (http://www.unimrcp.org) -Copyright (C) 2008 Arsen Chaloyan +Copyright (C) 2008-2010 Arsen Chaloyan Licensed under the Apache License, Version 2.0 (the "License"). This product includes a number of subcomponents with diff --git a/libs/unimrcp/acinclude.m4 b/libs/unimrcp/acinclude.m4 index 46eb391ab8..7a487f7046 100644 --- a/libs/unimrcp/acinclude.m4 +++ b/libs/unimrcp/acinclude.m4 @@ -3,7 +3,6 @@ m4_include([build/acmacros/apu.m4]) m4_include([build/acmacros/find_apr.m4]) m4_include([build/acmacros/find_apu.m4]) m4_include([build/acmacros/sofia-sip.m4]) -m4_include([build/acmacros/swift.m4]) m4_include([build/acmacros/sphinxbase.m4]) m4_include([build/acmacros/pocketsphinx.m4]) m4_include([build/acmacros/flite.m4]) diff --git a/libs/unimrcp/build/Makefile.am b/libs/unimrcp/build/Makefile.am index dfacd94fc1..822c9173c8 100644 --- a/libs/unimrcp/build/Makefile.am +++ b/libs/unimrcp/build/Makefile.am @@ -1,5 +1,9 @@ MAINTAINERCLEANFILES = Makefile.in +CLEANFILES = uni_revision.h -SUBDIRS = pkgconfig +SUBDIRS = pkgconfig svnrev -include_HEADERS = uni_version.h +include_HEADERS = uni_version.h uni_revision.h + +uni_revision.h : + svnrev/svnrev -rsvnrev/svnrev.input -p../ -ouni_revision.h diff --git a/libs/unimrcp/build/acmacros/flite.m4 b/libs/unimrcp/build/acmacros/flite.m4 index a1991bc16b..5585e963b4 100644 --- a/libs/unimrcp/build/acmacros/flite.m4 +++ b/libs/unimrcp/build/acmacros/flite.m4 @@ -13,21 +13,28 @@ AC_DEFUN([UNIMRCP_CHECK_FLITE], found_flite="no" - flite_libdir="build/libs" + flite_config="config/config" for dir in $flite_path ; do cd $dir && flite_dir=`pwd` && cd - > /dev/null - if test -d "$dir/$flite_libdir"; then - found_flite="yes" - UNIMRCP_FLITE_INCLUDES="-I$flite_dir/include" - UNIMRCP_FLITE_LIBS="$dir/$flite_libdir/libflite_cmu_us_awb.a \ - $dir/$flite_libdir/libflite_cmu_us_kal.a \ - $dir/$flite_libdir/libflite_cmu_us_rms.a \ - $dir/$flite_libdir/libflite_cmu_us_slt.a \ - $dir/$flite_libdir/libflite_cmulex.a \ - $dir/$flite_libdir/libflite_usenglish.a \ - $dir/$flite_libdir/libflite.a" - break - fi + if test -f "$flite_dir/$flite_config"; then + target_os=`grep TARGET_OS "$flite_dir/$flite_config" | sed "s/^.*= //"` ;\ + target_cpu=`grep TARGET_CPU "$flite_dir/$flite_config" | sed "s/^.*= //"` ;\ + flite_libdir=$flite_dir/build/$target_cpu-$target_os/lib + if test -d "$flite_libdir"; then + UNIMRCP_FLITE_INCLUDES="-I$flite_dir/include" + UNIMRCP_FLITE_LIBS="$flite_libdir/libflite_cmu_us_awb.a \ + $flite_libdir/libflite_cmu_us_kal.a \ + $flite_libdir/libflite_cmu_us_rms.a \ + $flite_libdir/libflite_cmu_us_slt.a \ + $flite_libdir/libflite_cmulex.a \ + $flite_libdir/libflite_usenglish.a \ + $flite_libdir/libflite.a" + found_flite="yes" + break + else + AC_MSG_WARN(Cannot find Flite lib dir: $flite_libdir) + fi + fi done if test x_$found_flite != x_yes; then diff --git a/libs/unimrcp/build/acmacros/swift.m4 b/libs/unimrcp/build/acmacros/swift.m4 deleted file mode 100644 index b9049767a4..0000000000 --- a/libs/unimrcp/build/acmacros/swift.m4 +++ /dev/null @@ -1,28 +0,0 @@ -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 -]) diff --git a/libs/unimrcp/build/init.d/unimrcp-server b/libs/unimrcp/build/init.d/unimrcp-server new file mode 100755 index 0000000000..29be4f3653 --- /dev/null +++ b/libs/unimrcp/build/init.d/unimrcp-server @@ -0,0 +1,271 @@ +#!/bin/sh +# +# unimrcp-server This shell script takes care of starting and stopping the UniMRCP server. +# +# chkconfig: 2345 65 35 +# description: UniMRCP is an open source MRCP v1 & v2 server + +# Some global variables + +# Application +APP_NAME="unimrcpserver" +APP_LONG_NAME="unimrcpserver" +UNIMRCP_DIR="/usr/local/unimrcp/" + +EXEC="${UNIMRCP_DIR}bin/${APP_NAME} -d -o 2 -r ${UNIMRCP_DIR}" + +# sudo user +USERNAME=root + +# Priority at which to run the server. See "man nice" for valid priorities. +# nice is only used if a priority is specified. +PRIORITY= + +# Location of the pid file. +PIDDIR="/var/run/" +pid= + +LOG="/var/log/${APP_NAME}.log" + +if [ -e $PIDDIR ]; then +echo +else +mkdir $PIDDIR +fi + +# Allow configuration overrides in /etc/sysconfig/$APP_NAME +CONFIGFILE=/etc/sysconfig/$APP_NAME + +[ -x $CONFIGFILE ] && . $CONFIGFILE + +# Do not modify anything beyond this point +#----------------------------------------------------------------------------- + +# Get the fully qualified path to the script +case $0 in + /*) + SCRIPT="$0" + ;; + *) + PWD=`pwd` + SCRIPT="$PWD/$0" + ;; +esac + +# Change spaces to ":" so the tokens can be parsed. +SCRIPT=`echo $SCRIPT | sed -e 's; ;:;g'` +# Get the real path to this script, resolving any symbolic links +TOKENS=`echo $SCRIPT | sed -e 's;/; ;g'` +REALPATH= +for C in $TOKENS; do +REALPATH="$REALPATH/$C" + while [ -h "$REALPATH" ] ; do +LS="`ls -ld "$REALPATH"`" + LINK="`expr "$LS" : '.*-> \(.*\)$'`" + if expr "$LINK" : '/.*' > /dev/null; then +REALPATH="$LINK" + else +REALPATH="`dirname "$REALPATH"`""/$LINK" + fi +done +done +# Change ":" chars back to spaces. +REALPATH=`echo $REALPATH | sed -e 's;:; ;g'` + +# Change the current directory to the location of the script +cd "`dirname "$REALPATH"`" + +chown $USERNAME $PIDDIR + +# Process ID +PIDFILE="$PIDDIR/$APP_NAME.pid" + +# Resolve the location of the 'ps' command +PSEXE="/usr/bin/ps" +if [ ! -x $PSEXE ] +then +PSEXE="/bin/ps" + if [ ! -x $PSEXE ] + then +echo "Unable to locate 'ps'." + echo "Please report this with the location on your system." + exit 1 + fi +fi + +# Build the nice clause +if [ "X$PRIORITY" = "X" ] +then +CMDNICE="" +else +CMDNICE="nice -$PRIORITY" +fi + +getpid() { + if [ -f $PIDFILE ] + then +if [ -r $PIDFILE ] + then +pid=`cat $PIDFILE` + if [ "X$pid" != "X" ] + then + # Verify that a process with this pid is still running. + pid=`$PSEXE -p $pid | grep $pid | grep -v grep | awk '{print $1}' | tail -1` + if [ "X$pid" = "X" ] + then + # This is a stale pid file. + rm -f $PIDFILE + echo "Removed stale pid file: $PIDFILE" + fi +fi +else +echo "Cannot read $PIDFILE." + exit 1 + fi +fi +} + +testpid() { + pid=`$PSEXE -p $pid | grep $pid | grep -v grep | awk '{print $1}' | tail -1` + if [ "X$pid" = "X" ] + then + # Process is gone so remove the pid file. + rm -f $PIDFILE + fi +} + +console() { + echo "Running $APP_LONG_NAME..." + getpid + if [ "X$pid" = "X" ] + then +exec sudo -u $USERNAME $CMDNICE $EXEC + else +echo "$APP_LONG_NAME is already running." + exit 1 + fi +} + +start() { + echo "Starting $APP_LONG_NAME..." + getpid + if [ "X$pid" = "X" ] + then +sudo -u $USERNAME $CMDNICE $EXEC + pid=`$PSEXE -C $APP_NAME -o pid=` +echo $pid +echo $pid > $PIDFILE + else +echo "$APP_LONG_NAME is already running." + exit 1 + fi +} + +stopit() { + echo "Stopping $APP_LONG_NAME..." + getpid + if [ "X$pid" = "X" ] + then +echo "$APP_LONG_NAME was not running." + else + # Running so try to stop it. + sudo -u $USERNAME kill $pid + if [ $? -ne 0 ] + then + # An explanation for the failure should have been given + echo "Unable to stop $APP_LONG_NAME." + exit 1 + fi + + # We can not predict how long it will take for the wrapper to + # actually stop as it depends on settings in wrapper.conf. + # Loop until it does. + savepid=$pid + CNT=0 + TOTCNT=0 + while [ "X$pid" != "X" ] + do + # Loop for up to 5 minutes + if [ "$TOTCNT" -lt "300" ] + then +if [ "$CNT" -lt "5" ] + then +CNT=`expr $CNT + 1` + else +echo "Waiting for $APP_LONG_NAME to exit..." + CNT=0 + fi +TOTCNT=`expr $TOTCNT + 1` + + sleep 1 + + testpid + else +pid= + fi +done + +pid=$savepid + testpid + if [ "X$pid" != "X" ] + then +echo "Timed out waiting for $APP_LONG_NAME to exit." + echo " Attempting a forced exit..." + kill -9 $pid + fi + +pid=$savepid + testpid + if [ "X$pid" != "X" ] + then +echo "Failed to stop $APP_LONG_NAME." + exit 1 + else +echo "Stopped $APP_LONG_NAME." + fi +fi +} + +status() { + getpid + if [ "X$pid" = "X" ] + then +echo "$APP_LONG_NAME is not running." + exit 1 + else +echo "$APP_LONG_NAME is running ($pid)." + exit 0 + fi +} + +case "$1" in + + 'console') + console + ;; + + 'start') + start + ;; + + 'stop') + stopit + ;; + + 'restart') + stopit + start + ;; + + 'status') + status + ;; + + *) + echo "Usage: $0 { console | start | stop | restart | status }" + exit 1 + ;; +esac + +exit 0 + diff --git a/libs/unimrcp/build/svnrev/Makefile.am b/libs/unimrcp/build/svnrev/Makefile.am new file mode 100644 index 0000000000..5ce3ff2644 --- /dev/null +++ b/libs/unimrcp/build/svnrev/Makefile.am @@ -0,0 +1,10 @@ +MAINTAINERCLEANFILES = Makefile.in + +INCLUDES = $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES) + +noinst_PROGRAMS = svnrev +svnrev_LDADD = $(UNIMRCP_APR_LIBS) $(UNIMRCP_APU_LIBS) +svnrev_SOURCES = svnrev.c + +rev: + ./svnrev -rsvnrev.input -p../../ -o../uni_revision.h diff --git a/libs/unimrcp/build/svnrev/svnrev.c b/libs/unimrcp/build/svnrev/svnrev.c new file mode 100644 index 0000000000..154b07ef3f --- /dev/null +++ b/libs/unimrcp/build/svnrev/svnrev.c @@ -0,0 +1,381 @@ +/* SvnRev + * + * This utility retrieves the highest number that follows the "$Id: $" keyword + * or a combination of the $Rev: $ and $Date: $ keywords. The Subversion + * version control system expands these keywords and keeps them up to date. + * For an example of the tag, see the end of this comment. + * + * Details on the usage and the operation of this utility is available on-line + * at http://www.compuphase.com/svnrev.htm. + * + * + * Acknowledgements + * + * The support for .java files is contributed by Tom McCann (tommc@spoken.com). + * The option for prefixing and/or suffixing the build number (in the string + * constant SVN_REVSTR) was suggested by Robert Nitzel. + * + * + * License + * + * Copyright (c) 2005-2009, ITB CompuPhase (www.compuphase.com). + * + * This software is provided "as-is", without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from + * the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software in + * a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Version: $Id: svnrev.c 1497 2010-02-12 17:20:21Z achaloyan $ + */ + +#include +#include +#include + +#include +#include + + +#if defined __WIN32__ || defined _Win32 || defined _WIN32 + #define DIRSEP '\\' +#elif defined macintosh + #define DIRSEP ':' +#else + /* assume Linux/Unix */ + #define DIRSEP '/' +#endif + +#define MAX_LINELENGTH 512 +#define MAX_SYMBOLLENGTH 32 + +static void about(void) +{ + printf("svnrev 1.7.\n\n"); + printf("Usage: svnrev [options] [input [...]]\n\n" + "Options:\n" + "-ofilename\tOutput filename for the file with the build number. When no\n" + "\t\tfilename follows \"-o\", the result is written to stdout. The\n" + "\t\tdefault filename is \"svnrev.h\" for C/C++ and \"VersionInfo.java\"\n" + "\t\tfor Java.\n\n" + "-fpattern\tFormat: Adds text before or after the build number in the\n" + "\t\tconstant SVN_REVSTR. The pattern has the form \"text#text\"\n" + "\t\t(without the quotes) where \"text\" is arbitrary text and \"#\"\n" + "\t\twill be replaced by the build number.\n\n" + "-i\t\tIncremental: this option should be used when the list of input\n" + "\t\tfiles is a subset of all files in the project. When -i is\n" + "\t\tpresent, svnrev also scans the output file that was generated\n" + "\t\ton a previous run.\n\n" + "-jname\t\tJava: this option writes a java package file instead of a C/C++\n" + "\t\theader file. The name of the Java package must follow the\n" + "\t\toption (this is not the filename).\n\n" + "-v\t\tVerbose: prints the names of files that are modified since the\n" + "\t\tlast commit (into version control) to stderr.\n"); + exit(1); +} + +static void processfile(const char *name, int failsilent, + int *max_build, int *accum_build, + int *max_year, int *max_month, int *max_day, + int *ismodified) + +{ + char str[MAX_LINELENGTH], str_base[MAX_LINELENGTH]; + char name_base[MAX_LINELENGTH]; + char *p1; + FILE *fp, *fp_base; + int build, maj_build; + int year, month, day; + int cnt; + char modchar; + + /* since we also want to verify whether the file is modified in version + * control, get the path to the working copy name + * for every source file "\, the "working copy" base can + * be found in "\.svn\text-base\.svn-base" + */ + if ((p1 = strrchr(name, DIRSEP)) != NULL) { + ++p1; /* skip directory separator character ('\' in Windows, '/' in Linux) */ + strncpy(name_base, name, (int)(p1 - name)); + name_base[(int)(p1 - name)] = '\0'; + } else { + name_base[0] = '\0'; + p1 = (char*)name; + } /* if */ + sprintf(name_base + strlen(name_base), ".svn%ctext-base%c%s.svn-base", + DIRSEP, DIRSEP, p1); + + /* first extract the revision keywords */ + fp = fopen(name, "r"); + if (fp == NULL) { + if (!failsilent) + fprintf(stderr, "Failed to open input file '%s'\n", name); + return; + } /* if */ + fp_base = fopen(name_base, "r"); /* fail silently */ + build = 0; + maj_build = 0; /* RCS / CVS */ + year = month = day = 0; + + while (fgets(str, sizeof str, fp) != NULL) { + if (fp_base == NULL || fgets(str_base, sizeof str_base, fp_base) == NULL) + str_base[0] = '\0'; + if ((p1 = strstr(str, "$Id:")) != NULL && strchr(p1+1, '$') != NULL) { + if (sscanf(p1, "$Id: %*s %d %d-%d-%d", &build, &year, &month, &day) < 4 + && sscanf(p1, "$Id: %*s %d %d/%d/%d", &build, &year, &month, &day) < 4) + if (sscanf(p1, "$Id: %*s %d.%d %d-%d-%d", &maj_build, &build, &year, &month, &day) < 5) + sscanf(p1, "$Id: %*s %d.%d %d/%d/%d", &maj_build, &build, &year, &month, &day); + } else if ((p1 = strstr(str, "$Rev:")) != NULL && strchr(p1+1, '$') != NULL) { + if (sscanf(p1, "$Rev: %d.%d", &maj_build, &build) < 2) { + sscanf(p1, "$Rev: %d", &build); + maj_build = 0; + } /* if */ + } else if ((p1 = strstr(str, "$Revision:")) != NULL && strchr(p1+1, '$') != NULL) { + if (sscanf(p1, "$Revision: %d.%d", &maj_build, &build) < 2) { + /* SvnRev also writes this keyword in its own generated file; read it + * back for partial updates + */ + cnt = sscanf(p1, "$Revision: %d%c", &build, &modchar); + if (cnt == 2 && modchar == 'M' && ismodified != NULL) + *ismodified = 1; + maj_build = 0; + } /* if */ + } else if ((p1 = strstr(str, "$Date:")) != NULL && strchr(p1+1, '$') != NULL) { + if (sscanf(p1, "$Date: %d-%d-%d", &year, &month, &day) < 3) + sscanf(p1, "$Date: %d/%d/%d", &year, &month, &day); + } else if (ismodified != NULL && *ismodified == 0 && fp_base != NULL) { + /* no keyword present, compare the lines for equivalence */ + *ismodified = strcmp(str, str_base) != 0; + } /* if */ + + if (maj_build) + *accum_build += build; /* RCS / CVS */ + else if (build > *max_build) + *max_build = build; /* Subversion */ + if (year > *max_year + || (year == *max_year && month > *max_month) + || (year == *max_year && month == *max_month && day > *max_day)) + { + *max_year = year; + *max_month = month; + *max_day = day; + } /* if */ + if (build > 0 && year > 0 && (fp_base == NULL || ismodified == NULL || *ismodified != 0)) + break; /* both build # and date found, not comparing or modification + * already found => no need to search further */ + + } /* while */ + fclose(fp); + if (fp_base != NULL) + fclose(fp_base); +} + +int main(int argc, char *argv[]) +{ + char *outname = NULL; + FILE *fp; + FILE *input_file; + char *input_file_name = NULL; + char *path_prefix = NULL; + int index; + int process_self = 0; + int verbose = 0; + int max_build, accum_build; + int max_year, max_month, max_day; + int ismodified, filemodified; + char prefix[MAX_SYMBOLLENGTH], suffix[MAX_SYMBOLLENGTH]; + char modified_suffix[2]; + int write_java = 0; /* flag for Java output, 0=.h output, 1=.java output */ + /* java package to put revision info in. + * REVIEW - I assume if you want Java output you will specify a package. */ + char *java_package = NULL; + + if (argc <= 1) + about(); + + /* collect the options */ + prefix[0] = '\0'; + suffix[0] = '\0'; + + for (index = 1; index < argc; index++) { + /* check for options */ + if (argv[index][0] == '-' +#if defined __WIN32__ || defined _Win32 || defined _WIN32 + || argv[index][0] == '/' +#endif + ) + { + switch (argv[index][1]) { + case 'f': { + int len; + char *ptr = strchr(&argv[index][2], '#'); + len = (ptr != NULL) ? (int)(ptr - &argv[index][2]) : (int)strlen(&argv[index][2]); + if (len >= MAX_SYMBOLLENGTH) + len = MAX_SYMBOLLENGTH - 1; + strncpy(prefix, &argv[index][2], len); + prefix[len] = '\0'; + ptr = (ptr != NULL) ? ptr + 1 : strchr(argv[index], '\0'); + len = (int)strlen(ptr); + if (len >= MAX_SYMBOLLENGTH) + len = MAX_SYMBOLLENGTH - 1; + strncpy(suffix, ptr, len); + suffix[len] = '\0'; + break; + } /* case */ + case 'i': + process_self = 1; + break; + case 'j': + write_java=1; + java_package = &argv[index][2]; + break; + case 'o': + outname = &argv[index][2]; + break; + case 'r': + input_file_name = &argv[index][2]; + break; + case 'p': + path_prefix = &argv[index][2]; + break; + case 'v': + verbose = 1; + break; + default: + fprintf(stderr, "Invalid option '%s'\n", argv[index]); + about(); + } /* switch */ + } /* if */ + } /* for */ + + if (outname == NULL) + outname = write_java ? "SvnRevision.java" : "uni_revision.h"; + if (!process_self && *outname != '\0') + remove(outname); + + /* phase 1: scan through all files and get the highest build number */ + + max_build = 0; + accum_build = 0; /* for RCS / CVS */ + max_year = max_month = max_day = 0; + ismodified = 0; + + if(input_file_name) { + input_file = fopen(input_file_name, "r"); + if (input_file != NULL) { + apr_dir_t *dir; + apr_finfo_t finfo; + apr_status_t rv; + apr_pool_t *pool; + char *file_path; + char dir_path[256]; /* line */ + int offset = 0; + if(path_prefix) + offset = sprintf(dir_path, "%s", path_prefix); + else + offset = sprintf(dir_path, "../../"); + + apr_initialize(); + apr_pool_create(&pool,NULL); + while (fgets(dir_path + offset, sizeof(dir_path) - offset, input_file) != NULL ) { /* read a line */ + size_t len = strlen(dir_path)-1; + if(dir_path[len] == '\n') + dir_path[len] = 0; + rv = apr_dir_open(&dir,dir_path,pool); + if(rv == APR_SUCCESS) { + while (apr_dir_read(&finfo, APR_FINFO_NAME, dir) == APR_SUCCESS) { /* get next file */ + if(finfo.filetype != APR_REG) continue; + + apr_filepath_merge(&file_path,dir_path,finfo.name,0,pool); + + filemodified = 0; + if (strcasecmp(file_path, outname)!=0) + processfile(file_path, 0, &max_build, &accum_build, &max_year, &max_month, &max_day, &filemodified); + if (filemodified && verbose) + fprintf(stderr, "\tNotice: modified file '%s'\n", file_path); + ismodified = ismodified || filemodified; + } + apr_dir_close(dir); + } + else { + fprintf(stderr, "No such directory '%s'\n", dir_path); + } + } + fclose (input_file); + apr_pool_destroy(pool); + apr_terminate(); + } + else { + fprintf(stderr, "No such input file '%s'\n", input_file_name); + } + } + else { + for (index = 1; index < argc; index++) { + /* skip the options (already handled) */ + if (argv[index][0] == '-' +#if defined __WIN32__ || defined _Win32 || defined _WIN32 + || argv[index][0] == '/' +#endif + ) + continue; + + filemodified = 0; + if (strcasecmp(argv[index], outname)!=0) + processfile(argv[index], 0, &max_build, &accum_build, &max_year, &max_month, &max_day, &filemodified); + if (filemodified && verbose) + fprintf(stderr, "\tNotice: modified file '%s'\n", argv[index]); + ismodified = ismodified || filemodified; + } /* for */ + } + + /* also run over the existing header file, if any */ + if (process_self && *outname != '\0') + processfile(outname, 1, &max_build, &accum_build, &max_year, &max_month, &max_day, NULL/*&ismodified*/); + + if (accum_build > max_build) + max_build = accum_build; + modified_suffix[0] = ismodified ? 'M' : '\0'; + modified_suffix[1] = '\0'; + + /* phase 2: write a file with this highest build number */ + if (*outname == '\0') { + fp = stdout; + } else if ((fp = fopen(outname, "w")) == NULL) { + fprintf(stderr, "Failed to create output file '%s'\n", outname); + return 2; + } /* if */ + if (*outname != '\0') { + /* don't print the comments to stdout */ + fprintf(fp, "/* This file was generated by the \"svnrev\" utility\n" + " * (http://www.compuphase.com/svnrev.htm).\n" + " * You should not modify it manually, as it may be re-generated.\n" + " *\n" + " * $Revision: %d%s$\n" + " * $Date: %04d-%02d-%02d$\n" + " */\n\n", max_build, modified_suffix, max_year, max_month, max_day); + } /* if */ + + fprintf(fp, "#ifndef UNI_REVISION_H\n"); + fprintf(fp, "#define UNI_REVISION_H\n\n"); + fprintf(fp, "#define UNI_REVISION\t\t%d\n", max_build); + fprintf(fp, "#define UNI_REVISION_STRING\t\"%s%d%s%s\"\n", prefix, max_build, modified_suffix, suffix); + fprintf(fp, "#define UNI_REVISION_DATE\t\"%04d-%02d-%02d\"\n", max_year, max_month, max_day); + fprintf(fp, "#define UNI_REVISION_STAMP\t%04d%02d%02dL\n", max_year, max_month, max_day); + fprintf(fp, "#define UNI_REVISION_MODIFIED\t%d\n", ismodified); + fprintf(fp, "\n#endif /* UNI_REVISION_H */\n"); + + if (*outname != '\0') + fclose(fp); + + return 0; +} diff --git a/libs/unimrcp/build/svnrev/svnrev.input b/libs/unimrcp/build/svnrev/svnrev.input new file mode 100644 index 0000000000..1f73eb847e --- /dev/null +++ b/libs/unimrcp/build/svnrev/svnrev.input @@ -0,0 +1,32 @@ +build +libs/apr-toolkit/include +libs/apr-toolkit/src +libs/mpf/include +libs/mpf/src +libs/mrcp/control/include +libs/mrcp/control/src +libs/mrcp/include +libs/mrcp/message/include +libs/mrcp/message/src +libs/mrcp/resources/include +libs/mrcp/resources/src +libs/mrcp-client/include +libs/mrcp-client/src +libs/mrcp-server/include +libs/mrcp-server/src +libs/mrcp-engine/include +libs/mrcp-engine/src +libs/mrcp-signaling/include +libs/mrcp-signaling/src +libs/mrcpv2-transport/include +libs/mrcpv2-transport/src +libs/uni-rtsp/include +libs/uni-rtsp/src +modules/mrcp-sofiasip/include +modules/mrcp-sofiasip/src +modules/mrcp-unirtsp/include +modules/mrcp-unirtsp/src +platforms/libunimrcp-client/include +platforms/libunimrcp-client/src +platforms/libunimrcp-server/include +platforms/libunimrcp-server/src \ No newline at end of file diff --git a/libs/unimrcp/build/svnrev/svnrev.vcproj b/libs/unimrcp/build/svnrev/svnrev.vcproj new file mode 100644 index 0000000000..44259880b7 --- /dev/null +++ b/libs/unimrcp/build/svnrev/svnrev.vcproj @@ -0,0 +1,345 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/unimrcp/build/tools/prepare.2008.vcproj b/libs/unimrcp/build/tools/prepare.2008.vcproj deleted file mode 100644 index d19d002f7e..0000000000 --- a/libs/unimrcp/build/tools/prepare.2008.vcproj +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/unimrcp/build/tools/prepare.vcproj b/libs/unimrcp/build/tools/prepare.vcproj index 370cabb3f6..4fec72ee99 100644 --- a/libs/unimrcp/build/tools/prepare.vcproj +++ b/libs/unimrcp/build/tools/prepare.vcproj @@ -28,7 +28,7 @@ > - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/unimrcp/build/tools/unimrcp_service.c b/libs/unimrcp/build/tools/unimrcp_service.c index b8a1bd7a2d..c76459fa19 100644 --- a/libs/unimrcp/build/tools/unimrcp_service.c +++ b/libs/unimrcp/build/tools/unimrcp_service.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: unimrcp_service.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include diff --git a/libs/unimrcp/build/tools/unimrcpservice.2008.vcproj b/libs/unimrcp/build/tools/unimrcpservice.2008.vcproj deleted file mode 100644 index 2ae65f7c05..0000000000 --- a/libs/unimrcp/build/tools/unimrcpservice.2008.vcproj +++ /dev/null @@ -1,158 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/unimrcp/build/tools/unimrcpservice.vcproj b/libs/unimrcp/build/tools/unimrcpservice.vcproj index 0b3f899e18..1c0b13840f 100644 --- a/libs/unimrcp/build/tools/unimrcpservice.vcproj +++ b/libs/unimrcp/build/tools/unimrcpservice.vcproj @@ -51,7 +51,7 @@ /> - /** 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 +#define UNI_MAJOR_VERSION 1 /** minor version * Minor API changes that do not cause binary compatibility problems. * Reset to 0 when upgrading UNI_MAJOR_VERSION */ -#define UNI_MINOR_VERSION 9 +#define UNI_MINOR_VERSION 0 /** patch level * The Patch Level never includes API changes, simply bug fixes. @@ -57,10 +57,40 @@ || ((major) == UNI_MAJOR_VERSION && (minor) < UNI_MINOR_VERSION) \ || ((major) == UNI_MAJOR_VERSION && (minor) == UNI_MINOR_VERSION && (patch) <= UNI_PATCH_VERSION)) + +/** Properly quote a value as a string in the C preprocessor */ +#define UNI_STRINGIFY(n) UNI_STRINGIFY_HELPER(n) +/** Helper macro for UNI_STRINGIFY */ +#define UNI_STRINGIFY_HELPER(n) #n + /** 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) + UNI_STRINGIFY(UNI_MAJOR_VERSION) "." \ + UNI_STRINGIFY(UNI_MINOR_VERSION) "." \ + UNI_STRINGIFY(UNI_PATCH_VERSION) + +/** An alternative formatted string of UniMRCP's version + macro for Win32 .rc files using numeric csv representation */ +#define UNI_VERSION_STRING_CSV UNI_MAJOR_VERSION ##, \ + ##UNI_MINOR_VERSION ##, \ + ##UNI_PATCH_VERSION + +/** The Copyright */ +#define UNI_COPYRIGHT "Copyright 2008-2010 Arsen Chaloyan" + +/** The License */ +#define UNI_LICENSE \ + "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." + -#endif /* __UNI_VERSION_H__ */ +#endif /* UNI_VERSION_H */ diff --git a/libs/unimrcp/build/vsprops/apr.props b/libs/unimrcp/build/vsprops/apr.props deleted file mode 100644 index 660a970181..0000000000 --- a/libs/unimrcp/build/vsprops/apr.props +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - $(LibRootDir)libs\apr - $(LibRootDir)libs\apr-util - $(LibRootDir)libs\apr-iconv - - - <_ProjectFileVersion>10.0.30319.1 - - - - $(AprDir)\include;$(AprUtilDir)\include;%(AdditionalIncludeDirectories) - - - - - $(AprDir) - - - $(AprUtilDir) - - - $(AprIconvDir) - - - \ No newline at end of file diff --git a/libs/unimrcp/build/vsprops/apt.props b/libs/unimrcp/build/vsprops/apt.props deleted file mode 100644 index 8ede1684dc..0000000000 --- a/libs/unimrcp/build/vsprops/apt.props +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - <_ProjectFileVersion>10.0.30319.1 - - - - $(ProjectRootDir)libs\apr-toolkit\include;%(AdditionalIncludeDirectories) - APT_STATIC_LIB;%(PreprocessorDefinitions) - - - \ No newline at end of file diff --git a/libs/unimrcp/build/vsprops/cepstral.vsprops b/libs/unimrcp/build/vsprops/cepstral.vsprops deleted file mode 100644 index 8df44eba0f..0000000000 --- a/libs/unimrcp/build/vsprops/cepstral.vsprops +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - diff --git a/libs/unimrcp/build/vsprops/mpf.props b/libs/unimrcp/build/vsprops/mpf.props deleted file mode 100644 index ff68ceaef2..0000000000 --- a/libs/unimrcp/build/vsprops/mpf.props +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - <_ProjectFileVersion>10.0.30319.1 - - - - $(ProjectRootDir)libs\mpf\include;%(AdditionalIncludeDirectories) - MPF_STATIC_LIB;%(PreprocessorDefinitions) - - - \ No newline at end of file diff --git a/libs/unimrcp/build/vsprops/mrcp.props b/libs/unimrcp/build/vsprops/mrcp.props deleted file mode 100644 index fa4ee3539b..0000000000 --- a/libs/unimrcp/build/vsprops/mrcp.props +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - <_ProjectFileVersion>10.0.30319.1 - - - - $(ProjectRootDir)libs\mrcp\include;$(ProjectRootDir)libs\mrcp\message\include;$(ProjectRootDir)libs\mrcp\control\include;$(ProjectRootDir)libs\mrcp\resources\include;%(AdditionalIncludeDirectories) - MRCP_STATIC_LIB;%(PreprocessorDefinitions) - - - \ No newline at end of file diff --git a/libs/unimrcp/build/vsprops/mrcpclient.props b/libs/unimrcp/build/vsprops/mrcpclient.props deleted file mode 100644 index b650e07d91..0000000000 --- a/libs/unimrcp/build/vsprops/mrcpclient.props +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - - - - $(ProjectRootDir)libs\mrcp-client\include;%(AdditionalIncludeDirectories) - - - \ No newline at end of file diff --git a/libs/unimrcp/build/vsprops/mrcpsignaling.props b/libs/unimrcp/build/vsprops/mrcpsignaling.props deleted file mode 100644 index 5e0c884a9f..0000000000 --- a/libs/unimrcp/build/vsprops/mrcpsignaling.props +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - - - - $(ProjectRootDir)libs\mrcp-signaling\include;%(AdditionalIncludeDirectories) - - - \ No newline at end of file diff --git a/libs/unimrcp/build/vsprops/mrcpv2transport.props b/libs/unimrcp/build/vsprops/mrcpv2transport.props deleted file mode 100644 index c71836559b..0000000000 --- a/libs/unimrcp/build/vsprops/mrcpv2transport.props +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - <_ProjectFileVersion>10.0.30319.1 - - - - $(ProjectRootDir)libs\mrcpv2-transport\include;%(AdditionalIncludeDirectories) - - - \ No newline at end of file diff --git a/libs/unimrcp/build/vsprops/sofiasip.props b/libs/unimrcp/build/vsprops/sofiasip.props deleted file mode 100644 index 3714d30977..0000000000 --- a/libs/unimrcp/build/vsprops/sofiasip.props +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - $(LibRootDir)libs\sofia-sip - - - <_ProjectFileVersion>10.0.30319.1 - - - - $(SofiaDir)\win32;$(SofiaDir)\libsofia-sip-ua\su;$(SofiaDir)\libsofia-sip-ua\nua;$(SofiaDir)\libsofia-sip-ua\url;$(SofiaDir)\libsofia-sip-ua\sip;$(SofiaDir)\libsofia-sip-ua\msg;$(SofiaDir)\libsofia-sip-ua\sdp;$(SofiaDir)\libsofia-sip-ua\nta;$(SofiaDir)\libsofia-sip-ua\nea;$(SofiaDir)\libsofia-sip-ua\soa;$(SofiaDir)\libsofia-sip-ua\iptsec;$(SofiaDir)\libsofia-sip-ua\bnf;$(SofiaDir)\libsofia-sip-ua\features;%(AdditionalIncludeDirectories) - - - - - $(SofiaDir) - - - \ No newline at end of file diff --git a/libs/unimrcp/build/vsprops/unibase.props b/libs/unimrcp/build/vsprops/unibase.props deleted file mode 100644 index 097e8596ab..0000000000 --- a/libs/unimrcp/build/vsprops/unibase.props +++ /dev/null @@ -1,26 +0,0 @@ - - - - $(ProjectDir)..\..\ - $(SolutionDir) - - - <_ProjectFileVersion>10.0.30319.1 - - - - WIN32;%(PreprocessorDefinitions) - Level4 - true - 4100;%(DisableSpecificWarnings) - - - - - $(ProjectRootDir) - - - $(LibRootDir) - - - \ No newline at end of file diff --git a/libs/unimrcp/build/vsprops/unidebug.props b/libs/unimrcp/build/vsprops/unidebug.props deleted file mode 100644 index e9778995ab..0000000000 --- a/libs/unimrcp/build/vsprops/unidebug.props +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - <_ProjectFileVersion>10.0.30319.1 - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - ProgramDatabase - - - \ No newline at end of file diff --git a/libs/unimrcp/build/vsprops/unimrcpclient.vsprops b/libs/unimrcp/build/vsprops/unimrcpclient.vsprops index 613b2ff02f..8f1edceebd 100644 --- a/libs/unimrcp/build/vsprops/unimrcpclient.vsprops +++ b/libs/unimrcp/build/vsprops/unimrcpclient.vsprops @@ -11,6 +11,6 @@ /> diff --git a/libs/unimrcp/build/vsprops/unimrcpplugin.vsprops b/libs/unimrcp/build/vsprops/unimrcpplugin.vsprops deleted file mode 100644 index 53c6857dfd..0000000000 --- a/libs/unimrcp/build/vsprops/unimrcpplugin.vsprops +++ /dev/null @@ -1,17 +0,0 @@ - - - - - diff --git a/libs/unimrcp/build/vsprops/unimrcpserver.vsprops b/libs/unimrcp/build/vsprops/unimrcpserver.vsprops index 0a44b670dd..8f812676ea 100644 --- a/libs/unimrcp/build/vsprops/unimrcpserver.vsprops +++ b/libs/unimrcp/build/vsprops/unimrcpserver.vsprops @@ -11,6 +11,6 @@ /> diff --git a/libs/unimrcp/build/vsprops/unirelease.props b/libs/unimrcp/build/vsprops/unirelease.props deleted file mode 100644 index 8081506815..0000000000 --- a/libs/unimrcp/build/vsprops/unirelease.props +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - <_ProjectFileVersion>10.0.30319.1 - - - - NDEBUG;%(PreprocessorDefinitions) - MultiThreadedDLL - - - ProgramDatabase - - - \ No newline at end of file diff --git a/libs/unimrcp/build/vsprops/unirtsp.props b/libs/unimrcp/build/vsprops/unirtsp.props deleted file mode 100644 index 7ed01cb9a8..0000000000 --- a/libs/unimrcp/build/vsprops/unirtsp.props +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - <_ProjectFileVersion>10.0.30319.1 - - - - $(ProjectRootDir)libs\uni-rtsp\include;%(AdditionalIncludeDirectories) - RTSP_STATIC_LIB;%(PreprocessorDefinitions) - - - \ No newline at end of file diff --git a/libs/unimrcp/conf/Makefile.am b/libs/unimrcp/conf/Makefile.am index 9241bbe561..d317e66ecb 100644 --- a/libs/unimrcp/conf/Makefile.am +++ b/libs/unimrcp/conf/Makefile.am @@ -2,10 +2,17 @@ MAINTAINERCLEANFILES = Makefile.in def-conf: test -d $(confdir) || $(mkinstalldirs) $(confdir) - for conffile in `find ./ -name \*.xml` ; do \ + for conffile in `find ./ -maxdepth 1 -name \*.xml -o -name \*.xsd` ; do \ filename=`echo $$conffile | sed -e 's|^.*/||'`; \ $(INSTALL) -m 644 $$filename $(confdir); \ done + test -d $(confdir)/client-profiles || $(mkinstalldirs) $(confdir)/client-profiles + for conffile in `find ./client-profiles/ -maxdepth 1 -name \*.xml -o -name \*.xsd` ; do \ + filename=`echo $$conffile | sed -e 's|^.*/||'`; \ + $(INSTALL) -m 644 client-profiles/$$filename $(confdir)/client-profiles; \ + done + + install-data-local: test -d $(confdir) || $(MAKE) def-conf diff --git a/libs/unimrcp/conf/client-profiles/lumenvox.xml b/libs/unimrcp/conf/client-profiles/lumenvox.xml new file mode 100644 index 0000000000..4b592a5450 --- /dev/null +++ b/libs/unimrcp/conf/client-profiles/lumenvox.xml @@ -0,0 +1,50 @@ + + + + + + + + + 5060 + + + + + + + + 554 + + + + + + + + + + + + SIP-Agent-1 + MRCPv2-Agent-1 + Media-Engine-1 + RTP-Factory-1 + LumenVox-SIP-Settings + RTP-Settings-1 + + + + + RTSP-Agent-1 + Media-Engine-1 + RTP-Factory-1 + LumenVox-RTSP-Settings + RTP-Settings-1 + + + + + diff --git a/libs/unimrcp/conf/client-profiles/nuance.xml b/libs/unimrcp/conf/client-profiles/nuance.xml new file mode 100644 index 0000000000..083f0cf8c4 --- /dev/null +++ b/libs/unimrcp/conf/client-profiles/nuance.xml @@ -0,0 +1,76 @@ + + + + + + + + + 5060 + + + + + + + + + 4900 + + media + + + + + + + + + + 50 + 200 + + 20 + PCMU PCMA L16/96/8000 telephone-event/101/8000 + + + + 2 + + 5000 + + 1000 + + + + + + + + + SIP-Agent-1 + MRCPv2-Agent-1 + Media-Engine-1 + RTP-Factory-1 + Nuance-SIP-Settings + Nuance-RTP-Settings + + + + + RTSP-Agent-1 + Media-Engine-1 + RTP-Factory-1 + Nuance-RTSP-Settings + Nuance-RTP-Settings + + + + + diff --git a/libs/unimrcp/conf/client-profiles/speechpro.xml b/libs/unimrcp/conf/client-profiles/speechpro.xml new file mode 100644 index 0000000000..9f765bef61 --- /dev/null +++ b/libs/unimrcp/conf/client-profiles/speechpro.xml @@ -0,0 +1,33 @@ + + + + + + + + + 8000 + + + + + + + + + + + + + RTSP-Agent-1 + Media-Engine-1 + RTP-Factory-1 + SpeechPro-RTSP-Settings + RTP-Settings-1 + + + + + diff --git a/libs/unimrcp/conf/client-profiles/unimrcp.xml b/libs/unimrcp/conf/client-profiles/unimrcp.xml new file mode 100644 index 0000000000..e29d8784fd --- /dev/null +++ b/libs/unimrcp/conf/client-profiles/unimrcp.xml @@ -0,0 +1,51 @@ + + + + + + + + + 8060 + + + + + + + + 1554 + + media + + + + + + + + + + + SIP-Agent-1 + MRCPv2-Agent-1 + Media-Engine-1 + RTP-Factory-1 + UniMRCP-SIP-Settings + RTP-Settings-1 + + + + + RTSP-Agent-1 + Media-Engine-1 + RTP-Factory-1 + UniMRCP-RTSP-Settings + RTP-Settings-1 + + + + + diff --git a/libs/unimrcp/conf/logger.xml b/libs/unimrcp/conf/logger.xml new file mode 100644 index 0000000000..73ae9b5cac --- /dev/null +++ b/libs/unimrcp/conf/logger.xml @@ -0,0 +1,38 @@ + + + + + INFO + + + CONSOLE + + + DATE,TIME,PRIORITY + + + NONE + diff --git a/libs/unimrcp/conf/umcscenarios.xml b/libs/unimrcp/conf/umcscenarios.xml index a9f1ce67cb..d5c713e201 100644 --- a/libs/unimrcp/conf/umcscenarios.xml +++ b/libs/unimrcp/conf/umcscenarios.xml @@ -1,3 +1,4 @@ + - + @@ -33,7 +35,7 @@ For instance, --> - + @@ -55,7 +57,7 @@ For instance, --> - + @@ -72,7 +74,7 @@ For instance, --> - + --> @@ -89,8 +91,24 @@ For instance, --> - + + + + + + + + + + + + + - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - - - - - - - - - - - - - + + + + + + 8062 + udp + UniMRCP SofiaSIP + UniMRCPClient + + + + + - - - + + 100 + + UniMRCPClient + + + + + 100 + false + 1024 + 1024 + + + + + + 1 + + + + + + + + 4000 + 5000 + + + + + + + + 50 + 200 + + 20 + PCMU PCMA L16/96/8000 telephone-event/101/8000 + + + + - + 1 - + 5000 - - - - - - - - - - - - - - - - - - - - - - - + 1000 + + + diff --git a/libs/unimrcp/conf/unimrcpclient.xsd b/libs/unimrcp/conf/unimrcpclient.xsd new file mode 100644 index 0000000000..349cae4252 --- /dev/null +++ b/libs/unimrcp/conf/unimrcpclient.xsd @@ -0,0 +1,266 @@ + + + + + UniMRCP client document + + + + + + Generic properties + + + + + + + + + + + + + + + + + + + + + + + + Common components + + + + + + Factory of MRCP resources + + + + + + + + + + + + + + + SIP signaling agent + + + + + + + + + + + + + + + + + + + + + + RTSP signaling agent + + + + + + + + + + + + + + + MRCPv2 connection agent + + + + + + + + + + + + + + + + Media processing engine + + + + + + + + + + + + Factory of RTP terminations + + + + + + + + + + + + + + + + + + Settings + + + + + + SIP settings + + + + + + + + + + + + + + + RTSP settings + + + + + + + + + + + + + + + + + + + + + + + + + + + RTP settings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Profiles + + + + + + MRCPv2 profile + + + + + + + + + + + + + + + + + MRCPv1 profile + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/unimrcp/conf/unimrcpserver.xml b/libs/unimrcp/conf/unimrcpserver.xml index b48e58a6e8..29189a8d03 100644 --- a/libs/unimrcp/conf/unimrcpserver.xml +++ b/libs/unimrcp/conf/unimrcpserver.xml @@ -1,103 +1,157 @@ - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + 8060 + udp,tcp + + UniMRCP SofiaSIP + UniMRCPServer + + + + + + + + + + + + 1554 + + + + + + 100 + UniMRCPServer + + + + + + + 1544 + 100 + false + 1024 + 1024 + + + + + 1 + + + + + + + + 5000 + 6000 + - - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + - - - + + + 50 + 200 + + 20 + PCMU PCMA L16/96/8000 telephone-event/101/8000 + + + + - - - + 1 + + 5000 - - - - - - - - - - - - - + 1000 + + - + - - - - - - + + SIP-Agent-1 + MRCPv2-Agent-1 + Media-Engine-1 + RTP-Factory-1 + RTP-Settings-1 + + + + - - - - - + + RTSP-Agent-1 + Media-Engine-1 + RTP-Factory-1 + RTP-Settings-1 + diff --git a/libs/unimrcp/conf/unimrcpserver.xsd b/libs/unimrcp/conf/unimrcpserver.xsd new file mode 100644 index 0000000000..920e5072f8 --- /dev/null +++ b/libs/unimrcp/conf/unimrcpserver.xsd @@ -0,0 +1,266 @@ + + + + + UniMRCP server document + + + + + + Generic properties + + + + + + + + + + + + + + + + + + + Common components + + + + + + Factory of MRCP resources + + + + + + + + + + + + + + + SIP signaling agent + + + + + + + + + + + + + + + + + + + + + + + RTSP signaling agent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MRCPv2 connection agent + + + + + + + + + + + + + + + + + Media processing engine + + + + + + + + + + + + Factory of RTP terminations + + + + + + + + + + + + + + + Factory of plugins (MRCP engines) + + + + + + + + + + + + + + + + + + + + + + + + + + + + Settings + + + + + + RTP settings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Profiles + + + + + + MRCPv2 profile + + + + + + + + + + + + + + + + MRCPv1 profile + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/unimrcp/configure.ac b/libs/unimrcp/configure.ac index 1ba581189b..f0fa56f737 100644 --- a/libs/unimrcp/configure.ac +++ b/libs/unimrcp/configure.ac @@ -3,14 +3,11 @@ AC_PREREQ(2.57) -AC_INIT([unimrcp],[0.9.0]) +AC_INIT([unimrcp],[1.0.0]) AC_CONFIG_AUX_DIR([build]) AC_CONFIG_MACRO_DIR([build/acmacros]) AC_PREFIX_DEFAULT(/usr/local/unimrcp) -CFLAGS="$CFLAGS $CONFIGURE_CFLAGS" -CXXFLAGS="$CXXFLAGS $CONFIGURE_CXXFLAGS" -LDFLAGS="$LDFLAGS $CONFIGURE_LDFLAGS" plugindir='${prefix}/plugin' confdir='${prefix}/conf' @@ -120,6 +117,15 @@ AC_ARG_ENABLE(demorecog-plugin, AM_CONDITIONAL([DEMORECOG_PLUGIN],[test "${enable_demorecog_plugin}" = "yes"]) +#Enable demo verifier plugin +AC_ARG_ENABLE(demoverifier-plugin, + [AC_HELP_STRING([--disable-demoverifier-plugin ],[exclude demo verifier plugin from build])], + [enable_demoverifier_plugin="$enableval"], + [enable_demoverifier_plugin="yes"]) + +AM_CONDITIONAL([DEMOVERIFIER_PLUGIN],[test "${enable_demoverifier_plugin}" = "yes"]) + + #Enable recorder plugin AC_ARG_ENABLE(recorder-plugin, [AC_HELP_STRING([--disable-recorder-plugin ],[exclude recorder plugin from build])], @@ -129,20 +135,6 @@ AC_ARG_ENABLE(recorder-plugin, AM_CONDITIONAL([RECORDER_PLUGIN],[test "${enable_recorder_plugin}" = "yes"]) -#Enable Cepstral Swift plugin -AC_ARG_ENABLE(cepstral-plugin, - [AC_HELP_STRING([--disable-cepstral-plugin ],[exclude cepstral plugin from build])], - [enable_cepstral_plugin="$enableval"], - [enable_cepstral_plugin="yes"]) - -if test "${enable_cepstral_plugin}" != "no"; then - UNIMRCP_CHECK_SWIFT -fi - -AM_CONDITIONAL([CEPSTRAL_PLUGIN],[test "${enable_cepstral_plugin}" = "yes" &&\ - test "${found_swift}" = "yes"]) - - #Enable PocketSphinx plugin AC_ARG_ENABLE(pocketsphinx-plugin, [AC_HELP_STRING([--enable-pocketsphinx-plugin ],[enable pocketsphinx plugin])], @@ -191,12 +183,12 @@ AC_CONFIG_FILES([ modules/mrcp-sofiasip/Makefile modules/mrcp-unirtsp/Makefile plugins/Makefile - plugins/mrcp-cepstral/Makefile plugins/mrcp-pocketsphinx/Makefile plugins/mrcp-flite/Makefile plugins/mrcp-recorder/Makefile plugins/demo-synth/Makefile plugins/demo-recog/Makefile + plugins/demo-verifier/Makefile platforms/Makefile platforms/libunimrcp-server/Makefile platforms/libunimrcp-client/Makefile @@ -216,8 +208,10 @@ AC_CONFIG_FILES([ build/pkgconfig/unimrcpclient.pc build/pkgconfig/unimrcpserver.pc build/pkgconfig/unimrcpplugin.pc + build/svnrev/Makefile conf/Makefile data/Makefile + docs/doxygen.conf ]) AC_OUTPUT @@ -231,6 +225,7 @@ AC_MSG_NOTICE([ Sofia-SIP: $sofia_version]) AC_MSG_NOTICE([Plugins:]) AC_MSG_NOTICE([ Demo Synthesizer: $enable_demosynth_plugin]) AC_MSG_NOTICE([ Demo Recognizer: $enable_demorecog_plugin]) -AC_MSG_NOTICE([ Cepstral: $enable_cepstral_plugin]) +AC_MSG_NOTICE([ Demo Verifier: $enable_demoverifier_plugin]) +AC_MSG_NOTICE([ Recorder: $enable_recorder_plugin]) AC_MSG_NOTICE([ PocketSphinx: $enable_pocketsphinx_plugin]) AC_MSG_NOTICE([ Flite: $enable_flite_plugin]) diff --git a/libs/unimrcp/data/demo-16kHz.pcm b/libs/unimrcp/data/demo-16kHz.pcm index 01ace40952cb432a96473d1531a6c6328f6747a3..5341461c25df7f50f246e75e41748b576eea5431 100644 GIT binary patch literal 70444 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 *xOv3APB1r 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 literal 115200 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ΝYC!W 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 literal 58636 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

2EnpKQm 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

?qQrQ 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 + + + one two three four five + + +--break-- \ No newline at end of file diff --git a/libs/unimrcp/data/johnsmith-16kHz.pcm b/libs/unimrcp/data/johnsmith-16kHz.pcm new file mode 100644 index 0000000000000000000000000000000000000000..235338077d8e1351bf6bab14ae6a3275d0271914 GIT binary patch literal 33214 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%0DgJGEcFb?L0tHB`fh^!-% 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

~B8~d!8EAjzS8%)L=(nP*n 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 I^WNkC1G7*pwEzGB literal 0 Hc-jL100001 diff --git a/libs/unimrcp/data/result-verification.xml b/libs/unimrcp/data/result-verification.xml new file mode 100644 index 0000000000..fa0c8ceef3 --- /dev/null +++ b/libs/unimrcp/data/result-verification.xml @@ -0,0 +1,21 @@ + + + + + + 500 + cellular-phone + male + accepted + 0.85 + + + 1500 + cellular-phone + male + accepted + 0.75 + + + + \ No newline at end of file diff --git a/libs/unimrcp/data/speak.txt b/libs/unimrcp/data/speak.txt index 3245b20dc9..894d43a75f 100644 --- a/libs/unimrcp/data/speak.txt +++ b/libs/unimrcp/data/speak.txt @@ -1 +1 @@ -Hello World. \ No newline at end of file +Welcome to Uni MRCP. \ No newline at end of file diff --git a/libs/unimrcp/data/speak.xml b/libs/unimrcp/data/speak.xml index e9a9ec3ebd..c64e8dfb31 100644 --- a/libs/unimrcp/data/speak.xml +++ b/libs/unimrcp/data/speak.xml @@ -1,6 +1,6 @@ - - - Hello World. - + +

+ Welcome to Uni MRCP. +

\ No newline at end of file diff --git a/libs/unimrcp/docs/doxygen.conf b/libs/unimrcp/docs/doxygen.conf.in similarity index 91% rename from libs/unimrcp/docs/doxygen.conf rename to libs/unimrcp/docs/doxygen.conf.in index 8b375cefd9..b405be48f0 100644 --- a/libs/unimrcp/docs/doxygen.conf +++ b/libs/unimrcp/docs/doxygen.conf.in @@ -1,6 +1,7 @@ PROJECT_NAME="UniMRCP" +PROJECT_NUMBER = @VERSION@ -INPUT=. +INPUT=. docs/mainpage.docs QUIET=YES RECURSIVE=YES FILE_PATTERNS=*.h diff --git a/libs/unimrcp/docs/mainpage.docs b/libs/unimrcp/docs/mainpage.docs new file mode 100644 index 0000000000..8961b43da3 --- /dev/null +++ b/libs/unimrcp/docs/mainpage.docs @@ -0,0 +1,92 @@ +/** +@mainpage UniMRCP + +
+@section Introduction + +UniMRCP is an open source cross-platform MRCP project, which provides everything required for MRCP client and server side deployment. +
+UniMRCP encapsulates SIP/MRCPv2, RTSP, SDP and RTP/RTCP stacks inside and provides MRCP version independent user level interface for the integration. +
+
+@section Source Tree Structure + +
+Libraries + +* apr-toolkit - set of utilities built on top of APR and APR-Util libraries (task abstraction, logging, etc) +
+* mpf - media processing framework +
+* mrcp - implementation of MRCP basics (message, parser, resources) +
+* mrcpv2-transport - implementation of MRCPv2 transport layer +
+* mrcp-signaling - abstract MRCP signaling (session management) interface +
+* mrcp-engine - abstract resource engine interface +
+* mrcp-client - implementation of MRCP client stack based on abstract signaling interface +
+* mrcp-server - implementation of MRCP server stack based on abstract signaling and engine interfaces +
+* uni-rtsp - implementation of minimal RTSP stack required for MRCPv1 + + +
+Modules + +* mrcp-sofiasip - implementation of abstract signaling interface using SofiaSIP library +
+* mrcp-unirtsp - implementation of abstract signaling interface using UniRTSP library +
+ + +
+Plugins + +* demo-synth - simulation of actual synthesizer engine +
+* demo-recog - simulation of actual recognizer engine +
+* mrcp-recorder - implementation of recorder resource +
+* mrcp-flite - implementation of synthesizer resource using open source Flite engine +
+* mrcp-pocketsphinx - implementation of recognizer resource using open source PocketSphinx engine + +
+Platforms + +* libunimrcpclient - unimrcp client stack based on libraries and modules above +
+* libunimrcpserver - unimrcp server stack based on libraries, modules and plugins above +
+* unimrcpclient - sample C application based on unimrcp client stack +
+* umc - sample C++ application based on unimrcp client stack +
+* unimrcpserver - final unimrcp server application + +
+@section Dependencies + +
APR - Apache Portable Runtime +
+ Sofia-SIP - SIP User Agent Library + +
+@section Project Links + + Website +
+ Downloads +
+ Wiki +
+ Issue Tracker +
+ Discussion Group +
+ +*/ diff --git a/libs/unimrcp/libs/apr-toolkit/Makefile.am b/libs/unimrcp/libs/apr-toolkit/Makefile.am index e887e398c2..0647143824 100644 --- a/libs/unimrcp/libs/apr-toolkit/Makefile.am +++ b/libs/unimrcp/libs/apr-toolkit/Makefile.am @@ -8,38 +8,43 @@ noinst_LTLIBRARIES = libaprtoolkit.la include_HEADERS = include/apt.h \ include/apt_obj_list.h \ include/apt_cyclic_queue.h \ + include/apt_dir_layout.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_poller_task.h \ include/apt_pool.h \ include/apt_log.h \ include/apt_pair.h \ include/apt_string.h \ include/apt_string_table.h \ + include/apt_header_field.h \ include/apt_text_stream.h \ + include/apt_text_message.h \ include/apt_net.h \ include/apt_nlsml_doc.h \ - include/apt_dir_layout.h \ + include/apt_multipart_content.h \ + include/apt_timer_queue.h \ include/apt_test_suite.h libaprtoolkit_la_SOURCES = src/apt_obj_list.c \ src/apt_cyclic_queue.c \ + src/apt_dir_layout.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_poller_task.c \ src/apt_pool.c \ src/apt_log.c \ src/apt_pair.c \ src/apt_string_table.c \ + src/apt_header_field.c \ src/apt_text_stream.c \ + src/apt_text_message.c \ src/apt_net.c \ src/apt_nlsml_doc.c \ - src/apt_dir_layout.c \ + src/apt_multipart_content.c \ + src/apt_timer_queue.c \ src/apt_test_suite.c - diff --git a/libs/unimrcp/libs/apr-toolkit/aprtoolkit.2008.vcproj b/libs/unimrcp/libs/apr-toolkit/aprtoolkit.2008.vcproj deleted file mode 100644 index d77441afa5..0000000000 --- a/libs/unimrcp/libs/apr-toolkit/aprtoolkit.2008.vcproj +++ /dev/null @@ -1,409 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/unimrcp/libs/apr-toolkit/aprtoolkit.2010.vcxproj b/libs/unimrcp/libs/apr-toolkit/aprtoolkit.2010.vcxproj deleted file mode 100644 index 9288736c40..0000000000 --- a/libs/unimrcp/libs/apr-toolkit/aprtoolkit.2010.vcxproj +++ /dev/null @@ -1,157 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - aprtoolkit - {13DEECA0-BDD4-4744-A1A2-8EB0A44DF3D2} - aprtoolkit - Win32Proj - - - - StaticLibrary - Unicode - true - - - StaticLibrary - Unicode - - - StaticLibrary - Unicode - true - - - StaticLibrary - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - - - - APT_STATIC_LIB;%(PreprocessorDefinitions) - - - - - X64 - - - APT_STATIC_LIB;%(PreprocessorDefinitions) - ProgramDatabase - - - - - APT_STATIC_LIB;%(PreprocessorDefinitions) - - - - - X64 - - - APT_STATIC_LIB;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {f057da7f-79e5-4b00-845c-ef446ef055e3} - false - - - - - - \ No newline at end of file diff --git a/libs/unimrcp/libs/apr-toolkit/aprtoolkit.2010.vcxproj.filters b/libs/unimrcp/libs/apr-toolkit/aprtoolkit.2010.vcxproj.filters deleted file mode 100644 index db0b3156b3..0000000000 --- a/libs/unimrcp/libs/apr-toolkit/aprtoolkit.2010.vcxproj.filters +++ /dev/null @@ -1,125 +0,0 @@ - - - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {4c2fadb2-8996-43e3-9db1-e3fc3eccee30} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - \ No newline at end of file diff --git a/libs/unimrcp/libs/apr-toolkit/aprtoolkit.vcproj b/libs/unimrcp/libs/apr-toolkit/aprtoolkit.vcproj index 9ea77e93a6..bb2746e815 100644 --- a/libs/unimrcp/libs/apr-toolkit/aprtoolkit.vcproj +++ b/libs/unimrcp/libs/apr-toolkit/aprtoolkit.vcproj @@ -254,19 +254,19 @@ > + + @@ -309,10 +313,18 @@ RelativePath=".\include\apt_test_suite.h" > + + + + + + @@ -382,10 +398,18 @@ RelativePath=".\src\apt_test_suite.c" > + + + + diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt.h b/libs/unimrcp/libs/apr-toolkit/include/apt.h index 2c0353161e..963b28b65a 100644 --- a/libs/unimrcp/libs/apr-toolkit/include/apt.h +++ b/libs/unimrcp/libs/apr-toolkit/include/apt.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: apt.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __APT_H__ -#define __APT_H__ +#ifndef APT_H +#define APT_H /** * @file apt.h @@ -56,4 +58,4 @@ /** Boolean value */ typedef int apt_bool_t; -#endif /*__APT_H__*/ +#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 index 59eff4015f..9085f0c3ba 100644 --- a/libs/unimrcp/libs/apr-toolkit/include/apt_consumer_task.h +++ b/libs/unimrcp/libs/apr-toolkit/include/apt_consumer_task.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: apt_consumer_task.h 1708 2010-05-24 17:03:25Z achaloyan $ */ -#ifndef __APT_CONSUMER_TASK_H__ -#define __APT_CONSUMER_TASK_H__ +#ifndef APT_CONSUMER_TASK_H +#define APT_CONSUMER_TASK_H /** * @file apt_consumer_task.h @@ -44,7 +46,7 @@ APT_DECLARE(apt_consumer_task_t*) apt_consumer_task_create( * 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); +APT_DECLARE(apt_task_t*) apt_consumer_task_base_get(const apt_consumer_task_t *task); /** * Get task vtable. @@ -56,8 +58,8 @@ APT_DECLARE(apt_task_vtable_t*) apt_consumer_task_vtable_get(apt_consumer_task_t * 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_DECLARE(void*) apt_consumer_task_object_get(const apt_consumer_task_t *task); APT_END_EXTERN_C -#endif /*__APT_CONSUMER_TASK_H__*/ +#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 index 7c6ea3ab08..b0500855d6 100644 --- a/libs/unimrcp/libs/apr-toolkit/include/apt_cyclic_queue.h +++ b/libs/unimrcp/libs/apr-toolkit/include/apt_cyclic_queue.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: apt_cyclic_queue.h 1708 2010-05-24 17:03:25Z achaloyan $ */ -#ifndef __APT_CYCLIC_QUEUE_H__ -#define __APT_CYCLIC_QUEUE_H__ +#ifndef APT_CYCLIC_QUEUE_H +#define APT_CYCLIC_QUEUE_H /** * @file apt_cyclic_queue.h @@ -69,9 +71,9 @@ APT_DECLARE(void) apt_cyclic_queue_clear(apt_cyclic_queue_t *queue); * @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_DECLARE(apt_bool_t) apt_cyclic_queue_is_empty(const apt_cyclic_queue_t *queue); APT_END_EXTERN_C -#endif /*__APT_CYCLIC_QUEUE_H__*/ +#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 index 497265d381..6adda9fab8 100644 --- a/libs/unimrcp/libs/apr-toolkit/include/apt_dir_layout.h +++ b/libs/unimrcp/libs/apr-toolkit/include/apt_dir_layout.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: apt_dir_layout.h 1524 2010-02-15 20:44:16Z achaloyan $ */ -#ifndef __APT_DIR_LAYOUT_H__ -#define __APT_DIR_LAYOUT_H__ +#ifndef APT_DIR_LAYOUT_H +#define APT_DIR_LAYOUT_H /** * @file apt_dir_layout.h @@ -56,12 +58,13 @@ APT_DECLARE(apt_dir_layout_t*) apt_custom_dir_layout_create( const char *data_dir_path, apr_pool_t *pool); -/** - * Construct file path with the given file name relative to data dir. - */ +/** Construct file path relative to data dir using the file name specified. */ APT_DECLARE(char*) apt_datadir_filepath_get(const apt_dir_layout_t *dir_layout, const char *file_name, apr_pool_t *pool); +/** Construct file path relative to conf dir using the file name specified. */ +APT_DECLARE(char*) apt_confdir_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__*/ +#endif /* APT_DIR_LAYOUT_H */ diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_header_field.h b/libs/unimrcp/libs/apr-toolkit/include/apt_header_field.h new file mode 100644 index 0000000000..72932059dd --- /dev/null +++ b/libs/unimrcp/libs/apr-toolkit/include/apt_header_field.h @@ -0,0 +1,178 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: apt_header_field.h 1719 2010-05-31 21:09:51Z achaloyan $ + */ + +#ifndef APT_HEADER_FIELD_H +#define APT_HEADER_FIELD_H + +/** + * @file apt_header_field.h + * @brief Header Field Declaration (RFC5322) + */ + +#ifdef WIN32 +#pragma warning(disable: 4127) +#endif +#include +#include "apt_string.h" + +APT_BEGIN_EXTERN_C + +/** Header field declaration */ +typedef struct apt_header_field_t apt_header_field_t; +/** Header section declaration */ +typedef struct apt_header_section_t apt_header_section_t; + +/** Header field */ +struct apt_header_field_t { + /** Ring entry */ + APR_RING_ENTRY(apt_header_field_t) link; + + /** Name of the header field */ + apt_str_t name; + /** Value of the header field */ + apt_str_t value; + + /** Numeric identifier associated with name */ + apr_size_t id; +}; + +/** + * Header section + * @remark The header section is a collection of header fields. + * The header fields are stored in both a ring and an array. + * The goal is to ensure efficient access and manipulation on the header fields. + */ +struct apt_header_section_t { + /** List of header fields (name-value pairs) */ + APR_RING_HEAD(apt_head_t, apt_header_field_t) ring; + /** Array of pointers to header fields */ + apt_header_field_t **arr; + /** Max number of header fields */ + apr_size_t arr_size; +}; + + +/** + * Allocate an empty header field. + * @param pool the pool to allocate memory from + */ +APT_DECLARE(apt_header_field_t*) apt_header_field_alloc(apr_pool_t *pool); + +/** + * Create a header field using given name and value APT strings. + * @param name the name of the header field + * @param value the value of the header field + * @param pool the pool to allocate memory from + */ +APT_DECLARE(apt_header_field_t*) apt_header_field_create(const apt_str_t *name, const apt_str_t *value, apr_pool_t *pool); + +/** + * Create a header field using given name and value C strings. + * @param name the name of the header field + * @param value the value of the header field + * @param pool the pool to allocate memory from + */ +APT_DECLARE(apt_header_field_t*) apt_header_field_create_c(const char *name, const char *value, apr_pool_t *pool); + +/** + * Create a header field from entire text line consisting of a name and value pair. + * @param line the text line, which consists of a name and value pair + * @param separator the name and value separator + * @param pool the pool to allocate memory from + */ +APT_DECLARE(apt_header_field_t*) apt_header_field_create_from_line(const apt_str_t *line, char separator, apr_pool_t *pool); + +/** + * Copy specified header field. + * @param src_header_field the header field to copy + * @param pool the pool to allocate memory from + */ +APT_DECLARE(apt_header_field_t*) apt_header_field_copy(const apt_header_field_t *src_header_field, apr_pool_t *pool); + +/** + * Initialize header section (collection of header fields). + * @param header the header section to initialize + */ +APT_DECLARE(void) apt_header_section_init(apt_header_section_t *header); + +/** + * Allocate header section to set/get header fields by numeric identifiers. + * @param header the header section to allocate + * @param max_field_count the max number of header fields in the section (protocol dependent) + * @param pool the pool to allocate memory from + */ +APT_DECLARE(apt_bool_t) apt_header_section_array_alloc(apt_header_section_t *header, apr_size_t max_field_count, apr_pool_t *pool); + +/** + * Add (append) header field to header section. + * @param header the header section to add field to + * @param header_field the header field to add + */ +APT_DECLARE(apt_bool_t) apt_header_section_field_add(apt_header_section_t *header, apt_header_field_t *header_field); + +/** + * Insert header field to header section based on numreic identifier if specified. + * @param header the header section to insert field into + * @param header_field the header field to insert + */ +APT_DECLARE(apt_bool_t) apt_header_section_field_insert(apt_header_section_t *header, apt_header_field_t *header_field); + +/** + * Set header field in the array of header fields using associated numeric identifier. + * @param header the header section to set field for + * @param header_field the header field to set + * @remark Typically, the header field should be already added to the header section using apt_header_section_field_add() + */ +APT_DECLARE(apt_bool_t) apt_header_section_field_set(apt_header_section_t *header, apt_header_field_t *header_field); + +/** + * Remove header field from header section. + * @param header the header section to remove field from + * @param header_field the header field to remove + */ +APT_DECLARE(apt_bool_t) apt_header_section_field_remove(apt_header_section_t *header, apt_header_field_t *header_field); + +/** + * Check whether specified header field is set. + * @param header the header section to use + * @param id the identifier associated with the header_field to check + */ +static APR_INLINE apt_bool_t apt_header_section_field_check(const apt_header_section_t *header, apr_size_t id) +{ + if(id < header->arr_size) { + return header->arr[id] ? TRUE : FALSE; + } + return FALSE; +} + +/** + * Get header field by specified identifier. + * @param header the header section to use + * @param id the identifier associated with the header_field + */ +static APR_INLINE apt_header_field_t* apt_header_section_field_get(const apt_header_section_t *header, apr_size_t id) +{ + if(id < header->arr_size) { + return header->arr[id]; + } + return NULL; +} + +APT_END_EXTERN_C + +#endif /* APT_HEADER_FIELD_H */ diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_log.h b/libs/unimrcp/libs/apr-toolkit/include/apt_log.h index ea2c561331..4d7c1bc5ed 100644 --- a/libs/unimrcp/libs/apr-toolkit/include/apt_log.h +++ b/libs/unimrcp/libs/apr-toolkit/include/apt_log.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: apt_log.h 1792 2011-01-10 21:08:52Z achaloyan $ */ -#ifndef __APT_LOG_H__ -#define __APT_LOG_H__ +#ifndef APT_LOG_H +#define APT_LOG_H /** * @file apt_log.h @@ -44,8 +46,10 @@ APT_BEGIN_EXTERN_C #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 +/** Format to log pointers and identifiers */ +#define APT_NAMESID_FMT "%s "APT_SID_FMT +/** Format to log names, identifiers and resources */ +#define APT_NAMESIDRES_FMT "%s "APT_SIDRES_FMT /** Priority of log messages ordered from highest priority to lowest (rfc3164) */ @@ -69,22 +73,30 @@ typedef enum { 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_THREAD = 0x10, /**< enable thread identifier output */ APT_LOG_HEADER_DEFAULT = APT_LOG_HEADER_DATE | APT_LOG_HEADER_TIME | APT_LOG_HEADER_PRIORITY } apt_log_header_e; -/** Log output modes */ +/** Mode of log output */ 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; +/** Masking mode of private data */ +typedef enum { + APT_LOG_MASKING_NONE, /**< log everything as is */ + APT_LOG_MASKING_COMPLETE, /**< mask private data completely */ + APT_LOG_MASKING_ENCRYPTED /**< encrypt private data */ +} apt_log_masking_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, +typedef apt_bool_t (*apt_log_ext_handler_f)(const char *file, int line, const char *obj, apt_log_priority_e priority, const char *format, va_list arg_ptr); /** @@ -95,6 +107,13 @@ typedef apt_bool_t (*apt_log_ext_handler_f)(const char *file, int line, const ch */ APT_DECLARE(apt_bool_t) apt_log_instance_create(apt_log_output_e mode, apt_log_priority_e priority, apr_pool_t *pool); +/** + * Create and load the singleton instance of the logger. + * @param config_file the path to configuration file to load settings from + * @param pool the memory pool to use + */ +APT_DECLARE(apt_bool_t) apt_log_instance_load(const char *config_file, apr_pool_t *pool); + /** * Destroy the singleton instance of the logger. */ @@ -116,13 +135,15 @@ APT_DECLARE(apt_bool_t) apt_log_instance_set(apt_logger_t *logger); * @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 append whether to append or to truncate (start over) the log file * @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, + const char *dir_path, + const char *file_name, + apr_size_t max_file_size, + apr_size_t max_file_count, + apt_bool_t append, apr_pool_t *pool); /** @@ -131,23 +152,73 @@ APT_DECLARE(apt_bool_t) apt_log_file_open( APT_DECLARE(apt_bool_t) apt_log_file_close(void); /** - * Set the logging output. + * Set the logging output mode. * @param mode the mode to set */ APT_DECLARE(apt_bool_t) apt_log_output_mode_set(apt_log_output_e mode); +/** + * Check the logging output mode to be enabled (set) or not. + * @param mode the mode to check + */ +APT_DECLARE(apt_bool_t) apt_log_output_mode_check(apt_log_output_e mode); + +/** + * Translate the output mode string to bitmask of apt_log_output_e values. + * @param str the string to translate + */ +APT_DECLARE(int) apt_log_output_mode_translate(char *str); + /** * 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); +/** + * Translate the priority (log level) string to enum. + * @param str the string to translate + */ +APT_DECLARE(apt_log_priority_e) apt_log_priority_translate(const char *str); + /** * 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); +/** + * Translate the header string to bitmask of apt_log_header_e values. + * @param str the string to translate + */ +APT_DECLARE(int) apt_log_header_translate(char *str); + +/** + * Set the masking mode of private data. + * @param masking the masking mode to set + */ +APT_DECLARE(apt_bool_t) apt_log_masking_set(apt_log_masking_e masking); + +/** + * Get the current masking mode of private data. + */ +APT_DECLARE(apt_log_masking_e) apt_log_masking_get(); + +/** + * Translate the masking mode string to enum. + * @param str the string to translate + */ +APT_DECLARE(apt_log_masking_e) apt_log_masking_translate(const char *str); + +/** + * Mask private data based on the masking mode + * @param data_in the data to mask + * @param length the length of the data to mask on input, the length of the masked data on output + * @param pool the memory pool to use if needed + * @return The masked data. + */ +APT_DECLARE(const char*) apt_log_data_mask(const char *data_in, apr_size_t *length, apr_pool_t *pool); + /** * Set the extended external log handler. * @param handler the handler to pass log events to @@ -165,6 +236,16 @@ APT_DECLARE(apt_bool_t) apt_log_ext_handler_set(apt_log_ext_handler_f handler); */ APT_DECLARE(apt_bool_t) apt_log(const char *file, int line, apt_log_priority_e priority, const char *format, ...); +/** + * 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 obj the associated object + * @param format the format of the entire log entry + */ +APT_DECLARE(apt_bool_t) apt_obj_log(const char *file, int line, apt_log_priority_e priority, void *obj, const char *format, ...); + APT_END_EXTERN_C -#endif /*__APT_LOG_H__*/ +#endif /* APT_LOG_H */ diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_multipart_content.h b/libs/unimrcp/libs/apr-toolkit/include/apt_multipart_content.h new file mode 100644 index 0000000000..c3f2dd8de2 --- /dev/null +++ b/libs/unimrcp/libs/apr-toolkit/include/apt_multipart_content.h @@ -0,0 +1,108 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: apt_multipart_content.h 1722 2010-06-01 08:40:35Z achaloyan $ + */ + +#ifndef APT_MULTIPART_CONTENT_H +#define APT_MULTIPART_CONTENT_H + +/** + * @file apt_multipart_content.h + * @brief Multipart Content Routine + */ + +#include "apt_header_field.h" + +APT_BEGIN_EXTERN_C + +/** Opaque multipart content declaration */ +typedef struct apt_multipart_content_t apt_multipart_content_t; + +/** Content part declaration */ +typedef struct apt_content_part_t apt_content_part_t; + +/** Content part */ +struct apt_content_part_t { + /** Header section */ + apt_header_section_t header; + /** Body */ + apt_str_t body; + + /** Pointer to parsed content-type header field */ + apt_str_t *type; + /** Pointer to parsed content-id header field */ + apt_str_t *id; + /** Pointer to parsed content-length header field */ + apt_str_t *length; +}; + +/** + * Create an empty multipart content + * @param max_content_size the max size of the content (body) + * @param boundary the boundary to separate content parts + * @param pool the pool to allocate memory from + * @return an empty multipart content + */ +APT_DECLARE(apt_multipart_content_t*) apt_multipart_content_create(apr_size_t max_content_size, const apt_str_t *boundary, apr_pool_t *pool); + +/** + * Add content part to multipart content + * @param multipart_content the multipart content to add content part to + * @param content_part the content part to add + * @return TRUE on success + */ +APT_DECLARE(apt_bool_t) apt_multipart_content_add(apt_multipart_content_t *multipart_content, const apt_content_part_t *content_part); + +/** + * Add content part to multipart content by specified header fields and body + * @param multipart_content the multipart content to add content part to + * @param content_type the type of content part + * @param content_id the identifier of content part + * @param body the body of content part + * @return TRUE on success + */ +APT_DECLARE(apt_bool_t) apt_multipart_content_add2(apt_multipart_content_t *multipart_content, const apt_str_t *content_type, const apt_str_t *content_id, const apt_str_t *body); + +/** + * Finalize multipart content generation + * @param multipart_content the multipart content to finalize + * @return generated multipart content + */ +APT_DECLARE(apt_str_t*) apt_multipart_content_finalize(apt_multipart_content_t *multipart_content); + + +/** + * Assign body to multipart content to get (parse) each content part from + * @param body the body of multipart content to parse + * @param boundary the boundary to separate content parts + * @param pool the pool to allocate memory from + * @return multipart content with assigned body + */ +APT_DECLARE(apt_multipart_content_t*) apt_multipart_content_assign(const apt_str_t *body, const apt_str_t *boundary, apr_pool_t *pool); + +/** + * Get the next content part + * @param multipart_content the multipart content to get the next content part from + * @param content_part the parsed content part + * @param is_final indicates the final boundary is reached + * @return TRUE on success + */ +APT_DECLARE(apt_bool_t) apt_multipart_content_get(apt_multipart_content_t *multipart_content, apt_content_part_t *content_part, apt_bool_t *is_final); + + +APT_END_EXTERN_C + +#endif /* APT_MULTIPART_CONTENT_H */ diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_net.h b/libs/unimrcp/libs/apr-toolkit/include/apt_net.h index 7c9d109851..d413c7f871 100644 --- a/libs/unimrcp/libs/apr-toolkit/include/apt_net.h +++ b/libs/unimrcp/libs/apr-toolkit/include/apt_net.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: apt_net.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __APT_NET_H__ -#define __APT_NET_H__ +#ifndef APT_NET_H +#define APT_NET_H /** * @file apt_net.h @@ -43,4 +45,4 @@ void apt_ntp_time_get(apr_uint32_t *sec, apr_uint32_t *frac); APT_END_EXTERN_C -#endif /*__APT_NET_H__*/ +#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 deleted file mode 100644 index 0cd9466f6a..0000000000 --- a/libs/unimrcp/libs/apr-toolkit/include/apt_net_client_task.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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 -#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 deleted file mode 100644 index fa97836463..0000000000 --- a/libs/unimrcp/libs/apr-toolkit/include/apt_net_server_task.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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 -#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_nlsml_doc.h b/libs/unimrcp/libs/apr-toolkit/include/apt_nlsml_doc.h index ab8724598f..ca29a07ad8 100644 --- a/libs/unimrcp/libs/apr-toolkit/include/apt_nlsml_doc.h +++ b/libs/unimrcp/libs/apr-toolkit/include/apt_nlsml_doc.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: apt_nlsml_doc.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __APT_NLSML_DOC_H__ -#define __APT_NLSML_DOC_H__ +#ifndef APT_NLSML_DOC_H +#define APT_NLSML_DOC_H /** * @file apt_nlsml_doc.h @@ -45,4 +47,4 @@ APT_DECLARE(const char *) nlsml_input_attrib_get(const apr_xml_elem *input, cons APT_END_EXTERN_C -#endif /*__APT_NLSML_DOC_H__*/ +#endif /* APT_NLSML_DOC_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 index ed3359567d..3d17a81595 100644 --- a/libs/unimrcp/libs/apr-toolkit/include/apt_obj_list.h +++ b/libs/unimrcp/libs/apr-toolkit/include/apt_obj_list.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: apt_obj_list.h 1708 2010-05-24 17:03:25Z achaloyan $ */ -#ifndef __APT_OBJ_LIST_H__ -#define __APT_OBJ_LIST_H__ +#ifndef APT_OBJ_LIST_H +#define APT_OBJ_LIST_H /** * @file apt_obj_list.h @@ -65,40 +67,40 @@ 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); +APT_DECLARE(void*) apt_list_head(const 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); +APT_DECLARE(void*) apt_obj_list_tail(const 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); +APT_DECLARE(apt_list_elem_t*) apt_list_first_elem_get(const 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); +APT_DECLARE(apt_list_elem_t*) apt_list_last_elem_get(const 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); +APT_DECLARE(apt_list_elem_t*) apt_list_next_elem_get(const 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); +APT_DECLARE(apt_list_elem_t*) apt_list_prev_elem_get(const apt_obj_list_t *list, apt_list_elem_t *elem); /** * Insert element to the list. @@ -123,15 +125,15 @@ APT_DECLARE(apt_list_elem_t*) apt_list_elem_remove(apt_obj_list_t *list, apt_lis * @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); +APT_DECLARE(apt_bool_t) apt_list_is_empty(const 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_DECLARE(void*) apt_list_elem_object_get(const apt_list_elem_t *elem); APT_END_EXTERN_C -#endif /*__APT_OBJ_LIST_H__*/ +#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 index 36b74dfbaa..4f3d8c55d6 100644 --- a/libs/unimrcp/libs/apr-toolkit/include/apt_pair.h +++ b/libs/unimrcp/libs/apr-toolkit/include/apt_pair.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: apt_pair.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __APT_PAIR_H__ -#define __APT_PAIR_H__ +#ifndef APT_PAIR_H +#define APT_PAIR_H /** * @file apt_pair.h @@ -70,4 +72,4 @@ APT_DECLARE(const apt_pair_t*) apt_pair_array_get(const apt_pair_arr_t *arr, int APT_END_EXTERN_C -#endif /*__APT_PAIR_H__*/ +#endif /* APT_PAIR_H */ diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_poller_task.h b/libs/unimrcp/libs/apr-toolkit/include/apt_poller_task.h new file mode 100644 index 0000000000..e1a3c6a655 --- /dev/null +++ b/libs/unimrcp/libs/apr-toolkit/include/apt_poller_task.h @@ -0,0 +1,122 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: apt_poller_task.h 1708 2010-05-24 17:03:25Z achaloyan $ + */ + +#ifndef APT_POLLER_TASK_H +#define APT_POLLER_TASK_H + +/** + * @file apt_poller_task.h + * @brief Poller Task + */ + +#include "apt_pollset.h" +#include "apt_task.h" +#include "apt_timer_queue.h" + +APT_BEGIN_EXTERN_C + +/** Opaque poller task declaration */ +typedef struct apt_poller_task_t apt_poller_task_t; + +/** Function prototype to handle signalled descripors */ +typedef apt_bool_t (*apt_poll_signal_f)(void *obj, const apr_pollfd_t *descriptor); + + +/** + * Create poller task. + * @param max_pollset_size the maximum number of descriptors pollset can hold + * @param signal_handler the handler of signalled descriptors + * @param obj the external object to pass to callback + * @param msg_pool the pool of task messages + * @param pool the pool to allocate memory from + */ +APT_DECLARE(apt_poller_task_t*) apt_poller_task_create( + apr_size_t max_pollset_size, + apt_poll_signal_f signal_handler, + void *obj, + apt_task_msg_pool_t *msg_pool, + apr_pool_t *pool); + +/** + * Destroy poller task. + * @param task the task to destroy + */ +APT_DECLARE(apt_bool_t) apt_poller_task_destroy(apt_poller_task_t *task); + +/** + * Cleanup poller task. + * @param task the task to cleanup + * + * @remark This function should be considered in protected scope. + * It will be called on task destroy unless you override the behavior. + */ +APT_DECLARE(void) apt_poller_task_cleanup(apt_poller_task_t *task); + +/** + * Start poller task and wait for incoming messages. + * @param task the task to start + */ +APT_DECLARE(apt_bool_t) apt_poller_task_start(apt_poller_task_t *task); + +/** + * Terminate poller task. + * @param task the task to terminate + */ +APT_DECLARE(apt_bool_t) apt_poller_task_terminate(apt_poller_task_t *task); + +/** + * Get task base. + * @param task the poller task to get task base from + */ +APT_DECLARE(apt_task_t*) apt_poller_task_base_get(const apt_poller_task_t *task); + +/** + * Get task vtable. + * @param task the poller task to get vtable from + */ +APT_DECLARE(apt_task_vtable_t*) apt_poller_task_vtable_get(apt_poller_task_t *task); + +/** + * Get external object. + * @param task the poller task to get object from + */ +APT_DECLARE(void*) apt_poller_task_object_get(const apt_poller_task_t *task); + +/** + * Get pollset. + * @param task the poller task to get pollset from + */ +APT_DECLARE(apt_pollset_t*) apt_poller_task_pollset_get(const apt_poller_task_t *task); + +/** + * Create timer. + * @param task the poller task to create timer in the scope of + * @param proc the timer callback + * @param obj the object to pass to callback + * @param pool the pool to allocate memory from + */ +APT_DECLARE(apt_timer_t*) apt_poller_task_timer_create( + apt_poller_task_t *task, + apt_timer_proc_f proc, + void *obj, + apr_pool_t *pool); + + +APT_END_EXTERN_C + +#endif /* APT_POLLER_TASK_H */ diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_pollset.h b/libs/unimrcp/libs/apr-toolkit/include/apt_pollset.h index 05ba559bd3..3f7d56527b 100644 --- a/libs/unimrcp/libs/apr-toolkit/include/apt_pollset.h +++ b/libs/unimrcp/libs/apr-toolkit/include/apt_pollset.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: apt_pollset.h 1565 2010-03-06 07:13:04Z achaloyan $ */ -#ifndef __APT_POLLSET_H__ -#define __APT_POLLSET_H__ +#ifndef APT_POLLSET_H +#define APT_POLLSET_H /** * @file apt_pollset.h @@ -39,7 +41,7 @@ APT_BEGIN_EXTERN_C typedef struct apt_pollset_t apt_pollset_t; /** - * Create interruptable pollset on top of APR pollset + * 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 */ @@ -69,7 +71,7 @@ APT_DECLARE(apt_bool_t) apt_pollset_remove(apt_pollset_t *pollset, const apr_pol * 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 num the number of signalled descriptors (output parameter) * @param descriptors the array of signalled descriptors (output parameter) */ APT_DECLARE(apr_status_t) apt_pollset_poll( @@ -93,4 +95,4 @@ APT_DECLARE(apt_bool_t) apt_pollset_is_wakeup(apt_pollset_t *pollset, const apr_ APT_END_EXTERN_C -#endif /*__APT_POLLSET_H__*/ +#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 index b2bff52688..7f1aabaf2b 100644 --- a/libs/unimrcp/libs/apr-toolkit/include/apt_pool.h +++ b/libs/unimrcp/libs/apr-toolkit/include/apt_pool.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: apt_pool.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __APT_POOL_H__ -#define __APT_POOL_H__ +#ifndef APT_POOL_H +#define APT_POOL_H /** * @file apt_pool.h @@ -44,4 +46,4 @@ APT_DECLARE(apr_pool_t*) apt_subpool_create(apr_pool_t *parent); APT_END_EXTERN_C -#endif /*__APT_POOL_H__*/ +#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 index 31dd72c0b4..23be9655d4 100644 --- a/libs/unimrcp/libs/apr-toolkit/include/apt_string.h +++ b/libs/unimrcp/libs/apr-toolkit/include/apt_string.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: apt_string.h 1531 2010-02-20 14:19:53Z achaloyan $ */ -#ifndef __APT_STRING_H__ -#define __APT_STRING_H__ +#ifndef APT_STRING_H +#define APT_STRING_H /** * @file apt_string.h @@ -65,7 +67,7 @@ static APR_INLINE apr_size_t apt_string_length_get(const apt_str_t *str) /** Check whether string is empty. */ static APR_INLINE apr_size_t apt_string_is_empty(const apt_str_t *str) { - return str->length ? TRUE : FALSE; + return str->length ? FALSE : TRUE; } /** @@ -140,4 +142,4 @@ static APR_INLINE apt_bool_t apt_string_compare(const apt_str_t *str1, const apt APT_END_EXTERN_C -#endif /*__APT_STRING_H__*/ +#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 index 112bd6bffc..3ba927f44e 100644 --- a/libs/unimrcp/libs/apr-toolkit/include/apt_string_table.h +++ b/libs/unimrcp/libs/apr-toolkit/include/apt_string_table.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: apt_string_table.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __APT_STRING_TABLE_H__ -#define __APT_STRING_TABLE_H__ +#ifndef APT_STRING_TABLE_H +#define APT_STRING_TABLE_H /** * @file apt_string_table.h @@ -60,4 +62,4 @@ APT_DECLARE(apr_size_t) apt_string_table_id_find(const apt_str_table_item_t tabl APT_END_EXTERN_C -#endif /*__APT_STRING_TABLE_H__*/ +#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 index 29c2dea399..031eff6af8 100644 --- a/libs/unimrcp/libs/apr-toolkit/include/apt_task.h +++ b/libs/unimrcp/libs/apr-toolkit/include/apt_task.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: apt_task.h 1696 2010-05-20 15:44:16Z achaloyan $ */ -#ifndef __APT_TASK_H__ -#define __APT_TASK_H__ +#ifndef APT_TASK_H +#define APT_TASK_H /** * @file apt_task.h @@ -124,19 +126,19 @@ APT_DECLARE(apt_bool_t) apt_task_msg_process(apt_task_t *task, apt_task_msg_t *m * 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); +APT_DECLARE(apt_task_t*) apt_task_parent_get(const 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); +APT_DECLARE(apr_pool_t*) apt_task_pool_get(const 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); +APT_DECLARE(void*) apt_task_object_get(const apt_task_t *task); /** * Get task vtable. @@ -155,7 +157,7 @@ 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); +APT_DECLARE(const char*) apt_task_name_get(const apt_task_t *task); /** * Enable/disable auto ready mode. @@ -170,6 +172,36 @@ APT_DECLARE(void) apt_task_auto_ready_set(apt_task_t *task, apt_bool_t auto_read */ APT_DECLARE(apt_bool_t) apt_task_ready(apt_task_t *task); +/** + * Get the running flag. + * @param task the task + */ +APT_DECLARE(apt_bool_t*) apt_task_running_flag_get(apt_task_t *task); + +/** + * Add start request. + * @param task the task + */ +APT_DECLARE(apt_bool_t) apt_task_start_request_add(apt_task_t *task); + +/** + * Remove start request. + * @param task the task + */ +APT_DECLARE(apt_bool_t) apt_task_start_request_remove(apt_task_t *task); + +/** + * Add termination request. + * @param task the task + */ +APT_DECLARE(apt_bool_t) apt_task_terminate_request_add(apt_task_t *task); + +/** + * Remove termination request. + * @param task the task + */ +APT_DECLARE(apt_bool_t) apt_task_terminate_request_remove(apt_task_t *task); + /** * Hold task execution. * @param msec the time to hold @@ -197,26 +229,16 @@ struct apt_task_vtable_t { apt_task_event_f on_pre_run; /** Virtual post-run event handler */ apt_task_event_f on_post_run; + /** Virtual start-request event handler */ + apt_task_event_f on_start_request; /** Virtual start-complete event handler */ apt_task_event_f on_start_complete; + /** Virtual terminate-request event handler */ + apt_task_event_f on_terminate_request; /** 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__*/ +#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 index 4d43ee5ca3..8680bf4491 100644 --- a/libs/unimrcp/libs/apr-toolkit/include/apt_task_msg.h +++ b/libs/unimrcp/libs/apr-toolkit/include/apt_task_msg.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: apt_task_msg.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __APT_TASK_MSG_H__ -#define __APT_TASK_MSG_H__ +#ifndef APT_TASK_MSG_H +#define APT_TASK_MSG_H /** * @file apt_task_msg.h @@ -77,4 +79,4 @@ APT_DECLARE(void) apt_task_msg_release(apt_task_msg_t *task_msg); APT_END_EXTERN_C -#endif /*__APT_TASK_MSG_H__*/ +#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 index 3e1b2cbeca..ce19f477c7 100644 --- a/libs/unimrcp/libs/apr-toolkit/include/apt_test_suite.h +++ b/libs/unimrcp/libs/apr-toolkit/include/apt_test_suite.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: apt_test_suite.h 1708 2010-05-24 17:03:25Z achaloyan $ */ -#ifndef __APT_TEST_SUITE_H__ -#define __APT_TEST_SUITE_H__ +#ifndef APT_TEST_SUITE_H +#define APT_TEST_SUITE_H /** * @file apt_test_suite.h @@ -92,8 +94,8 @@ APT_DECLARE(apt_bool_t) apt_test_framework_run(apt_test_framework_t *framework, * 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_DECLARE(apr_pool_t*) apt_test_framework_pool_get(const apt_test_framework_t *framework); APT_END_EXTERN_C -#endif /*__APT_TEST_SUITE_H__*/ +#endif /* APT_TEST_SUITE_H */ diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_text_message.h b/libs/unimrcp/libs/apr-toolkit/include/apt_text_message.h new file mode 100644 index 0000000000..40edf0af50 --- /dev/null +++ b/libs/unimrcp/libs/apr-toolkit/include/apt_text_message.h @@ -0,0 +1,125 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: apt_text_message.h 1722 2010-06-01 08:40:35Z achaloyan $ + */ + +#ifndef APT_TEXT_MESSAGE_H +#define APT_TEXT_MESSAGE_H + +/** + * @file apt_text_message.h + * @brief Text Message Interface (RFC5322) + */ + +#include "apt_header_field.h" +#include "apt_text_stream.h" + +APT_BEGIN_EXTERN_C + +/** Status of text message processing (parsing/generation) */ +typedef enum { + APT_MESSAGE_STATUS_COMPLETE, + APT_MESSAGE_STATUS_INCOMPLETE, + APT_MESSAGE_STATUS_INVALID +} apt_message_status_e; + + +/** Opaque text message parser */ +typedef struct apt_message_parser_t apt_message_parser_t; +/** Vtable of text message parser */ +typedef struct apt_message_parser_vtable_t apt_message_parser_vtable_t; + +/** Opaque text message generator */ +typedef struct apt_message_generator_t apt_message_generator_t; +/** Vtable of text message generator */ +typedef struct apt_message_generator_vtable_t apt_message_generator_vtable_t; + +/** Temporary context associated with message and used for its parsing or generation */ +typedef struct apt_message_context_t apt_message_context_t; + +/** Create message parser */ +APT_DECLARE(apt_message_parser_t*) apt_message_parser_create(void *obj, const apt_message_parser_vtable_t *vtable, apr_pool_t *pool); + +/** Parse message by raising corresponding event handlers */ +APT_DECLARE(apt_message_status_e) apt_message_parser_run(apt_message_parser_t *parser, apt_text_stream_t *stream, void **message); + +/** Get external object associated with parser */ +APT_DECLARE(void*) apt_message_parser_object_get(apt_message_parser_t *parser); + +/** Set verbose mode for the parser */ +APT_DECLARE(void) apt_message_parser_verbose_set(apt_message_parser_t *parser, apt_bool_t verbose); + + +/** Create message generator */ +APT_DECLARE(apt_message_generator_t*) apt_message_generator_create(void *obj, const apt_message_generator_vtable_t *vtable, apr_pool_t *pool); + +/** Generate message */ +APT_DECLARE(apt_message_status_e) apt_message_generator_run(apt_message_generator_t *generator, void *message, apt_text_stream_t *stream); + +/** Get external object associated with generator */ +APT_DECLARE(void*) apt_message_generator_object_get(apt_message_generator_t *generator); + +/** Set verbose mode for the parser */ +APT_DECLARE(void) apt_message_generator_verbose_set(apt_message_generator_t *generator, apt_bool_t verbose); + + +/** Parse individual header field (name-value pair) */ +APT_DECLARE(apt_header_field_t*) apt_header_field_parse(apt_text_stream_t *stream, apr_pool_t *pool); + +/** Generate individual header field (name-value pair) */ +APT_DECLARE(apt_bool_t) apt_header_field_generate(const apt_header_field_t *header_field, apt_text_stream_t *stream); + +/** Parse header section */ +APT_DECLARE(apt_bool_t) apt_header_section_parse(apt_header_section_t *header, apt_text_stream_t *stream, apr_pool_t *pool); + +/** Generate header section */ +APT_DECLARE(apt_bool_t) apt_header_section_generate(const apt_header_section_t *header, apt_text_stream_t *stream); + + +/** Temporary context associated with message and used for its parsing or generation */ +struct apt_message_context_t { + /** Context or ptotocol specific message */ + void *message; + /** Header section of the message */ + apt_header_section_t *header; + /** Body or content of the message */ + apt_str_t *body; +}; + +/** Vtable of text message parser */ +struct apt_message_parser_vtable_t { + /** Start new message parsing by associating corresponding context and reading its start-line if applicable */ + apt_bool_t (*on_start)(apt_message_parser_t *parser, apt_message_context_t *context, apt_text_stream_t *stream, apr_pool_t *pool); + /** Header section handler is invoked when entire header section has been read and parsed into header fields */ + apt_bool_t (*on_header_complete)(apt_message_parser_t *parser, apt_message_context_t *context); + /** Body handler is invoked when entire body has been read */ + apt_bool_t (*on_body_complete)(apt_message_parser_t *parser, apt_message_context_t *context); +}; + +/** Vtable of text message generator */ +struct apt_message_generator_vtable_t { + /** Start message generation by associating corresponding context and generating message start-line if applicable */ + apt_bool_t (*on_start)(apt_message_generator_t *generator, apt_message_context_t *context, apt_text_stream_t *stream); + /** Header section handler is invoked to notify header section has been generated */ + apt_bool_t (*on_header_complete)(apt_message_generator_t *generator, apt_message_context_t *context, apt_text_stream_t *stream); + /** Body handler is invoked to notify body has been generated */ + apt_bool_t (*on_body_complete)(apt_message_generator_t *generator, apt_message_context_t *context, apt_text_stream_t *stream); +}; + + +APT_END_EXTERN_C + +#endif /* APT_TEXT_MESSAGE_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 index e9e40cad5b..3df2565145 100644 --- a/libs/unimrcp/libs/apr-toolkit/include/apt_text_stream.h +++ b/libs/unimrcp/libs/apr-toolkit/include/apt_text_stream.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,25 +12,27 @@ * 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. + * + * $Id: apt_text_stream.h 1672 2010-04-28 20:37:22Z achaloyan $ */ -#ifndef __APT_TEXT_STREAM_H__ -#define __APT_TEXT_STREAM_H__ +#ifndef APT_TEXT_STREAM_H +#define APT_TEXT_STREAM_H /** * @file apt_text_stream.h * @brief Text Stream Parse/Generate Routine */ -#include "apt_string.h" +#include "apt_string_table.h" #include "apt_pair.h" APT_BEGIN_EXTERN_C -/** Named tokens */ - /** Space */ -#define APT_TOKEN_SP ' ' +#define APT_TOKEN_SP 0x20 +/** Horizontal tab */ +#define APT_TOKEN_HTAB 0x09 /** Carrige return */ #define APT_TOKEN_CR 0x0D /** Line feed */ @@ -52,73 +54,77 @@ struct apt_text_stream_t { apt_bool_t is_eos; }; + /** - * Navigate through the lines of the text stream (message). - * @param stream the text stream to navigate + * Read entire line of the text stream. + * @param stream the text stream to navigate on * @param line the read line to return * @return TRUE if the line is successfully read, otherwise FALSE + * @remark To be used to 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); /** - * Navigate through the headers (name:value pairs) of the text stream (message). + * Read header field (name-value pair) of the text stream by scanning entire line. * @param stream the text stream to navigate * @param pair the read pair to return * @return TRUE if the header is successfully read, otherwise FALSE + * @remark To be used to navigate through the lines and read header fields + * (name:value pairs) of the text stream (message). */ 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. + * Read the field terminated with specified separator. * @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 + * @return TRUE if the read field isn't empty, otherwise FALSE + * @remark To be used to navigate through the fields of the text stream (message). */ 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 name-value pair line */ +APT_DECLARE(apt_bool_t) apt_text_name_value_insert(apt_text_stream_t *stream, const apt_str_t *name, const apt_str_t *value); - -/** 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); +/** Generate only the name ("name:") of the header field */ +APT_DECLARE(apt_bool_t) apt_text_header_name_insert(apt_text_stream_t *stream, const apt_str_t *name); /** 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); +APT_DECLARE(apt_bool_t) apt_pair_array_generate(const apt_pair_arr_t *arr, apt_str_t *str, apr_pool_t *pool); + +/** Insert array of name-value pairs */ +APT_DECLARE(apt_bool_t) apt_text_pair_array_insert(apt_text_stream_t *stream, const apt_pair_arr_t *arr); /** Parse boolean-value */ APT_DECLARE(apt_bool_t) apt_boolean_value_parse(const apt_str_t *str, apt_bool_t *value); +/** Generate apr_size_t value from pool (buffer is allocated from pool) */ +APT_DECLARE(apt_bool_t) apt_boolean_value_generate(apt_bool_t value, apt_str_t *str, apr_pool_t *pool); -/** Generate boolean-value */ -APT_DECLARE(apt_bool_t) apt_boolean_value_generate(apt_bool_t value, apt_text_stream_t *str); +/** Insert boolean-value */ +APT_DECLARE(apt_bool_t) apt_text_boolean_value_insert(apt_text_stream_t *stream, apt_bool_t value); -/** Parse size_t value */ +/** Parse apr_size_t value */ APT_DECLARE(apr_size_t) apt_size_value_parse(const apt_str_t *str); +/** Generate apr_size_t value from pool (buffer is allocated from pool) */ +APT_DECLARE(apt_bool_t) apt_size_value_generate(apr_size_t value, apt_str_t *str, apr_pool_t *pool); -/** Generate apr_size_t value */ -APT_DECLARE(apt_bool_t) apt_size_value_generate(apr_size_t value, apt_text_stream_t *stream); +/** Insert apr_size_t value */ +APT_DECLARE(apt_bool_t) apt_text_size_value_insert(apt_text_stream_t *stream, apr_size_t value); /** Parse float value */ APT_DECLARE(float) apt_float_value_parse(const apt_str_t *str); +/** Generate float value (buffer is allocated from pool) */ +APT_DECLARE(apt_bool_t) apt_float_value_generate(float value, apt_str_t *str, apr_pool_t *pool); -/** Generate float value */ -APT_DECLARE(apt_bool_t) apt_float_value_generate(float value, apt_text_stream_t *stream); - -/** 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; -} +/** Insert float value */ +APT_DECLARE(apt_bool_t) apt_text_float_value_insert(apt_text_stream_t *stream, float value); +/** Insert string value */ +APT_DECLARE(apt_bool_t) apt_text_string_insert(apt_text_stream_t *stream, const apt_str_t *str); /** Reset navigation related data of the text stream */ static APR_INLINE void apt_text_stream_reset(apt_text_stream_t *stream) @@ -137,36 +143,74 @@ static APR_INLINE void apt_text_stream_init(apt_text_stream_t *stream, char *buf } /** Insert end of the line symbol(s) */ -static APR_INLINE void apt_text_eol_insert(apt_text_stream_t *stream) +static APR_INLINE apt_bool_t apt_text_eol_insert(apt_text_stream_t *stream) { - *stream->pos++ = APT_TOKEN_CR; - *stream->pos++ = APT_TOKEN_LF; + if(stream->pos + 2 < stream->end) { + *stream->pos++ = APT_TOKEN_CR; + *stream->pos++ = APT_TOKEN_LF; + return TRUE; + } + return FALSE; } /** Insert character */ -static APR_INLINE void apt_text_char_insert(apt_text_stream_t *stream, char ch) +static APR_INLINE apt_bool_t apt_text_char_insert(apt_text_stream_t *stream, char ch) { - *stream->pos++ = ch; + if(stream->pos + 1 < stream->end) { + *stream->pos++ = ch; + return TRUE; + } + return FALSE; } /** Insert space */ -static APR_INLINE void apt_text_space_insert(apt_text_stream_t *stream) +static APR_INLINE apt_bool_t apt_text_space_insert(apt_text_stream_t *stream) { - *stream->pos++ = APT_TOKEN_SP; + return apt_text_char_insert(stream,APT_TOKEN_SP); } -/** Skip spaces */ +/** Insert space */ +static APR_INLINE apt_bool_t apt_text_htab_insert(apt_text_stream_t *stream) +{ + return apt_text_char_insert(stream,APT_TOKEN_HTAB); +} + +/** Check whether specified character is a white space (WSP = SP / HTAB) */ +static APR_INLINE apt_bool_t apt_text_is_wsp(char ch) +{ + return (ch == APT_TOKEN_SP || ch == APT_TOKEN_HTAB) ? TRUE : FALSE; +} + +/** Skip sequence of 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++; + while(stream->pos < stream->end && *stream->pos == APT_TOKEN_SP) + stream->pos++; +} + +/** Skip sequence of white spaces (WSP = SP / HTAB) */ +static APR_INLINE void apt_text_white_spaces_skip(apt_text_stream_t *stream) +{ + while(stream->pos < stream->end && apt_text_is_wsp(*stream->pos) == TRUE) + 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++; + if(stream->pos < stream->end && *stream->pos == ch) stream->pos++; +} + +/** Skip sequence of specified characters */ +static APR_INLINE void apt_text_chars_skip(apt_text_stream_t *stream, char ch) +{ + while(stream->pos < stream->end && *stream->pos == ch) stream->pos++; +} + +/** Skip to specified character */ +static APR_INLINE void apt_text_skip_to_char(apt_text_stream_t *stream, char ch) +{ + while(stream->pos < stream->end && *stream->pos != ch) stream->pos++; } /** Check whether end of stream is reached */ @@ -180,13 +224,14 @@ 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 completion-cause */ +APT_DECLARE(apt_bool_t) apt_completion_cause_generate(const apt_str_table_item_t table[], apr_size_t size, apr_size_t cause, apt_str_t *str, apr_pool_t *pool); /** * Generate unique identifier (hex string) @@ -199,4 +244,4 @@ APT_DECLARE(apt_bool_t) apt_unique_id_generate(apt_str_t *id, apr_size_t length, APT_END_EXTERN_C -#endif /*__APT_TEXT_STREAM_H__*/ +#endif /* APT_TEXT_STREAM_H */ diff --git a/libs/unimrcp/libs/apr-toolkit/include/apt_timer_queue.h b/libs/unimrcp/libs/apr-toolkit/include/apt_timer_queue.h new file mode 100644 index 0000000000..0536e94a8d --- /dev/null +++ b/libs/unimrcp/libs/apr-toolkit/include/apt_timer_queue.h @@ -0,0 +1,68 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: apt_timer_queue.h 1642 2010-04-08 13:37:57Z achaloyan $ + */ + +#ifndef APT_TIMER_QUEUE_H +#define APT_TIMER_QUEUE_H + +/** + * @file apt_timer_queue.h + * @brief Timer Queue + */ + +#include "apt.h" + +APT_BEGIN_EXTERN_C + +/** Opaque timer declaration */ +typedef struct apt_timer_t apt_timer_t; +/** Opaque timer queue declaration */ +typedef struct apt_timer_queue_t apt_timer_queue_t; + +/** Prototype of timer callback */ +typedef void (*apt_timer_proc_f)(apt_timer_t *timer, void *obj); + + +/** Create timer queue */ +APT_DECLARE(apt_timer_queue_t*) apt_timer_queue_create(apr_pool_t *pool); + +/** Destroy timer queue */ +APT_DECLARE(void) apt_timer_queue_destroy(apt_timer_queue_t *timer_queue); + +/** Advance scheduled timers */ +APT_DECLARE(void) apt_timer_queue_advance(apt_timer_queue_t *timer_queue, apr_uint32_t elapsed_time); + +/** Is timer queue empty */ +APT_DECLARE(apt_bool_t) apt_timer_queue_is_empty(const apt_timer_queue_t *timer_queue); + +/** Get current timeout */ +APT_DECLARE(apt_bool_t) apt_timer_queue_timeout_get(const apt_timer_queue_t *timer_queue, apr_uint32_t *timeout); + + +/** Create timer */ +APT_DECLARE(apt_timer_t*) apt_timer_create(apt_timer_queue_t *timer_queue, apt_timer_proc_f proc, void *obj, apr_pool_t *pool); + +/** Set one-shot timer */ +APT_DECLARE(apt_bool_t) apt_timer_set(apt_timer_t *timer, apr_uint32_t timeout); + +/** Kill timer */ +APT_DECLARE(apt_bool_t) apt_timer_kill(apt_timer_t *timer); + + +APT_END_EXTERN_C + +#endif /* APT_TIMER_QUEUE_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 index ceb9320d98..28c691a274 100644 --- a/libs/unimrcp/libs/apr-toolkit/src/apt_consumer_task.c +++ b/libs/unimrcp/libs/apr-toolkit/src/apt_consumer_task.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: apt_consumer_task.c 1708 2010-05-24 17:03:25Z achaloyan $ */ #include @@ -54,7 +56,7 @@ APT_DECLARE(apt_consumer_task_t*) apt_consumer_task_create( return consumer_task; } -APT_DECLARE(apt_task_t*) apt_consumer_task_base_get(apt_consumer_task_t *task) +APT_DECLARE(apt_task_t*) apt_consumer_task_base_get(const apt_consumer_task_t *task) { return task->base; } @@ -64,7 +66,7 @@ APT_DECLARE(apt_task_vtable_t*) apt_consumer_task_vtable_get(apt_consumer_task_t return apt_task_vtable_get(task->base); } -APT_DECLARE(void*) apt_consumer_task_object_get(apt_consumer_task_t *task) +APT_DECLARE(void*) apt_consumer_task_object_get(const apt_consumer_task_t *task) { return task->obj; } @@ -79,22 +81,25 @@ static apt_bool_t apt_consumer_task_run(apt_task_t *task) { apr_status_t rv; void *msg; - apt_bool_t running = TRUE; + apt_bool_t *running; apt_consumer_task_t *consumer_task; consumer_task = apt_task_object_get(task); if(!consumer_task) { return FALSE; } - while(running) { - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Wait for Task Messages [%s]",apt_task_name_get(task)); + running = apt_task_running_flag_get(task); + if(!running) { + return FALSE; + } + + while(*running) { + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Wait for Messages [%s]",apt_task_name_get(task)); 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; - } + apt_task_msg_process(consumer_task->base,task_msg); } } } diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_cyclic_queue.c b/libs/unimrcp/libs/apr-toolkit/src/apt_cyclic_queue.c index fff7de514f..2ac36c4dbb 100644 --- a/libs/unimrcp/libs/apr-toolkit/src/apt_cyclic_queue.c +++ b/libs/unimrcp/libs/apr-toolkit/src/apt_cyclic_queue.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: apt_cyclic_queue.c 1708 2010-05-24 17:03:25Z achaloyan $ */ #include @@ -78,7 +80,7 @@ APT_DECLARE(void) apt_cyclic_queue_clear(apt_cyclic_queue_t *queue) queue->head = queue->tail = 0; } -APT_DECLARE(apt_bool_t) apt_cyclic_queue_is_empty(apt_cyclic_queue_t *queue) +APT_DECLARE(apt_bool_t) apt_cyclic_queue_is_empty(const apt_cyclic_queue_t *queue) { return queue->actual_size ? TRUE : FALSE; } diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_dir_layout.c b/libs/unimrcp/libs/apr-toolkit/src/apt_dir_layout.c index 9a527b63b0..2e651863d8 100644 --- a/libs/unimrcp/libs/apr-toolkit/src/apt_dir_layout.c +++ b/libs/unimrcp/libs/apr-toolkit/src/apt_dir_layout.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: apt_dir_layout.c 1524 2010-02-15 20:44:16Z achaloyan $ */ #include @@ -72,3 +74,14 @@ APT_DECLARE(char*) apt_datadir_filepath_get(const apt_dir_layout_t *dir_layout, } return NULL; } + +APT_DECLARE(char*) apt_confdir_filepath_get(const apt_dir_layout_t *dir_layout, const char *file_name, apr_pool_t *pool) +{ + if(dir_layout && dir_layout->conf_dir_path && file_name) { + char *file_path = NULL; + if(apr_filepath_merge(&file_path,dir_layout->conf_dir_path,file_name,0,pool) == APR_SUCCESS) { + return file_path; + } + } + return NULL; +} diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_header_field.c b/libs/unimrcp/libs/apr-toolkit/src/apt_header_field.c new file mode 100644 index 0000000000..9cf814549f --- /dev/null +++ b/libs/unimrcp/libs/apr-toolkit/src/apt_header_field.c @@ -0,0 +1,183 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: apt_header_field.c 1685 2010-05-06 05:34:54Z achaloyan $ + */ + +#include "apt_header_field.h" +#include "apt_text_stream.h" + +#define UNKNOWN_HEADER_FIELD_ID (apr_size_t)-1 + +/** Allocate an empty header field */ +APT_DECLARE(apt_header_field_t*) apt_header_field_alloc(apr_pool_t *pool) +{ + apt_header_field_t *header_field = apr_palloc(pool,sizeof(apt_header_field_t)); + apt_string_reset(&header_field->name); + apt_string_reset(&header_field->value); + header_field->id = UNKNOWN_HEADER_FIELD_ID; + APR_RING_ELEM_INIT(header_field,link); + return header_field; +} + +/** Create a header field using given name and value APT strings */ +APT_DECLARE(apt_header_field_t*) apt_header_field_create(const apt_str_t *name, const apt_str_t *value, apr_pool_t *pool) +{ + apt_header_field_t *header_field; + if(!name || !value) { + return NULL; + } + header_field = apr_palloc(pool,sizeof(apt_header_field_t)); + apt_string_copy(&header_field->name,name,pool); + apt_string_copy(&header_field->value,value,pool); + header_field->id = UNKNOWN_HEADER_FIELD_ID; + APR_RING_ELEM_INIT(header_field,link); + return header_field; +} + +/** Create a header field using given name and value C strings */ +APT_DECLARE(apt_header_field_t*) apt_header_field_create_c(const char *name, const char *value, apr_pool_t *pool) +{ + apt_header_field_t *header_field; + if(!name || !value) { + return NULL; + } + header_field = apr_palloc(pool,sizeof(apt_header_field_t)); + apt_string_assign(&header_field->name,name,pool); + apt_string_assign(&header_field->value,value,pool); + header_field->id = UNKNOWN_HEADER_FIELD_ID; + APR_RING_ELEM_INIT(header_field,link); + return header_field; +} + +/* Create a header field from entire text line consisting of a name and value pair */ +APT_DECLARE(apt_header_field_t*) apt_header_field_create_from_line(const apt_str_t *line, char separator, apr_pool_t *pool) +{ + apt_str_t item; + apt_text_stream_t stream; + apt_header_field_t *header_field; + if(!line) { + return NULL; + } + + header_field = apr_palloc(pool,sizeof(apt_header_field_t)); + stream.text = *line; + apt_text_stream_reset(&stream); + + /* read name */ + if(apt_text_field_read(&stream,separator,TRUE,&item) == FALSE) { + return NULL; + } + apt_string_copy(&header_field->name,&item,pool); + + /* read value */ + apt_text_field_read(&stream,0,TRUE,&item); + apt_string_copy(&header_field->value,&item,pool); + + header_field->id = UNKNOWN_HEADER_FIELD_ID; + APR_RING_ELEM_INIT(header_field,link); + return header_field; +} + +/** Copy specified header field */ +APT_DECLARE(apt_header_field_t*) apt_header_field_copy(const apt_header_field_t *src_header_field, apr_pool_t *pool) +{ + apt_header_field_t *header_field = apr_palloc(pool,sizeof(apt_header_field_t)); + apt_string_copy(&header_field->name,&src_header_field->name,pool); + apt_string_copy(&header_field->value,&src_header_field->value,pool); + header_field->id = src_header_field->id; + APR_RING_ELEM_INIT(header_field,link); + return header_field; +} + +/** Initialize header section (collection of header fields) */ +APT_DECLARE(void) apt_header_section_init(apt_header_section_t *header) +{ + APR_RING_INIT(&header->ring, apt_header_field_t, link); + header->arr = NULL; + header->arr_size = 0; +} + +/** Allocate header section to set/get header fields by numeric identifiers */ +APT_DECLARE(apt_bool_t) apt_header_section_array_alloc(apt_header_section_t *header, apr_size_t max_field_count, apr_pool_t *pool) +{ + if(!max_field_count) { + return FALSE; + } + + header->arr = (apt_header_field_t**)apr_pcalloc(pool,sizeof(apt_header_field_t*) * max_field_count); + header->arr_size = max_field_count; + return TRUE; +} + +/** Add (append) header field to header section */ +APT_DECLARE(apt_bool_t) apt_header_section_field_add(apt_header_section_t *header, apt_header_field_t *header_field) +{ + if(header_field->id < header->arr_size) { + if(header->arr[header_field->id]) { + return FALSE; + } + header->arr[header_field->id] = header_field; + } + APR_RING_INSERT_TAIL(&header->ring,header_field,apt_header_field_t,link); + return TRUE; +} + +/** Insert header field to header section based on numreic identifier if specified */ +APT_DECLARE(apt_bool_t) apt_header_section_field_insert(apt_header_section_t *header, apt_header_field_t *header_field) +{ + apt_header_field_t *it; + if(header_field->id < header->arr_size) { + if(header->arr[header_field->id]) { + return FALSE; + } + header->arr[header_field->id] = header_field; + + for(it = APR_RING_FIRST(&header->ring); + it != APR_RING_SENTINEL(&header->ring, apt_header_field_t, link); + it = APR_RING_NEXT(it, link)) { + if(header_field->id < it->id) { + APR_RING_INSERT_BEFORE(it,header_field,link); + return TRUE; + } + } + } + + APR_RING_INSERT_TAIL(&header->ring,header_field,apt_header_field_t,link); + return TRUE; +} + +/** Set header field in the array of header fields using associated numeric identifier */ +APT_DECLARE(apt_bool_t) apt_header_section_field_set(apt_header_section_t *header, apt_header_field_t *header_field) +{ + if(header_field->id >= header->arr_size) { + return FALSE; + } + if(header->arr[header_field->id]) { + return FALSE; + } + header->arr[header_field->id] = header_field; + return TRUE; +} + +/** Remove header field from header section */ +APT_DECLARE(apt_bool_t) apt_header_section_field_remove(apt_header_section_t *header, apt_header_field_t *header_field) +{ + if(header_field->id < header->arr_size) { + header->arr[header_field->id] = NULL; + } + APR_RING_REMOVE(header_field,link); + return TRUE; +} diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_log.c b/libs/unimrcp/libs/apr-toolkit/src/apt_log.c index 4ad91a996b..10b374d957 100644 --- a/libs/unimrcp/libs/apr-toolkit/src/apt_log.c +++ b/libs/unimrcp/libs/apr-toolkit/src/apt_log.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,14 @@ * 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. + * + * $Id: apt_log.c 1792 2011-01-10 21:08:52Z achaloyan $ */ #include #include +#include +#include #include "apt_log.h" #define MAX_LOG_ENTRY_SIZE 4096 @@ -43,6 +47,7 @@ struct apt_log_file_data_t { apr_size_t max_size; apr_size_t cur_file_index; apr_size_t max_file_count; + apt_bool_t append; apr_thread_mutex_t *mutex; apr_pool_t *pool; }; @@ -53,6 +58,7 @@ struct apt_logger_t { int header; apt_log_ext_handler_f ext_handler; apt_log_file_data_t *file_data; + apt_log_masking_e masking; }; static apt_logger_t *apt_logger = NULL; @@ -61,19 +67,83 @@ static apt_bool_t apt_do_log(const char *file, int line, apt_log_priority_e prio 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); +static apr_xml_doc* apt_log_doc_parse(const char *file_path, apr_pool_t *pool); +static apr_size_t apt_log_file_get_size(apt_log_file_data_t *file_data); +static apr_byte_t apt_log_file_exist(apt_log_file_data_t *file_data); +static apt_logger_t* apt_log_instance_alloc(apr_pool_t *pool) +{ + apt_logger_t *logger = apr_palloc(pool,sizeof(apt_logger_t)); + logger->mode = APT_LOG_OUTPUT_CONSOLE; + logger->priority = APT_PRIO_INFO; + logger->header = APT_LOG_HEADER_DEFAULT; + logger->ext_handler = NULL; + logger->file_data = NULL; + logger->masking = APT_LOG_MASKING_NONE; + return logger; +} 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 = apt_log_instance_alloc(pool); 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_load(const char *config_file, apr_pool_t *pool) +{ + apr_xml_doc *doc; + const apr_xml_elem *elem; + const apr_xml_elem *root; + char *text; + + if(apt_logger) { + return FALSE; + } + apt_logger = apt_log_instance_alloc(pool); + + /* Parse XML document */ + doc = apt_log_doc_parse(config_file,pool); + if(!doc) { + return FALSE; + } + + root = doc->root; + + /* Match document name */ + if(!root || strcasecmp(root->name,"aptlogger") != 0) { + /* Unknown document */ + return FALSE; + } + + /* Navigate through document */ + for(elem = root->first_child; elem; elem = elem->next) { + if(!elem->first_cdata.first || !elem->first_cdata.first->text) + continue; + + text = apr_pstrdup(pool,elem->first_cdata.first->text); + apr_collapse_spaces(text,text); + + if(strcasecmp(elem->name,"priority") == 0) { + apt_logger->priority = apt_log_priority_translate(text); + } + else if(strcasecmp(elem->name,"output") == 0) { + apt_logger->mode = apt_log_output_mode_translate(text); + } + else if(strcasecmp(elem->name,"headers") == 0) { + apt_logger->header = apt_log_header_translate(text); + } + else if(strcasecmp(elem->name,"masking") == 0) { + apt_logger->masking = apt_log_masking_translate(text); + } + else { + /* Unknown element */ + } + } return TRUE; } @@ -104,7 +174,13 @@ APT_DECLARE(apt_bool_t) apt_log_instance_set(apt_logger_t *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) +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, + apt_bool_t append, + apr_pool_t *pool) { const char *log_file_path; apt_log_file_data_t *file_data; @@ -117,29 +193,55 @@ APT_DECLARE(apt_bool_t) apt_log_file_open(const char *dir_path, const char *file } 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->log_dir_path = apr_pstrdup(pool,dir_path); + file_data->log_file_name = apr_pstrdup(pool,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->append = append; file_data->mutex = NULL; file_data->pool = pool; if(!file_data->max_size) { - file_data->max_file_count = MAX_LOG_FILE_SIZE; + file_data->max_size = MAX_LOG_FILE_SIZE; } if(!file_data->max_file_count) { file_data->max_file_count = MAX_LOG_FILE_COUNT; } + if(file_data->append == TRUE) { + /* iteratively find the last created file */ + while(file_data->cur_file_indexmax_file_count) + { + if(apt_log_file_exist(file_data) == 0) + { + if(file_data->cur_file_index > 0) + file_data->cur_file_index--; + file_data->cur_size = apt_log_file_get_size(file_data); + break; + } + file_data->cur_file_index++; + } + + /* if all the files have been created start rewriting from beginning */ + if(file_data->cur_file_index>=file_data->max_file_count) + { + file_data->cur_file_index=0; + file_data->cur_size=0; + log_file_path = apt_log_file_path_make(file_data); + file_data->file = fopen(log_file_path,"wb"); /* truncate the first file to zero length */ + fclose(file_data->file); + } + } + /* 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"); + file_data->file = fopen(log_file_path,file_data->append == TRUE ? "ab" : "wb"); if(!file_data->file) { apr_thread_mutex_destroy(file_data->mutex); return FALSE; @@ -177,6 +279,31 @@ APT_DECLARE(apt_bool_t) apt_log_output_mode_set(apt_log_output_e mode) return TRUE; } +APT_DECLARE(apt_bool_t) apt_log_output_mode_check(apt_log_output_e mode) +{ + if(!apt_logger) { + return FALSE; + } + return (apt_logger->mode | mode) ? TRUE : FALSE; +} + +APT_DECLARE(int) apt_log_output_mode_translate(char *str) +{ + int mode = APT_LOG_OUTPUT_NONE; + char *name; + char *last; + name = apr_strtok(str, ",", &last); + while(name) { + if(strcasecmp(name, "CONSOLE") == 0) + mode |= APT_LOG_OUTPUT_CONSOLE; + else if(strcasecmp(name, "FILE") == 0) + mode |= APT_LOG_OUTPUT_FILE; + + name = apr_strtok(NULL, ",", &last); + } + return mode; +} + APT_DECLARE(apt_bool_t) apt_log_priority_set(apt_log_priority_e priority) { if(!apt_logger || priority >= APT_PRIO_COUNT) { @@ -186,6 +313,28 @@ APT_DECLARE(apt_bool_t) apt_log_priority_set(apt_log_priority_e priority) return TRUE; } +APT_DECLARE(apt_log_priority_e) apt_log_priority_translate(const char *str) +{ + if(strcasecmp(str, "EMERGENCY") == 0) + return APT_PRIO_EMERGENCY; + else if(strcasecmp(str, "ALERT") == 0) + return APT_PRIO_ALERT; + else if(strcasecmp(str, "CRITICAL") == 0) + return APT_PRIO_CRITICAL; + else if(strcasecmp(str, "ERROR") == 0) + return APT_PRIO_ERROR; + else if(strcasecmp(str, "WARNING") == 0) + return APT_PRIO_WARNING; + else if(strcasecmp(str, "NOTICE") == 0) + return APT_PRIO_NOTICE; + else if(strcasecmp(str, "INFO") == 0) + return APT_PRIO_INFO; + else if(strcasecmp(str, "DEBUG") == 0) + return APT_PRIO_DEBUG; + + return APT_PRIO_DEBUG; +} + APT_DECLARE(apt_bool_t) apt_log_header_set(int header) { if(!apt_logger) { @@ -195,6 +344,69 @@ APT_DECLARE(apt_bool_t) apt_log_header_set(int header) return TRUE; } +APT_DECLARE(int) apt_log_header_translate(char *str) +{ + int header = APT_LOG_OUTPUT_NONE; + char *name; + char *last; + name = apr_strtok(str, ",", &last); + while(name) { + if(strcasecmp(name, "DATE") == 0) + header |= APT_LOG_HEADER_DATE; + else if(strcasecmp(name, "TIME") == 0) + header |= APT_LOG_HEADER_TIME; + else if(strcasecmp(name, "PRIORITY") == 0) + header |= APT_LOG_HEADER_PRIORITY; + else if(strcasecmp(name, "MARK") == 0) + header |= APT_LOG_HEADER_MARK; + else if(strcasecmp(name, "THREAD") == 0) + header |= APT_LOG_HEADER_THREAD; + + name = apr_strtok(NULL, ",", &last); + } + return header; +} + +APT_DECLARE(apt_bool_t) apt_log_masking_set(apt_log_masking_e masking) +{ + if(!apt_logger) { + return FALSE; + } + apt_logger->masking = masking; + return TRUE; +} + +APT_DECLARE(apt_log_masking_e) apt_log_masking_get() +{ + if(!apt_logger) { + return APT_LOG_MASKING_NONE; + } + return apt_logger->masking; +} + +APT_DECLARE(apt_log_masking_e) apt_log_masking_translate(const char *str) +{ + if(strcasecmp(str, "COMPLETE") == 0) + return APT_LOG_MASKING_COMPLETE; + else if(strcasecmp(str, "ENCRYPTED") == 0) + return APT_LOG_MASKING_ENCRYPTED; + return APT_LOG_MASKING_NONE; +} + +#define APT_MASKED_CONTENT "*** masked ***" + +APT_DECLARE(const char*) apt_log_data_mask(const char *data_in, apr_size_t *length, apr_pool_t *pool) +{ + if(!apt_logger) { + return NULL; + } + if(apt_logger->masking == APT_LOG_MASKING_COMPLETE) { + *length = sizeof(APT_MASKED_CONTENT) - 1; + return APT_MASKED_CONTENT; + } + return data_in; +} + APT_DECLARE(apt_bool_t) apt_log_ext_handler_set(apt_log_ext_handler_f handler) { if(!apt_logger) { @@ -224,6 +436,35 @@ APT_DECLARE(apt_bool_t) apt_log(const char *file, int line, apt_log_priority_e p return status; } +APT_DECLARE(apt_bool_t) apt_obj_log(const char *file, int line, apt_log_priority_e priority, void *obj, 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,obj,priority,format,arg_ptr); + } + else { + status = apt_do_log(file,line,priority,format,arg_ptr); + } + va_end(arg_ptr); + } + return status; +} + +static APR_INLINE unsigned long apt_thread_id_get() +{ +#ifdef WIN32 + return (unsigned long) GetCurrentThreadId(); +#else + return (unsigned long) apr_os_thread_current(); +#endif +} + 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]; @@ -249,6 +490,9 @@ static apt_bool_t apt_do_log(const char *file, int line, apt_log_priority_e prio if(apt_logger->header & APT_LOG_HEADER_MARK) { offset += apr_snprintf(log_entry+offset,max_size-offset,"%s:%03d ",file,line); } + if(apt_logger->header & APT_LOG_HEADER_THREAD) { + offset += apr_snprintf(log_entry+offset,max_size-offset,"%05lu ",apt_thread_id_get()); + } if(apt_logger->header & APT_LOG_HEADER_PRIORITY) { memcpy(log_entry+offset,priority_snames[priority],MAX_PRIORITY_NAME_LENGTH); offset += MAX_PRIORITY_NAME_LENGTH; @@ -275,6 +519,40 @@ static const char* apt_log_file_path_make(apt_log_file_data_t *file_data) return log_file_path; } +static apr_size_t apt_log_file_get_size(apt_log_file_data_t *file_data) +{ + FILE* fp; + const char *log_file_path; + apr_size_t ret; + + log_file_path = apt_log_file_path_make(file_data); + fp = fopen(log_file_path,"rb"); + + if(!fp) return 0; + + fseek(fp,0,SEEK_END); + ret = ftell(fp); + + fclose(fp); + + return ret; +} + +static apr_byte_t apt_log_file_exist(apt_log_file_data_t *file_data) +{ + FILE* fp; + const char *log_file_path; + + log_file_path = apt_log_file_path_make(file_data); + fp = fopen(log_file_path,"rb"); + + if(!fp) return 0; + + fclose(fp); + + return 1; +} + 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); @@ -303,3 +581,24 @@ static apt_bool_t apt_log_file_dump(apt_log_file_data_t *file_data, const char * apr_thread_mutex_unlock(file_data->mutex); return TRUE; } + +static apr_xml_doc* apt_log_doc_parse(const char *file_path, apr_pool_t *pool) +{ + apr_xml_parser *parser = NULL; + apr_xml_doc *xml_doc = NULL; + apr_file_t *fd = NULL; + apr_status_t rv; + + rv = apr_file_open(&fd,file_path,APR_READ|APR_BINARY,0,pool); + if(rv != APR_SUCCESS) { + return NULL; + } + + rv = apr_xml_parse_file(pool,&parser,&xml_doc,fd,2000); + if(rv != APR_SUCCESS) { + xml_doc = NULL; + } + + apr_file_close(fd); + return xml_doc; +} diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_multipart_content.c b/libs/unimrcp/libs/apr-toolkit/src/apt_multipart_content.c new file mode 100644 index 0000000000..3f3690ff7a --- /dev/null +++ b/libs/unimrcp/libs/apr-toolkit/src/apt_multipart_content.c @@ -0,0 +1,312 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: apt_multipart_content.c 1673 2010-04-28 20:45:47Z achaloyan $ + */ + +#include +#include "apt_multipart_content.h" +#include "apt_text_stream.h" +#include "apt_text_message.h" + +#define CONTENT_LENGTH_HEADER "Content-Length" +#define CONTENT_TYPE_HEADER "Content-Type" +#define CONTENT_ID_HEADER "Content-Id" + +#define DEFAULT_BOUNDARY "break" +#define DEFAULT_HYPHENS "--" + +#define DEFAULT_MULTIPART_CONTENT_SIZE 4096 + +/** Multipart content */ +struct apt_multipart_content_t { + apr_pool_t *pool; + apt_text_stream_t stream; + + apt_str_t boundary; + apt_str_t hyphens; +}; + +/** Create an empty multipart content */ +APT_DECLARE(apt_multipart_content_t*) apt_multipart_content_create(apr_size_t max_content_size, const apt_str_t *boundary, apr_pool_t *pool) +{ + char *buffer; + apt_multipart_content_t *multipart_content = apr_palloc(pool,sizeof(apt_multipart_content_t)); + multipart_content->pool = pool; + + if(max_content_size == 0) { + max_content_size = DEFAULT_MULTIPART_CONTENT_SIZE; + } + + if(boundary) { + multipart_content->boundary = *boundary; + } + else { + multipart_content->boundary.buf = DEFAULT_BOUNDARY; + multipart_content->boundary.length = sizeof(DEFAULT_BOUNDARY)-1; + } + + multipart_content->hyphens.buf = DEFAULT_HYPHENS; + multipart_content->hyphens.length = sizeof(DEFAULT_HYPHENS)-1; + + buffer = apr_palloc(pool,max_content_size+1); + apt_text_stream_init(&multipart_content->stream,buffer,max_content_size); + return multipart_content; +} + +/** Initialize content part generation */ +static apt_bool_t apt_multipart_content_initialize(apt_multipart_content_t *multipart_content) +{ + /* insert preceding end-of-line */ + if(apt_text_eol_insert(&multipart_content->stream) == FALSE) { + return FALSE; + } + /* insert hyphens */ + if(apt_text_string_insert(&multipart_content->stream,&multipart_content->hyphens) == FALSE) { + return FALSE; + } + /* insert boundary */ + if(apt_text_string_insert(&multipart_content->stream,&multipart_content->boundary) == FALSE) { + return FALSE; + } + return apt_text_eol_insert(&multipart_content->stream); +} + +/** Add content part to multipart content */ +APT_DECLARE(apt_bool_t) apt_multipart_content_add(apt_multipart_content_t *multipart_content, const apt_content_part_t *content_part) +{ + if(!content_part) { + return FALSE; + } + + /* insert preceding eol, hyppens and boudnary */ + if(apt_multipart_content_initialize(multipart_content) == FALSE) { + return FALSE; + } + + /* insert header fields */ + if(apt_header_section_generate(&content_part->header,&multipart_content->stream) == FALSE) { + return FALSE; + } + + /* insert body */ + return apt_text_string_insert(&multipart_content->stream,&content_part->body); +} + +/** Add content part to multipart content by specified header fields and body */ +APT_DECLARE(apt_bool_t) apt_multipart_content_add2(apt_multipart_content_t *multipart_content, const apt_str_t *content_type, const apt_str_t *content_id, const apt_str_t *body) +{ + /* insert preceding eol, hyppens and boudnary */ + if(apt_multipart_content_initialize(multipart_content) == FALSE) { + return FALSE; + } + + /* insert content-type */ + if(content_type) { + apt_str_t name = {CONTENT_TYPE_HEADER,sizeof(CONTENT_TYPE_HEADER)-1}; + if(apt_text_name_value_insert(&multipart_content->stream,&name,content_type) == FALSE) { + return FALSE; + } + } + + /* insert content-id */ + if(content_id) { + apt_str_t name = {CONTENT_ID_HEADER,sizeof(CONTENT_ID_HEADER)-1}; + if(apt_text_name_value_insert(&multipart_content->stream,&name,content_id) == FALSE) { + return FALSE; + } + } + + /* insert content-length */ + if(body) { + apt_str_t name = {CONTENT_LENGTH_HEADER,sizeof(CONTENT_LENGTH_HEADER)-1}; + if(apt_text_header_name_insert(&multipart_content->stream,&name) == FALSE) { + return FALSE; + } + if(apt_text_size_value_insert(&multipart_content->stream,body->length) == FALSE) { + return FALSE; + } + if(apt_text_eol_insert(&multipart_content->stream) == FALSE) { + return FALSE; + } + } + + /* insert empty line */ + if(apt_text_eol_insert(&multipart_content->stream) == FALSE) { + return FALSE; + } + + /* insert body */ + if(body) { + if(apt_text_string_insert(&multipart_content->stream,body) == FALSE) { + return FALSE; + } + } + return TRUE; +} + +/** Finalize multipart content generation */ +APT_DECLARE(apt_str_t*) apt_multipart_content_finalize(apt_multipart_content_t *multipart_content) +{ + apt_text_stream_t *stream = &multipart_content->stream; + /* insert preceding end-of-line */ + if(apt_text_eol_insert(&multipart_content->stream) == FALSE) { + return NULL; + } + /* insert hyphens */ + if(apt_text_string_insert(&multipart_content->stream,&multipart_content->hyphens) == FALSE) { + return NULL; + } + /* insert boundary */ + if(apt_text_string_insert(&multipart_content->stream,&multipart_content->boundary) == FALSE) { + return NULL; + } + /* insert final hyphens */ + if(apt_text_string_insert(&multipart_content->stream,&multipart_content->hyphens) == FALSE) { + return NULL; + } + if(apt_text_eol_insert(&multipart_content->stream) == FALSE) { + return NULL; + } + + stream->text.length = stream->pos - stream->text.buf; + stream->text.buf[stream->text.length] = '\0'; + return &stream->text; +} + + +/** Assign body to multipart content to get (parse) each content part from */ +APT_DECLARE(apt_multipart_content_t*) apt_multipart_content_assign(const apt_str_t *body, const apt_str_t *boundary, apr_pool_t *pool) +{ + apt_multipart_content_t *multipart_content = apr_palloc(pool,sizeof(apt_multipart_content_t)); + multipart_content->pool = pool; + + if(!body) { + return FALSE; + } + + if(boundary) { + multipart_content->boundary = *boundary; + } + else { + apt_string_reset(&multipart_content->boundary); + } + + apt_string_reset(&multipart_content->hyphens); + apt_text_stream_init(&multipart_content->stream,body->buf,body->length); + return multipart_content; +} + +static APR_INLINE void apt_content_part_reset(apt_content_part_t *content_part) +{ + apt_header_section_init(&content_part->header); + apt_string_reset(&content_part->body); + content_part->type = NULL; + content_part->id = NULL; + content_part->length = NULL; +} + +/** Get the next content part */ +APT_DECLARE(apt_bool_t) apt_multipart_content_get(apt_multipart_content_t *multipart_content, apt_content_part_t *content_part, apt_bool_t *is_final) +{ + apt_str_t boundary; + apt_header_field_t *header_field; + apt_text_stream_t *stream = &multipart_content->stream; + + if(!content_part || !is_final) { + return FALSE; + } + *is_final = FALSE; + apt_content_part_reset(content_part); + + /* skip preamble */ + apt_text_skip_to_char(stream,'-'); + if(apt_text_is_eos(stream) == TRUE) { + return FALSE; + } + + /* skip initial hyphens */ + apt_text_chars_skip(stream,'-'); + if(apt_text_is_eos(stream) == TRUE) { + return FALSE; + } + + /* read line and the boundary */ + if(apt_text_line_read(stream,&boundary) == FALSE) { + return FALSE; + } + + /* remove optional trailing spaces */ + while(boundary.length && boundary.buf[boundary.length-1] == APT_TOKEN_SP) boundary.length--; + + /* check whether this is the final boundary */ + if(boundary.length >= 2) { + if(boundary.buf[boundary.length-1] == '-' && boundary.buf[boundary.length-2] == '-') { + /* final boundary */ + boundary.length -= 2; + *is_final = TRUE; + } + } + + /* compare boundaries */ + if(apt_string_is_empty(&multipart_content->boundary) == TRUE) { + /* no boundary was specified from user space, + learn boundary from the content */ + multipart_content->boundary = boundary; + } + else { + if(apt_string_compare(&multipart_content->boundary,&boundary) == FALSE) { + /* invalid boundary */ + return FALSE; + } + } + + if(*is_final == TRUE) { + /* final boundary => return TRUE, content remains empty */ + return TRUE; + } + + /* read header fields */ + if(apt_header_section_parse(&content_part->header,stream,multipart_content->pool) == FALSE) { + return FALSE; + } + + for(header_field = APR_RING_FIRST(&content_part->header.ring); + header_field != APR_RING_SENTINEL(&content_part->header.ring, apt_header_field_t, link); + header_field = APR_RING_NEXT(header_field, link)) { + if(strncmp(header_field->name.buf,CONTENT_LENGTH_HEADER,header_field->name.length) == 0) { + content_part->length = &header_field->value; + } + else if(strncmp(header_field->name.buf,CONTENT_TYPE_HEADER,header_field->name.length) == 0) { + content_part->type = &header_field->value; + } + else if(strncmp(header_field->name.buf,CONTENT_ID_HEADER,header_field->name.length) == 0) { + content_part->id = &header_field->value; + } + } + + if(content_part->length && apt_string_is_empty(content_part->length) == FALSE) { + apr_size_t length = atoi(content_part->length->buf); + if(length + stream->pos > stream->end) { + return FALSE; + } + + /* read content */ + apt_string_assign_n(&content_part->body,stream->pos,length,multipart_content->pool); + stream->pos += length; + } + + return TRUE; +} diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_net.c b/libs/unimrcp/libs/apr-toolkit/src/apt_net.c index 733f0e20bc..e8da32a5b4 100644 --- a/libs/unimrcp/libs/apr-toolkit/src/apt_net.c +++ b/libs/unimrcp/libs/apr-toolkit/src/apt_net.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: apt_net.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include 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 deleted file mode 100644 index 6effe42f3c..0000000000 --- a/libs/unimrcp/libs/apr-toolkit/src/apt_net_client_task.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * 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; - } - apt_task_auto_ready_set(task->base,FALSE); - - 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; - } - - /* explicitly indicate task is ready to process messages */ - apt_task_ready(task->base); - - 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); - 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 deleted file mode 100644 index 93cc9f5d69..0000000000 --- a/libs/unimrcp/libs/apr-toolkit/src/apt_net_server_task.c +++ /dev/null @@ -1,393 +0,0 @@ -/* - * 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; - } - apt_task_auto_ready_set(task->base,FALSE); - - 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; - } - - /* explicitly indicate task is ready to process messages */ - apt_task_ready(task->base); - - 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); - 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_nlsml_doc.c b/libs/unimrcp/libs/apr-toolkit/src/apt_nlsml_doc.c index 4e4ae82124..af46ab7342 100644 --- a/libs/unimrcp/libs/apr-toolkit/src/apt_nlsml_doc.c +++ b/libs/unimrcp/libs/apr-toolkit/src/apt_nlsml_doc.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,9 +12,12 @@ * 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. + * + * $Id: apt_nlsml_doc.c 1655 2010-04-16 18:36:27Z achaloyan $ */ #include "apt_nlsml_doc.h" +#include "apt_log.h" /** Load NLSML document */ APT_DECLARE(apr_xml_doc*) nlsml_doc_load(const apt_str_t *data, apr_pool_t *pool) @@ -26,21 +29,25 @@ APT_DECLARE(apr_xml_doc*) nlsml_doc_load(const apt_str_t *data, apr_pool_t *pool /* create XML parser */ parser = apr_xml_parser_create(pool); if(apr_xml_parser_feed(parser,data->buf,data->length) != APR_SUCCESS) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to feed NLSML input to the parser"); return NULL; } /* done with XML tree creation */ if(apr_xml_parser_done(parser,&doc) != APR_SUCCESS) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to terminate NLSML parsing"); return NULL; } if(!doc || !doc->root) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No NLSML root element"); return NULL; } root = doc->root; /* NLSML validity check: root element must be */ if(strcmp(root->name,"result") != 0) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unexpected NLSML root element <%s>",root->name); return NULL; } diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_obj_list.c b/libs/unimrcp/libs/apr-toolkit/src/apt_obj_list.c index a1d320a8aa..69f006adee 100644 --- a/libs/unimrcp/libs/apr-toolkit/src/apt_obj_list.c +++ b/libs/unimrcp/libs/apr-toolkit/src/apt_obj_list.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: apt_obj_list.c 1708 2010-05-24 17:03:25Z achaloyan $ */ #ifdef WIN32 @@ -65,7 +67,7 @@ APT_DECLARE(void*) apt_list_pop_front(apt_obj_list_t *list) return elem->obj; } -APT_DECLARE(void*) apt_list_head(apt_obj_list_t *list) +APT_DECLARE(void*) apt_list_head(const apt_obj_list_t *list) { apt_list_elem_t *elem; if(APR_RING_EMPTY(&list->head,apt_list_elem_t,link)) { @@ -75,7 +77,7 @@ APT_DECLARE(void*) apt_list_head(apt_obj_list_t *list) return elem->obj; } -APT_DECLARE(void*) apt_obj_list_tail(apt_obj_list_t *list) +APT_DECLARE(void*) apt_obj_list_tail(const apt_obj_list_t *list) { apt_list_elem_t *elem; if(APR_RING_EMPTY(&list->head,apt_list_elem_t,link)) { @@ -85,7 +87,7 @@ APT_DECLARE(void*) apt_obj_list_tail(apt_obj_list_t *list) return elem->obj; } -APT_DECLARE(apt_list_elem_t*) apt_list_first_elem_get(apt_obj_list_t *list) +APT_DECLARE(apt_list_elem_t*) apt_list_first_elem_get(const apt_obj_list_t *list) { if(APR_RING_EMPTY(&list->head,apt_list_elem_t,link)) { return NULL; @@ -93,7 +95,7 @@ APT_DECLARE(apt_list_elem_t*) apt_list_first_elem_get(apt_obj_list_t *list) return APR_RING_FIRST(&list->head); } -APT_DECLARE(apt_list_elem_t*) apt_list_last_elem_get(apt_obj_list_t *list) +APT_DECLARE(apt_list_elem_t*) apt_list_last_elem_get(const apt_obj_list_t *list) { if(APR_RING_EMPTY(&list->head,apt_list_elem_t,link)) { return NULL; @@ -101,7 +103,7 @@ APT_DECLARE(apt_list_elem_t*) apt_list_last_elem_get(apt_obj_list_t *list) 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_DECLARE(apt_list_elem_t*) apt_list_next_elem_get(const 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)) { @@ -110,7 +112,7 @@ APT_DECLARE(apt_list_elem_t*) apt_list_next_elem_get(apt_obj_list_t *list, apt_l 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_DECLARE(apt_list_elem_t*) apt_list_prev_elem_get(const 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)) { @@ -137,7 +139,7 @@ APT_DECLARE(apt_list_elem_t*) apt_list_elem_remove(apt_obj_list_t *list, apt_lis return next_elem; } -APT_DECLARE(apt_bool_t) apt_list_is_empty(apt_obj_list_t *list) +APT_DECLARE(apt_bool_t) apt_list_is_empty(const apt_obj_list_t *list) { if(APR_RING_EMPTY(&list->head,apt_list_elem_t,link)) { return TRUE; @@ -145,7 +147,7 @@ APT_DECLARE(apt_bool_t) apt_list_is_empty(apt_obj_list_t *list) return FALSE; } -APT_DECLARE(void*) apt_list_elem_object_get(apt_list_elem_t *elem) +APT_DECLARE(void*) apt_list_elem_object_get(const 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 index 29eb60e4d9..05c05c9e7e 100644 --- a/libs/unimrcp/libs/apr-toolkit/src/apt_pair.c +++ b/libs/unimrcp/libs/apr-toolkit/src/apt_pair.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: apt_pair.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include "apt_pair.h" diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_poller_task.c b/libs/unimrcp/libs/apr-toolkit/src/apt_poller_task.c new file mode 100644 index 0000000000..99a581667b --- /dev/null +++ b/libs/unimrcp/libs/apr-toolkit/src/apt_poller_task.c @@ -0,0 +1,271 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: apt_poller_task.c 1708 2010-05-24 17:03:25Z achaloyan $ + */ + +#include "apt_poller_task.h" +#include "apt_task.h" +#include "apt_pool.h" +#include "apt_cyclic_queue.h" +#include "apt_log.h" + + +/** Poller task */ +struct apt_poller_task_t { + apr_pool_t *pool; + apt_task_t *base; + + void *obj; + apt_poll_signal_f signal_handler; + + apr_thread_mutex_t *guard; + apt_cyclic_queue_t *msg_queue; + apt_pollset_t *pollset; + apt_timer_queue_t *timer_queue; +}; + +static apt_bool_t apt_poller_task_msg_signal(apt_task_t *task, apt_task_msg_t *msg); +static apt_bool_t apt_poller_task_run(apt_task_t *task); +static apt_bool_t apt_poller_task_on_destroy(apt_task_t *task); + + +/** Create poller task */ +APT_DECLARE(apt_poller_task_t*) apt_poller_task_create( + apr_size_t max_pollset_size, + apt_poll_signal_f signal_handler, + void *obj, + apt_task_msg_pool_t *msg_pool, + apr_pool_t *pool) +{ + apt_task_vtable_t *vtable; + apt_poller_task_t *task; + + if(!signal_handler) { + return NULL; + } + + task = apr_palloc(pool,sizeof(apt_poller_task_t)); + task->pool = pool; + task->obj = obj; + task->pollset = NULL; + task->signal_handler = signal_handler; + + task->pollset = apt_pollset_create((apr_uint32_t)max_pollset_size,pool); + if(!task->pollset) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Pollset"); + return NULL; + } + + task->base = apt_task_create(task,msg_pool,pool); + if(!task->base) { + apt_pollset_destroy(task->pollset); + return NULL; + } + + vtable = apt_task_vtable_get(task->base); + if(vtable) { + vtable->run = apt_poller_task_run; + vtable->destroy = apt_poller_task_on_destroy; + vtable->signal_msg = apt_poller_task_msg_signal; + } + apt_task_auto_ready_set(task->base,FALSE); + + task->msg_queue = apt_cyclic_queue_create(CYCLIC_QUEUE_DEFAULT_SIZE); + apr_thread_mutex_create(&task->guard,APR_THREAD_MUTEX_UNNESTED,pool); + + task->timer_queue = apt_timer_queue_create(pool); + return task; +} + +/** Destroy poller task */ +APT_DECLARE(apt_bool_t) apt_poller_task_destroy(apt_poller_task_t *task) +{ + return apt_task_destroy(task->base); +} + +/** Cleanup poller task */ +APT_DECLARE(void) apt_poller_task_cleanup(apt_poller_task_t *task) +{ + if(task->pollset) { + apt_pollset_destroy(task->pollset); + task->pollset = NULL; + } + 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; + } +} + +/** Virtual destroy handler */ +static apt_bool_t apt_poller_task_on_destroy(apt_task_t *base) +{ + apt_poller_task_t *task = apt_task_object_get(base); + apt_poller_task_cleanup(task); + return TRUE; +} + + +/** Start poller task */ +APT_DECLARE(apt_bool_t) apt_poller_task_start(apt_poller_task_t *task) +{ + return apt_task_start(task->base); +} + +/** Terminate poller task */ +APT_DECLARE(apt_bool_t) apt_poller_task_terminate(apt_poller_task_t *task) +{ + return apt_task_terminate(task->base,TRUE); +} + +/** Get task */ +APT_DECLARE(apt_task_t*) apt_poller_task_base_get(const apt_poller_task_t *task) +{ + return task->base; +} + +/** Get task vtable */ +APT_DECLARE(apt_task_vtable_t*) apt_poller_task_vtable_get(apt_poller_task_t *task) +{ + return apt_task_vtable_get(task->base); +} + +/** Get external object */ +APT_DECLARE(void*) apt_poller_task_object_get(const apt_poller_task_t *task) +{ + return task->obj; +} + +/** Get pollset */ +APT_DECLARE(apt_pollset_t*) apt_poller_task_pollset_get(const apt_poller_task_t *task) +{ + return task->pollset; +} + +/** Create timer */ +APT_DECLARE(apt_timer_t*) apt_poller_task_timer_create( + apt_poller_task_t *task, + apt_timer_proc_f proc, + void *obj, + apr_pool_t *pool) +{ + return apt_timer_create(task->timer_queue,proc,obj,pool); +} + +static apt_bool_t apt_poller_task_wakeup_process(apt_poller_task_t *task) +{ + 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) { + apt_task_msg_process(task->base,msg); + } + else { + running = FALSE; + } + } + while(running == TRUE); + return TRUE; +} + +static apt_bool_t apt_poller_task_run(apt_task_t *base) +{ + apt_poller_task_t *task = apt_task_object_get(base); + apt_bool_t *running; + apr_status_t status; + apr_int32_t num; + const apr_pollfd_t *ret_pfd; + apr_interval_time_t timeout; + apr_uint32_t queue_timeout; + apr_time_t time_now, time_last = 0; + int i; + const char *task_name; + + if(!task) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Start Poller Task"); + return FALSE; + } + task_name = apt_task_name_get(task->base), + + running = apt_task_running_flag_get(task->base); + if(!running) { + return FALSE; + } + + /* explicitly indicate task is ready to process messages */ + apt_task_ready(task->base); + + while(*running) { + if(apt_timer_queue_timeout_get(task->timer_queue,&queue_timeout) == TRUE) { + timeout = queue_timeout * 1000; + time_last = apr_time_now(); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Wait for Messages [%s] timeout [%u]", + task_name, queue_timeout); + } + else { + timeout = -1; + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Wait for Messages [%s]",task_name); + } + status = apt_pollset_poll(task->pollset, timeout, &num, &ret_pfd); + if(status != APR_SUCCESS && status != APR_TIMEUP) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Poll [%s] status: %d",task_name,status); + 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 Poller Wakeup [%s]",task_name); + apt_poller_task_wakeup_process(task); + if(*running == FALSE) { + break; + } + continue; + } + + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process Signalled Descriptor [%s]",task_name); + task->signal_handler(task->obj,&ret_pfd[i]); + } + + if(timeout != -1) { + time_now = apr_time_now(); + if(time_now > time_last) { + apt_timer_queue_advance(task->timer_queue,(apr_uint32_t)((time_now - time_last)/1000)); + } + } + } + + return TRUE; +} + +static apt_bool_t apt_poller_task_msg_signal(apt_task_t *base, apt_task_msg_t *msg) +{ + apt_bool_t status; + apt_poller_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_pollset.c b/libs/unimrcp/libs/apr-toolkit/src/apt_pollset.c index 87db7f8c04..7592aff663 100644 --- a/libs/unimrcp/libs/apr-toolkit/src/apt_pollset.c +++ b/libs/unimrcp/libs/apr-toolkit/src/apt_pollset.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: apt_pollset.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_pool.c b/libs/unimrcp/libs/apr-toolkit/src/apt_pool.c index 8f75400836..8cbe247b9b 100644 --- a/libs/unimrcp/libs/apr-toolkit/src/apt_pool.c +++ b/libs/unimrcp/libs/apr-toolkit/src/apt_pool.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: apt_pool.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include "apt_pool.h" diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_string_table.c b/libs/unimrcp/libs/apr-toolkit/src/apt_string_table.c index cc0c6be73b..bc96c51c49 100644 --- a/libs/unimrcp/libs/apr-toolkit/src/apt_string_table.c +++ b/libs/unimrcp/libs/apr-toolkit/src/apt_string_table.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: apt_string_table.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_task.c b/libs/unimrcp/libs/apr-toolkit/src/apt_task.c index 9d7014d592..5ce74e137f 100644 --- a/libs/unimrcp/libs/apr-toolkit/src/apt_task.c +++ b/libs/unimrcp/libs/apr-toolkit/src/apt_task.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: apt_task.c 1696 2010-05-20 15:44:16Z achaloyan $ */ #include @@ -23,10 +25,10 @@ /** 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_START_REQUESTED, /**< start of the task has been requested, but it's not running yet */ TASK_STATE_RUNNING, /**< task is running */ - TASK_STATE_TERMINATE_REQUESTED /**< task termination is requested and is in progress */ -} apt_task_state_t; + TASK_STATE_TERMINATE_REQUESTED /**< termination of the task has been requested, but it's still running */ +} apt_task_state_e; struct apt_task_t { void *obj; /* external object associated with the task */ @@ -34,18 +36,22 @@ struct apt_task_t { 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_state_e 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 */ + apt_bool_t running; /* task is running (TRUE if even terminate has already been requested) */ apt_bool_t auto_ready; /* if TRUE, task is implicitly ready to process messages */ const char *name; /* name of the task */ }; static void* APR_THREAD_FUNC apt_task_run(apr_thread_t *thread_handle, void *data); +static APR_INLINE void apt_task_vtable_reset(apt_task_vtable_t *vtable); static apt_bool_t apt_task_terminate_request(apt_task_t *task); +static void apt_task_start_complete_raise(apt_task_t *task); +static void apt_task_terminate_complete_raise(apt_task_t *task); APT_DECLARE(apt_task_t*) apt_task_create( @@ -98,7 +104,7 @@ APT_DECLARE(apt_bool_t) apt_task_destroy(apt_task_t *task) apt_task_wait_till_complete(task); } - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Destroy %s",task->name); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Destroy Task [%s]",task->name); if(task->vtable.destroy) { task->vtable.destroy(task); } @@ -120,7 +126,7 @@ APT_DECLARE(apt_bool_t) apt_task_start(apt_task_t *task) 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); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Start Task [%s]",task->name); if(task->vtable.start) { /* raise virtual start method */ task->vtable.start(task); @@ -152,7 +158,7 @@ APT_DECLARE(apt_bool_t) apt_task_terminate(apt_task_t *task, apt_bool_t wait_til if(task->state == TASK_STATE_TERMINATE_REQUESTED) { /* raise virtual terminate method */ - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Terminate %s",task->name); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Terminate Task [%s]",task->name); if(task->vtable.terminate) { status = task->vtable.terminate(task); } @@ -180,17 +186,17 @@ 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) +APT_DECLARE(apt_task_t*) apt_task_parent_get(const apt_task_t *task) { return task->parent_task; } -APT_DECLARE(apr_pool_t*) apt_task_pool_get(apt_task_t *task) +APT_DECLARE(apr_pool_t*) apt_task_pool_get(const apt_task_t *task) { return task->pool; } -APT_DECLARE(void*) apt_task_object_get(apt_task_t *task) +APT_DECLARE(void*) apt_task_object_get(const apt_task_t *task) { return task->obj; } @@ -205,7 +211,7 @@ 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) +APT_DECLARE(const char*) apt_task_name_get(const apt_task_t *task) { return task->name; } @@ -220,6 +226,8 @@ APT_DECLARE(apt_task_msg_t*) apt_task_msg_get(apt_task_t *task) APT_DECLARE(apt_bool_t) apt_task_msg_signal(apt_task_t *task, apt_task_msg_t *msg) { + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Signal Message to [%s] [%d;%d]", + task->name, msg->type, msg->sub_type); if(task->vtable.signal_msg) { return task->vtable.signal_msg(task,msg); } @@ -238,74 +246,48 @@ APT_DECLARE(apt_bool_t) apt_task_msg_parent_signal(apt_task_t *task, apt_task_ms } -APT_DECLARE(apt_bool_t) apt_core_task_msg_process(apt_task_t *task, apt_task_msg_t *msg) +static 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: + 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); - } - } + apt_task_start_request_remove(task); break; } case CORE_TASK_MSG_TERMINATE_REQUEST: { apt_task_child_terminate(task); if(!task->pending_term) { - running = FALSE; + task->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; - } + apt_task_terminate_request_remove(task); break; } default: break; } - return running; + return TRUE; } APT_DECLARE(apt_bool_t) apt_task_msg_process(apt_task_t *task, apt_task_msg_t *msg) { - apt_bool_t running = TRUE; + apt_bool_t status = FALSE; + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process Message [%s] [%d;%d]", + task->name, msg->type, msg->sub_type); if(msg->type == TASK_MSG_CORE) { - running = apt_core_task_msg_process(task,msg); + status = apt_core_task_msg_process(task,msg); } else { if(task->vtable.process_msg) { - task->vtable.process_msg(task,msg); + status = task->vtable.process_msg(task,msg); } } apt_task_msg_release(msg); - return running; + return status; } static apt_bool_t apt_task_terminate_request(apt_task_t *task) @@ -325,6 +307,9 @@ 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; + if(task->vtable.on_start_request) { + task->vtable.on_start_request(task); + } /* walk through the list of the child tasks and start them */ while(elem) { child_task = apt_list_elem_object_get(elem); @@ -338,18 +323,7 @@ APT_DECLARE(apt_bool_t) apt_task_child_start(apt_task_t *task) 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); - } - } + apt_task_start_complete_raise(task); } return TRUE; } @@ -359,6 +333,9 @@ 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; + if(task->vtable.on_terminate_request) { + task->vtable.on_terminate_request(task); + } /* walk through the list of the child tasks and terminate them */ while(elem) { child_task = apt_list_elem_object_get(elem); @@ -380,20 +357,7 @@ APT_DECLARE(apt_bool_t) apt_task_child_terminate(apt_task_t *task) 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); - } -#ifdef ENABLE_SIMULT_TASK_TERMINATION - 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); - } - } -#endif + apt_task_terminate_complete_raise(task); } return TRUE; } @@ -414,6 +378,85 @@ APT_DECLARE(apt_bool_t) apt_task_ready(apt_task_t *task) return TRUE; } +APT_DECLARE(apt_bool_t*) apt_task_running_flag_get(apt_task_t *task) +{ + return &task->running; +} + +APT_DECLARE(apt_bool_t) apt_task_start_request_add(apt_task_t *task) +{ + task->pending_start++; + return TRUE; +} + +APT_DECLARE(apt_bool_t) apt_task_start_request_remove(apt_task_t *task) +{ + if(!task->pending_start) { + /* error case, no pending start */ + return FALSE; + } + task->pending_start--; + if(!task->pending_start) { + apt_task_start_complete_raise(task); + } + return TRUE; +} + +APT_DECLARE(apt_bool_t) apt_task_terminate_request_add(apt_task_t *task) +{ + task->pending_term++; + return TRUE; +} + +APT_DECLARE(apt_bool_t) apt_task_terminate_request_remove(apt_task_t *task) +{ + if(!task->pending_term) { + /* error case, no pending terminate */ + return FALSE; + } + task->pending_term--; + if(!task->pending_term) { + apt_task_terminate_complete_raise(task); + task->running = FALSE; + } + return TRUE; +} + +static void apt_task_start_complete_raise(apt_task_t *task) +{ + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Task Started [%s]",task->name); + 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); + } + } +} + +static void apt_task_terminate_complete_raise(apt_task_t *task) +{ + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Task Terminated [%s]",task->name); + if(task->vtable.on_terminate_complete) { + task->vtable.on_terminate_complete(task); + } +#ifdef ENABLE_SIMULT_TASK_TERMINATION + 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); + } + } +#endif +} static void* APR_THREAD_FUNC apt_task_run(apr_thread_t *thread_handle, void *data) { @@ -425,6 +468,7 @@ static void* APR_THREAD_FUNC apt_task_run(apr_thread_t *thread_handle, void *dat } apr_thread_mutex_lock(task->data_guard); task->state = TASK_STATE_RUNNING; + task->running = TRUE; apr_thread_mutex_unlock(task->data_guard); if(task->auto_ready == TRUE) { @@ -439,6 +483,7 @@ static void* APR_THREAD_FUNC apt_task_run(apr_thread_t *thread_handle, void *dat apr_thread_mutex_lock(task->data_guard); task->state = TASK_STATE_IDLE; + task->running = FALSE; apr_thread_mutex_unlock(task->data_guard); /* raise post-run event */ if(task->vtable.on_post_run) { @@ -448,3 +493,19 @@ static void* APR_THREAD_FUNC apt_task_run(apr_thread_t *thread_handle, void *dat apr_thread_exit(thread_handle,APR_SUCCESS); return NULL; } + +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_request = NULL; + vtable->on_start_complete = NULL; + vtable->on_terminate_request = NULL; + vtable->on_terminate_complete = 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 index fdff519fb1..bb64cea6ef 100644 --- a/libs/unimrcp/libs/apr-toolkit/src/apt_task_msg.c +++ b/libs/unimrcp/libs/apr-toolkit/src/apt_task_msg.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: apt_task_msg.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_test_suite.c b/libs/unimrcp/libs/apr-toolkit/src/apt_test_suite.c index 6a5d18ad7d..afaf29f0ce 100644 --- a/libs/unimrcp/libs/apr-toolkit/src/apt_test_suite.c +++ b/libs/unimrcp/libs/apr-toolkit/src/apt_test_suite.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: apt_test_suite.c 1708 2010-05-24 17:03:25Z achaloyan $ */ #include "apt_pool.h" @@ -61,7 +63,7 @@ APT_DECLARE(apt_bool_t) apt_test_framework_suite_add(apt_test_framework_t *frame 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) +APT_DECLARE(apr_pool_t*) apt_test_framework_pool_get(const apt_test_framework_t *framework) { return framework->pool; } diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_text_message.c b/libs/unimrcp/libs/apr-toolkit/src/apt_text_message.c new file mode 100644 index 0000000000..1e0d901b43 --- /dev/null +++ b/libs/unimrcp/libs/apr-toolkit/src/apt_text_message.c @@ -0,0 +1,448 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: apt_text_message.c 1671 2010-04-28 19:50:29Z achaloyan $ + */ + +#include "apt_text_message.h" +#include "apt_log.h" + +/** Stage of text message processing (parsing/generation) */ +typedef enum { + APT_MESSAGE_STAGE_START_LINE, + APT_MESSAGE_STAGE_HEADER, + APT_MESSAGE_STAGE_BODY +} apt_message_stage_e; + + +/** Text message parser */ +struct apt_message_parser_t { + const apt_message_parser_vtable_t *vtable; + void *obj; + apr_pool_t *pool; + apt_message_context_t context; + apr_size_t content_length; + apt_message_stage_e stage; + apt_bool_t skip_lf; + apt_bool_t verbose; +}; + +/** Text message generator */ +struct apt_message_generator_t { + const apt_message_generator_vtable_t *vtable; + void *obj; + apr_pool_t *pool; + apt_message_context_t context; + apr_size_t content_length; + apt_message_stage_e stage; + apt_bool_t verbose; +}; + +/** Parse individual header field (name-value pair) */ +APT_DECLARE(apt_header_field_t*) apt_header_field_parse(apt_text_stream_t *stream, apr_pool_t *pool) +{ + apr_size_t folding_length = 0; + apr_array_header_t *folded_lines = NULL; + apt_header_field_t *header_field; + apt_str_t *line; + apt_pair_t pair; + /* read name-value pair */ + if(apt_text_header_read(stream,&pair) == FALSE) { + return NULL; + } + + /* check folding lines (value spanning multiple lines) */ + while(stream->pos < stream->end) { + if(apt_text_is_wsp(*stream->pos) == FALSE) { + break; + } + + stream->pos++; + + /* skip further white spaces (if any) */ + apt_text_white_spaces_skip(stream); + + if(!folded_lines) { + folded_lines = apr_array_make(pool,1,sizeof(apt_str_t)); + } + line = apr_array_push(folded_lines); + apt_text_line_read(stream,line); + folding_length += line->length; + }; + + header_field = apt_header_field_alloc(pool); + /* copy parsed name of the header field */ + header_field->name.length = pair.name.length; + header_field->name.buf = apr_palloc(pool, pair.name.length + 1); + if(pair.name.length) { + memcpy(header_field->name.buf, pair.name.buf, pair.name.length); + } + header_field->name.buf[header_field->name.length] = '\0'; + + /* copy parsed value of the header field */ + header_field->value.length = pair.value.length + folding_length; + header_field->value.buf = apr_palloc(pool, header_field->value.length + 1); + if(pair.value.length) { + memcpy(header_field->value.buf, pair.value.buf, pair.value.length); + } + + if(folding_length) { + int i; + char *pos = header_field->value.buf + pair.value.length; + /* copy parsed folding lines */ + for(i=0; inelts; i++) { + line = &APR_ARRAY_IDX(folded_lines,i,apt_str_t); + + memcpy(pos,line->buf,line->length); + pos += line->length; + } + } + header_field->value.buf[header_field->value.length] = '\0'; + + return header_field; +} + +/** Generate individual header field (name-value pair) */ +APT_DECLARE(apt_bool_t) apt_header_field_generate(const apt_header_field_t *header_field, apt_text_stream_t *stream) +{ + return apt_text_name_value_insert(stream,&header_field->name,&header_field->value); +} + +/** Parse header section */ +APT_DECLARE(apt_bool_t) apt_header_section_parse(apt_header_section_t *header, apt_text_stream_t *stream, apr_pool_t *pool) +{ + apt_header_field_t *header_field; + apt_bool_t result = FALSE; + + do { + header_field = apt_header_field_parse(stream,pool); + if(header_field) { + if(apt_string_is_empty(&header_field->name) == FALSE) { + /* normal header */ + apt_header_section_field_add(header,header_field); + } + else { + /* empty header => exit */ + result = TRUE; + break; + } + } + else { + /* malformed header => skip to the next one */ + } + } + while(apt_text_is_eos(stream) == FALSE); + + return result; +} + +/** Generate header section */ +APT_DECLARE(apt_bool_t) apt_header_section_generate(const apt_header_section_t *header, apt_text_stream_t *stream) +{ + apt_header_field_t *header_field; + for(header_field = APR_RING_FIRST(&header->ring); + header_field != APR_RING_SENTINEL(&header->ring, apt_header_field_t, link); + header_field = APR_RING_NEXT(header_field, link)) { + apt_header_field_generate(header_field,stream); + } + + return apt_text_eol_insert(stream); +} + +static apt_bool_t apt_message_body_read(apt_message_parser_t *parser, apt_text_stream_t *stream) +{ + apt_bool_t status = TRUE; + apt_str_t *body = parser->context.body; + if(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 = parser->content_length - body->length; + if(required_length > stream_length) { + required_length = stream_length; + /* incomplete */ + status = FALSE; + } + memcpy(body->buf + body->length, stream->pos, required_length); + body->length += required_length; + stream->pos += required_length; + if(parser->verbose == TRUE) { + apr_size_t length = required_length; + const char *masked_data = apt_log_data_mask(stream->pos,&length,parser->pool); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Parsed Message Body [%"APR_SIZE_T_FMT" bytes]\n%.*s", + required_length, length, masked_data); + } + } + + return status; +} + +static apt_bool_t apt_message_body_write(apt_message_generator_t *generator, apt_text_stream_t *stream) +{ + apt_bool_t status = TRUE; + apt_str_t *body = generator->context.body; + if(body && body->length < generator->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 = generator->content_length - body->length; + if(required_length > stream_length) { + required_length = stream_length; + /* incomplete */ + status = FALSE; + } + + memcpy(stream->pos, body->buf + body->length, required_length); + + if(generator->verbose == TRUE) { + apr_size_t length = required_length; + const char *masked_data = apt_log_data_mask(stream->pos,&length,generator->pool); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Generated Message Body [%"APR_SIZE_T_FMT" bytes]\n%.*s", + required_length, length, masked_data); + } + + body->length += required_length; + stream->pos += required_length; + } + + return status; +} + + +/** Create message parser */ +APT_DECLARE(apt_message_parser_t*) apt_message_parser_create(void *obj, const apt_message_parser_vtable_t *vtable, apr_pool_t *pool) +{ + apt_message_parser_t *parser = apr_palloc(pool,sizeof(apt_message_parser_t)); + parser->obj = obj; + parser->vtable = vtable; + parser->pool = pool; + parser->context.message = NULL; + parser->context.body = NULL; + parser->context.header = NULL; + parser->content_length = 0; + parser->stage = APT_MESSAGE_STAGE_START_LINE; + parser->skip_lf = FALSE; + parser->verbose = FALSE; + return parser; +} + +static APR_INLINE void apt_crlf_segmentation_test(apt_message_parser_t *parser, apt_text_stream_t *stream) +{ + /* in the worst case message segmentation may occur between and */ + if(stream->pos == stream->end && *(stream->pos-1)== APT_TOKEN_CR) { + /* if this is the case be prepared to skip with the next attempt */ + parser->skip_lf = TRUE; + } +} + +/** Parse message by raising corresponding event handlers */ +APT_DECLARE(apt_message_status_e) apt_message_parser_run(apt_message_parser_t *parser, apt_text_stream_t *stream, void **message) +{ + const char *pos; + apt_message_status_e status = APT_MESSAGE_STATUS_INCOMPLETE; + if(parser->skip_lf == TRUE) { + /* skip occurred as a result of message segmentation between and */ + apt_text_char_skip(stream,APT_TOKEN_LF); + parser->skip_lf = FALSE; + } + if(message) { + *message = NULL; + } + + do { + pos = stream->pos; + if(parser->stage == APT_MESSAGE_STAGE_START_LINE) { + if(parser->vtable->on_start(parser,&parser->context,stream,parser->pool) == FALSE) { + if(apt_text_is_eos(stream) == FALSE) { + status = APT_MESSAGE_STATUS_INVALID; + } + break; + } + + apt_crlf_segmentation_test(parser,stream); + + parser->stage = APT_MESSAGE_STAGE_HEADER; + } + + if(parser->stage == APT_MESSAGE_STAGE_HEADER) { + /* read header section */ + apt_bool_t res = apt_header_section_parse(parser->context.header,stream,parser->pool); + if(parser->verbose == TRUE) { + apr_size_t length = stream->pos - pos; + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Parsed Message Header [%"APR_SIZE_T_FMT" bytes]\n%.*s", + length, length, pos); + } + + apt_crlf_segmentation_test(parser,stream); + + if(res == FALSE) { + break; + } + + if(parser->vtable->on_header_complete) { + if(parser->vtable->on_header_complete(parser,&parser->context) == FALSE) { + status = APT_MESSAGE_STATUS_INVALID; + break; + } + } + + if(parser->context.body && parser->context.body->length) { + apt_str_t *body = parser->context.body; + parser->content_length = body->length; + body->buf = apr_palloc(parser->pool,parser->content_length+1); + body->buf[parser->content_length] = '\0'; + body->length = 0; + parser->stage = APT_MESSAGE_STAGE_BODY; + } + else { + status = APT_MESSAGE_STATUS_COMPLETE; + if(message) { + *message = parser->context.message; + } + parser->stage = APT_MESSAGE_STAGE_START_LINE; + break; + } + } + + if(parser->stage == APT_MESSAGE_STAGE_BODY) { + if(apt_message_body_read(parser,stream) == FALSE) { + break; + } + + if(parser->vtable->on_body_complete) { + parser->vtable->on_body_complete(parser,&parser->context); + } + status = APT_MESSAGE_STATUS_COMPLETE; + if(message) { + *message = parser->context.message; + } + parser->stage = APT_MESSAGE_STAGE_START_LINE; + break; + } + } + while(apt_text_is_eos(stream) == FALSE); + + return status; +} + +/** Get external object associated with parser */ +APT_DECLARE(void*) apt_message_parser_object_get(apt_message_parser_t *parser) +{ + return parser->obj; +} + +/** Set verbose mode for the parser */ +APT_DECLARE(void) apt_message_parser_verbose_set(apt_message_parser_t *parser, apt_bool_t verbose) +{ + parser->verbose = verbose; +} + + +/** Create message generator */ +APT_DECLARE(apt_message_generator_t*) apt_message_generator_create(void *obj, const apt_message_generator_vtable_t *vtable, apr_pool_t *pool) +{ + apt_message_generator_t *generator = apr_palloc(pool,sizeof(apt_message_generator_t)); + generator->obj = obj; + generator->vtable = vtable; + generator->pool = pool; + generator->context.message = NULL; + generator->context.header = NULL; + generator->context.body = NULL; + generator->content_length = 0; + generator->stage = APT_MESSAGE_STAGE_START_LINE; + generator->verbose = FALSE; + return generator; +} + +static apt_message_status_e apt_message_generator_break(apt_message_generator_t *generator, apt_text_stream_t *stream) +{ + /* failed to generate message */ + if(apt_text_is_eos(stream) == TRUE) { + /* end of stream reached */ + return APT_MESSAGE_STATUS_INCOMPLETE; + } + + /* error case */ + return APT_MESSAGE_STATUS_INVALID; +} + +/** Generate message */ +APT_DECLARE(apt_message_status_e) apt_message_generator_run(apt_message_generator_t *generator, void *message, apt_text_stream_t *stream) +{ + if(!message) { + return APT_MESSAGE_STATUS_INVALID; + } + + if(message != generator->context.message) { + generator->stage = APT_MESSAGE_STAGE_START_LINE; + generator->context.message = message; + generator->context.header = NULL; + generator->context.body = NULL; + } + + if(generator->stage == APT_MESSAGE_STAGE_START_LINE) { + /* generate start-line */ + if(generator->vtable->on_start(generator,&generator->context,stream) == FALSE) { + return apt_message_generator_break(generator,stream); + } + + if(!generator->context.header || !generator->context.body) { + return APT_MESSAGE_STATUS_INVALID; + } + + /* generate header */ + if(apt_header_section_generate(generator->context.header,stream) == FALSE) { + return apt_message_generator_break(generator,stream); + } + + if(generator->vtable->on_header_complete) { + generator->vtable->on_header_complete(generator,&generator->context,stream); + } + if(generator->verbose == TRUE) { + apr_size_t length = stream->pos - stream->text.buf; + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Generated Message Header [%"APR_SIZE_T_FMT" bytes]\n%.*s", + length, length, stream->text.buf); + } + + generator->stage = APT_MESSAGE_STAGE_START_LINE; + generator->content_length = generator->context.body->length; + if(generator->content_length) { + generator->context.body->length = 0; + generator->stage = APT_MESSAGE_STAGE_BODY; + } + } + + if(generator->stage == APT_MESSAGE_STAGE_BODY) { + if(apt_message_body_write(generator,stream) == FALSE) { + return apt_message_generator_break(generator,stream); + } + + generator->stage = APT_MESSAGE_STAGE_START_LINE; + } + + return APT_MESSAGE_STATUS_COMPLETE; +} + +/** Get external object associated with generator */ +APT_DECLARE(void*) apt_message_generator_object_get(apt_message_generator_t *generator) +{ + return generator->obj; +} + +/** Set verbose mode for the parser */ +APT_DECLARE(void) apt_message_generator_verbose_set(apt_message_generator_t *generator, apt_bool_t verbose) +{ + generator->verbose = verbose; +} diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_text_stream.c b/libs/unimrcp/libs/apr-toolkit/src/apt_text_stream.c index 5617dff6fa..a15bbdb3cf 100644 --- a/libs/unimrcp/libs/apr-toolkit/src/apt_text_stream.c +++ b/libs/unimrcp/libs/apr-toolkit/src/apt_text_stream.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: apt_text_stream.c 1793 2011-01-10 21:46:14Z achaloyan $ */ #include @@ -61,19 +63,20 @@ APT_DECLARE(apt_bool_t) apt_text_line_read(apt_text_stream_t *stream, apt_str_t else { /* end of stream is reached, do not advance stream pos, but set is_eos flag */ stream->is_eos = TRUE; + line->length = pos - line->buf; } return status; } -/** Navigate through the headers (name:value pairs) of the text stream (message) - Valid headers are: +/** To be used to navigate through the header fields (name:value pairs) of the text stream (message) + Valid header fields are: name:value name: value name: value name: value name: (only name, no value) (empty header) - Malformed headers are: + Malformed header fields are: name:value (missing end of line ) name (missing separator ':') */ @@ -109,8 +112,8 @@ APT_DECLARE(apt_bool_t) apt_text_header_read(apt_text_stream_t *stream, apt_pair break; } else if(!pair->name.length) { - /* skip initial spaces and read name */ - if(!pair->name.buf && *pos != APT_TOKEN_SP) { + /* skip preceding white spaces (SHOULD NOT be any WSP, though) and read name */ + if(!pair->name.buf && apt_text_is_wsp(*pos) == FALSE) { pair->name.buf = pos; } if(*pos == ':') { @@ -119,8 +122,8 @@ APT_DECLARE(apt_bool_t) apt_text_header_read(apt_text_stream_t *stream, apt_pair } } else if(!pair->value.length) { - /* skip initial spaces and read value */ - if(!pair->value.buf && *pos != APT_TOKEN_SP) { + /* skip preceding white spaces and read value */ + if(!pair->value.buf && apt_text_is_wsp(*pos) == FALSE) { pair->value.buf = pos; } } @@ -170,14 +173,19 @@ APT_DECLARE(apt_bool_t) apt_text_field_read(apt_text_stream_t *stream, char sepa /** 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) { + if(stream->pos == stream->end) { + stream->pos = stream->text.buf; + } + else { + 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; - return FALSE; + stream->text.length = remaining_length; } - 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; } @@ -216,14 +224,36 @@ APT_DECLARE(apt_bool_t) apt_id_resource_generate(const apt_str_t *id, const apt_ 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) +/** Generate name-value pair line */ +APT_DECLARE(apt_bool_t) apt_text_name_value_insert(apt_text_stream_t *stream, const apt_str_t *name, const apt_str_t *value) { char *pos = stream->pos; + if(pos + name->length + value->length + 2 >= stream->end) { + return FALSE; + } + memcpy(pos,name->buf,name->length); + pos += name->length; + *pos++ = ':'; + *pos++ = APT_TOKEN_SP; + if(apt_string_is_empty(value) == FALSE) { + memcpy(pos,value->buf,value->length); + pos += value->length; + } + stream->pos = pos; + return apt_text_eol_insert(stream); +} + +/** Generate only the name ("name":) of the header field */ +APT_DECLARE(apt_bool_t) apt_text_header_name_insert(apt_text_stream_t *stream, const apt_str_t *name) +{ + char *pos = stream->pos; + if(pos + name->length + 2 >= stream->end) { + return FALSE; + } memcpy(pos,name->buf,name->length); pos += name->length; *pos++ = ':'; - *pos++ = ' '; + *pos++ = APT_TOKEN_SP; stream->pos = pos; return TRUE; } @@ -269,7 +299,21 @@ APT_DECLARE(apt_bool_t) apt_pair_array_parse(apt_pair_arr_t *arr, const apt_str_ } /** 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) +APT_DECLARE(apt_bool_t) apt_pair_array_generate(const apt_pair_arr_t *arr, apt_str_t *str, apr_pool_t *pool) +{ + char buf[512]; + apt_text_stream_t stream; + apt_text_stream_init(&stream,buf,sizeof(buf)); + if(apt_text_pair_array_insert(&stream,arr) == FALSE) { + return FALSE; + } + apt_string_assign_n(str, stream.text.buf, stream.pos - stream.text.buf, pool); + return TRUE; +} + + +/** Insert array of name-value pairs */ +APT_DECLARE(apt_bool_t) apt_text_pair_array_insert(apt_text_stream_t *stream, const apt_pair_arr_t *arr) { int i; apt_pair_t *pair; @@ -314,30 +358,61 @@ APT_DECLARE(apt_bool_t) apt_boolean_value_parse(const apt_str_t *str, apt_bool_t return FALSE; } +/** Generate apr_size_t value from pool (buffer is allocated from pool) */ +APT_DECLARE(apt_bool_t) apt_boolean_value_generate(apt_bool_t value, apt_str_t *str, apr_pool_t *pool) +{ + if(value == TRUE) { + str->length = TOKEN_TRUE_LENGTH; + str->buf = apr_palloc(pool,str->length); + memcpy(str->buf,TOKEN_TRUE,str->length); + } + else { + str->length = TOKEN_FALSE_LENGTH; + str->buf = apr_palloc(pool,str->length); + memcpy(str->buf,TOKEN_FALSE,str->length); + } + return TRUE; +} + /** Generate boolean-value */ -APT_DECLARE(apt_bool_t) apt_boolean_value_generate(apt_bool_t value, apt_text_stream_t *stream) +APT_DECLARE(apt_bool_t) apt_boolean_value_insert(apt_text_stream_t *stream, apt_bool_t value) { if(value == TRUE) { + if(stream->pos + TOKEN_TRUE_LENGTH >= stream->end) { + return FALSE; + } memcpy(stream->pos,TOKEN_TRUE,TOKEN_TRUE_LENGTH); stream->pos += TOKEN_TRUE_LENGTH; } else { + if(stream->pos + TOKEN_FALSE_LENGTH >= stream->end) { + return FALSE; + } memcpy(stream->pos,TOKEN_FALSE,TOKEN_FALSE_LENGTH); stream->pos += TOKEN_FALSE_LENGTH; } return TRUE; } + /** Parse size_t value */ APT_DECLARE(apr_size_t) apt_size_value_parse(const apt_str_t *str) { return str->buf ? atol(str->buf) : 0; } -/** Generate apr_size_t value */ -APT_DECLARE(apt_bool_t) apt_size_value_generate(apr_size_t value, apt_text_stream_t *stream) +/** Generate apr_size_t value (buffer is allocated from pool) */ +APT_DECLARE(apt_bool_t) apt_size_value_generate(apr_size_t value, apt_str_t *str, apr_pool_t *pool) { - int length = sprintf(stream->pos, "%"APR_SIZE_T_FMT, value); + str->buf = apr_psprintf(pool, "%"APR_SIZE_T_FMT, value); + str->length = strlen(str->buf); + return TRUE; +} + +/** Insert apr_size_t value */ +APT_DECLARE(apt_bool_t) apt_text_size_value_insert(apt_text_stream_t *stream, apr_size_t value) +{ + int length = apr_snprintf(stream->pos, stream->end - stream->pos, "%"APR_SIZE_T_FMT, value); if(length <= 0) { return FALSE; } @@ -345,29 +420,58 @@ APT_DECLARE(apt_bool_t) apt_size_value_generate(apr_size_t value, apt_text_strea return TRUE; } + /** Parse float value */ APT_DECLARE(float) apt_float_value_parse(const apt_str_t *str) { return str->buf ? (float)atof(str->buf) : 0; } +/** Generate float value (buffer is allocated from pool) */ +APT_DECLARE(apt_bool_t) apt_float_value_generate(float value, apt_str_t *str, apr_pool_t *pool) +{ + char *end; + str->buf = apr_psprintf(pool,"%f",value); + str->length = strlen(str->buf); + + /* remove trailing 0s (if any) */ + end = str->buf + str->length - 1; + while(*end == 0x30 && end != str->buf && *(end - 1) != '.') end--; + + str->length = end - str->buf + 1; + return TRUE; +} + /** Generate float value */ -APT_DECLARE(apt_bool_t) apt_float_value_generate(float value, apt_text_stream_t *stream) +APT_DECLARE(apt_bool_t) apt_text_float_value_insert(apt_text_stream_t *stream, float value) { char *end; - int length = sprintf(stream->pos,"%f",value); + int length = apr_snprintf(stream->pos, stream->end - stream->pos, "%f", value); if(length <= 0) { return FALSE; } /* remove trailing 0s (if any) */ end = stream->pos + length - 1; - while(*end == 0x30 && end != stream->pos) end--; + while(*end == 0x30 && end != stream->pos && *(end - 1) != '.') end--; stream->pos = end + 1; return TRUE; } +/** Insert string value */ +APT_DECLARE(apt_bool_t) apt_text_string_insert(apt_text_stream_t *stream, const apt_str_t *str) +{ + if(stream->pos + str->length >= stream->end) { + return FALSE; + } + if(str->length) { + memcpy(stream->pos,str->buf,str->length); + stream->pos += str->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) { @@ -405,6 +509,25 @@ APT_DECLARE(apt_bool_t) apt_var_length_value_generate(apr_size_t *value, apr_siz return TRUE; } +/** Generate completion-cause */ +APT_DECLARE(apt_bool_t) apt_completion_cause_generate(const apt_str_table_item_t table[], apr_size_t size, apr_size_t cause, apt_str_t *str, apr_pool_t *pool) +{ + char buf[256]; + int length; + const apt_str_t *name = apt_string_table_str_get(table,size,cause); + if(!name) { + return FALSE; + } + length = sprintf(buf,"%03"APR_SIZE_T_FMT" ",cause); + if(length <= 0) { + return FALSE; + } + + memcpy(buf+length,name->buf,name->length); + apt_string_assign_n(str,buf,name->length + length,pool); + 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) diff --git a/libs/unimrcp/libs/apr-toolkit/src/apt_timer_queue.c b/libs/unimrcp/libs/apr-toolkit/src/apt_timer_queue.c new file mode 100644 index 0000000000..8d1b007b8c --- /dev/null +++ b/libs/unimrcp/libs/apr-toolkit/src/apt_timer_queue.c @@ -0,0 +1,211 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: apt_timer_queue.c 1665 2010-04-25 05:03:26Z achaloyan $ + */ + +#ifdef WIN32 +#pragma warning(disable: 4127) +#endif +#include +#include "apt_timer_queue.h" +#include "apt_log.h" + +/** Timer queue */ +struct apt_timer_queue_t { + /** Ring head */ + APR_RING_HEAD(apt_timer_head_t, apt_timer_t) head; + + /** Elapsed time */ + apr_uint32_t elapsed_time; +}; + +/** Timer */ +struct apt_timer_t { + /** Ring entry */ + APR_RING_ENTRY(apt_timer_t) link; + + /** Back pointer to queue */ + apt_timer_queue_t *queue; + /** Time next report is scheduled at */ + apr_uint32_t scheduled_time; + + /** Timer proc */ + apt_timer_proc_f proc; + /** Timer object */ + void *obj; +}; + +static void apt_timers_reschedule(apt_timer_queue_t *timer_queue); + +/** Create timer queue */ +APT_DECLARE(apt_timer_queue_t*) apt_timer_queue_create(apr_pool_t *pool) +{ + apt_timer_queue_t *timer_queue = apr_palloc(pool,sizeof(apt_timer_queue_t)); + APR_RING_INIT(&timer_queue->head, apt_timer_t, link); + timer_queue->elapsed_time = 0; + return timer_queue; +} + +/** Destroy timer queue */ +APT_DECLARE(void) apt_timer_queue_destroy(apt_timer_queue_t *timer_queue) +{ +} + +/** Advance scheduled timers */ +APT_DECLARE(void) apt_timer_queue_advance(apt_timer_queue_t *timer_queue, apr_uint32_t elapsed_time) +{ + apt_timer_t *timer; + + if(APR_RING_EMPTY(&timer_queue->head, apt_timer_t, link)) { + /* just return, nothing to do */ + return; + } + + /* increment elapsed time */ + timer_queue->elapsed_time += elapsed_time; + if(timer_queue->elapsed_time >= 0xFFFF) { + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Reschedule Timers [%u]",timer_queue->elapsed_time); + apt_timers_reschedule(timer_queue); + } + + /* process timers */ + do { + /* get first node (timer) */ + timer = APR_RING_FIRST(&timer_queue->head); + + if(timer->scheduled_time > timer_queue->elapsed_time) { + /* scheduled time is not elapsed yet */ + break; + } + + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Timer Elapsed 0x%x [%u]",timer,timer->scheduled_time); + /* remove the elapsed timer from the list */ + APR_RING_REMOVE(timer, link); + timer->scheduled_time = 0; + /* process the elapsed timer */ + timer->proc(timer,timer->obj); + } + while(!APR_RING_EMPTY(&timer_queue->head, apt_timer_t, link)); +} + +/** Is timer queue empty */ +APT_DECLARE(apt_bool_t) apt_timer_queue_is_empty(const apt_timer_queue_t *timer_queue) +{ + return APR_RING_EMPTY(&timer_queue->head, apt_timer_t, link) ? TRUE : FALSE; +} + +/** Get current timeout */ +APT_DECLARE(apt_bool_t) apt_timer_queue_timeout_get(const apt_timer_queue_t *timer_queue, apr_uint32_t *timeout) +{ + apt_timer_t *timer; + /* is queue empty */ + if(APR_RING_EMPTY(&timer_queue->head, apt_timer_t, link)) { + return FALSE; + } + + /* get first node (timer) */ + timer = APR_RING_FIRST(&timer_queue->head); + if(!timer) { + return FALSE; + } + + *timeout = timer->scheduled_time - timer_queue->elapsed_time; + return TRUE; +} + + +/** Create timer */ +APT_DECLARE(apt_timer_t*) apt_timer_create(apt_timer_queue_t *timer_queue, apt_timer_proc_f proc, void *obj, apr_pool_t *pool) +{ + apt_timer_t *timer = apr_palloc(pool,sizeof(apt_timer_t)); + timer->queue = timer_queue; + timer->scheduled_time = 0; + timer->proc = proc; + timer->obj = obj; + return timer; +} + +static APR_INLINE apt_bool_t apt_timer_insert(apt_timer_queue_t *timer_queue, apt_timer_t *timer) +{ + apt_timer_t *it; + for(it = APR_RING_LAST(&timer_queue->head); + it != APR_RING_SENTINEL(&timer_queue->head, apt_timer_t, link); + it = APR_RING_PREV(it, link)) { + + if(it->scheduled_time <= timer->scheduled_time) { + APR_RING_INSERT_AFTER(it,timer,link); + return TRUE; + } + } + APR_RING_INSERT_HEAD(&timer_queue->head,timer,apt_timer_t,link); + return TRUE; +} + +/** Set one-shot timer */ +APT_DECLARE(apt_bool_t) apt_timer_set(apt_timer_t *timer, apr_uint32_t timeout) + +{ + apt_timer_queue_t *queue = timer->queue; + + if(timeout <= 0 || !timer->proc) { + return FALSE; + } + + /* calculate time to elapse */ + timer->scheduled_time = queue->elapsed_time + timeout; + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Set Timer 0x%x [%u]",timer,timer->scheduled_time); + + if(APR_RING_EMPTY(&queue->head, apt_timer_t, link)) { + APR_RING_INSERT_TAIL(&queue->head,timer,apt_timer_t,link); + return TRUE; + } + + /* insert new node (timer) to sorted by scheduled time list */ + return apt_timer_insert(queue,timer); +} + +/** Kill timer */ +APT_DECLARE(apt_bool_t) apt_timer_kill(apt_timer_t *timer) +{ + apt_timer_queue_t *queue = timer->queue; + + if(!timer->scheduled_time) { + return FALSE; + } + + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Kill Timer 0x%x [%u]",timer,timer->scheduled_time); + /* remove node (timer) from the list */ + APR_RING_REMOVE(timer,link); + timer->scheduled_time = 0; + + if(APR_RING_EMPTY(&queue->head, apt_timer_t, link)) { + /* reset elapsed time if no timers set */ + queue->elapsed_time = 0; + } + return TRUE; +} + +static void apt_timers_reschedule(apt_timer_queue_t *queue) +{ + apt_timer_t *it; + for(it = APR_RING_LAST(&queue->head); + it != APR_RING_SENTINEL(&queue->head, apt_timer_t, link); + it = APR_RING_PREV(it, link)) { + + it->scheduled_time -= queue->elapsed_time; + } + queue->elapsed_time = 0; +} diff --git a/libs/unimrcp/libs/mpf/Makefile.am b/libs/unimrcp/libs/mpf/Makefile.am index d153905278..0e904a46ed 100644 --- a/libs/unimrcp/libs/mpf/Makefile.am +++ b/libs/unimrcp/libs/mpf/Makefile.am @@ -35,7 +35,6 @@ include_HEADERS = codecs/g711/g711.h \ include/mpf_rtp_termination_factory.h \ include/mpf_file_termination_factory.h \ include/mpf_scheduler.h \ - include/mpf_timer_manager.h \ include/mpf_types.h \ include/mpf_encoder.h \ include/mpf_decoder.h \ @@ -72,7 +71,6 @@ libmpf_la_SOURCES = codecs/g711/g711.c \ src/mpf_file_termination_factory.c \ src/mpf_frame_buffer.c \ src/mpf_scheduler.c \ - src/mpf_timer_manager.c \ src/mpf_encoder.c \ src/mpf_decoder.c \ src/mpf_jitter_buffer.c \ diff --git a/libs/unimrcp/libs/mpf/include/mpf.h b/libs/unimrcp/libs/mpf/include/mpf.h index 7edc0da71b..66fbc37460 100644 --- a/libs/unimrcp/libs/mpf/include/mpf.h +++ b/libs/unimrcp/libs/mpf/include/mpf.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_H__ -#define __MPF_H__ +#ifndef MPF_H +#define MPF_H /** * @file mpf.h @@ -39,4 +41,4 @@ #define MPF_DECLARE(type) type #endif -#endif /*__MPF_H__*/ +#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 index 1b90b558d5..3bb17f64f9 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_activity_detector.h +++ b/libs/unimrcp/libs/mpf/include/mpf_activity_detector.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_activity_detector.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_ACTIVITY_DETECTOR_H__ -#define __MPF_ACTIVITY_DETECTOR_H__ +#ifndef MPF_ACTIVITY_DETECTOR_H +#define MPF_ACTIVITY_DETECTOR_H /** * @file mpf_activity_detector.h @@ -63,4 +65,4 @@ MPF_DECLARE(mpf_detector_event_e) mpf_activity_detector_process(mpf_activity_det APT_END_EXTERN_C -#endif /*__MPF_ACTIVITY_DETECTOR_H__*/ +#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 index 0d9c439c4c..df1aa1fbcb 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_audio_file_descriptor.h +++ b/libs/unimrcp/libs/mpf/include/mpf_audio_file_descriptor.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_audio_file_descriptor.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_AUDIO_FILE_DESCRIPTOR_H__ -#define __MPF_AUDIO_FILE_DESCRIPTOR_H__ +#ifndef MPF_AUDIO_FILE_DESCRIPTOR_H +#define MPF_AUDIO_FILE_DESCRIPTOR_H /** * @file mpf_audio_file_descriptor.h @@ -51,4 +53,4 @@ struct mpf_audio_file_descriptor_t { APT_END_EXTERN_C -#endif /*__MPF_AUDIO_FILE_DESCRIPTOR_H__*/ +#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 index f117fbfbb6..0f936baddd 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_audio_file_stream.h +++ b/libs/unimrcp/libs/mpf/include/mpf_audio_file_stream.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_audio_file_stream.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_AUDIO_FILE_STREAM_H__ -#define __MPF_AUDIO_FILE_STREAM_H__ +#ifndef MPF_AUDIO_FILE_STREAM_H +#define MPF_AUDIO_FILE_STREAM_H /** * @file mpf_audio_file_stream.h @@ -43,4 +45,4 @@ MPF_DECLARE(apt_bool_t) mpf_file_stream_modify(mpf_audio_stream_t *stream, mpf_a APT_END_EXTERN_C -#endif /*__MPF_AUDIO_FILE_STREAM_H__*/ +#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 index 395aaa966a..3988e0bf3e 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_bridge.h +++ b/libs/unimrcp/libs/mpf/include/mpf_bridge.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_bridge.h 1693 2010-05-16 18:33:07Z achaloyan $ */ -#ifndef __MPF_BRIDGE_H__ -#define __MPF_BRIDGE_H__ +#ifndef MPF_BRIDGE_H +#define MPF_BRIDGE_H /** * @file mpf_bridge.h @@ -31,15 +33,17 @@ APT_BEGIN_EXTERN_C * @param source the source audio stream * @param sink the sink audio stream * @param codec_manager the codec manager + * @param name the informative name used for debugging * @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, const mpf_codec_manager_t *codec_manager, + const char *name, apr_pool_t *pool); APT_END_EXTERN_C -#endif /*__MPF_BRIDGE_H__*/ +#endif /* MPF_BRIDGE_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_buffer.h b/libs/unimrcp/libs/mpf/include/mpf_buffer.h index 6dd22f3f42..ee0cc0121c 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_buffer.h +++ b/libs/unimrcp/libs/mpf/include/mpf_buffer.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_buffer.h 1709 2010-05-24 17:12:11Z achaloyan $ */ -#ifndef __MPF_BUFFER_H__ -#define __MPF_BUFFER_H__ +#ifndef MPF_BUFFER_H +#define MPF_BUFFER_H /** * @file mpf_buffer.h @@ -49,8 +51,8 @@ apt_bool_t mpf_buffer_event_write(mpf_buffer_t *buffer, mpf_frame_type_e event_t 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); +apr_size_t mpf_buffer_get_size(const mpf_buffer_t *buffer); APT_END_EXTERN_C -#endif /*__MPF_BUFFER_H__*/ +#endif /* MPF_BUFFER_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_codec.h b/libs/unimrcp/libs/mpf/include/mpf_codec.h index 04d9b27079..817e1540ce 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_codec.h +++ b/libs/unimrcp/libs/mpf/include/mpf_codec.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_codec.h 1686 2010-05-08 18:46:08Z achaloyan $ */ -#ifndef __MPF_CODEC_H__ -#define __MPF_CODEC_H__ +#ifndef MPF_CODEC_H +#define MPF_CODEC_H /** * @file mpf_codec.h @@ -55,6 +57,9 @@ struct mpf_codec_vtable_t { /** Virtual dissect method */ apt_bool_t (*dissect)(mpf_codec_t *codec, void **buffer, apr_size_t *size, mpf_codec_frame_t *frame); + + /** Virtual initialize method */ + apt_bool_t (*initialize)(mpf_codec_t *codec, mpf_codec_frame_t *frame_out); }; /** @@ -154,6 +159,19 @@ static APR_INLINE apt_bool_t mpf_codec_dissect(mpf_codec_t *codec, void **buffer return rv; } +/** Initialize (fill) codec frame with silence */ +static APR_INLINE apt_bool_t mpf_codec_initialize(mpf_codec_t *codec, mpf_codec_frame_t *frame_out) +{ + apt_bool_t rv = TRUE; + if(codec->vtable->initialize) { + rv = codec->vtable->initialize(codec,frame_out); + } + else { + memset(frame_out->buffer,0,frame_out->size); + } + return rv; +} + APT_END_EXTERN_C -#endif /*__MPF_CODEC_H__*/ +#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 index 9f3a6ea1d7..4958cada57 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_codec_descriptor.h +++ b/libs/unimrcp/libs/mpf/include/mpf_codec_descriptor.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_codec_descriptor.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_CODEC_DESCRIPTOR_H__ -#define __MPF_CODEC_DESCRIPTOR_H__ +#ifndef MPF_CODEC_DESCRIPTOR_H +#define MPF_CODEC_DESCRIPTOR_H /** * @file mpf_codec_descriptor.h @@ -278,4 +280,4 @@ MPF_DECLARE(int) mpf_sample_rate_mask_get(apr_uint16_t sampling_rate); APT_END_EXTERN_C -#endif /*__MPF_CODEC_DESCRIPTOR_H__*/ +#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 index 2b14070b52..44aaf2cfca 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_codec_manager.h +++ b/libs/unimrcp/libs/mpf/include/mpf_codec_manager.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_codec_manager.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_CODEC_MANAGER_H__ -#define __MPF_CODEC_MANAGER_H__ +#ifndef MPF_CODEC_MANAGER_H +#define MPF_CODEC_MANAGER_H /** * @file mpf_codec_manager.h @@ -50,4 +52,4 @@ MPF_DECLARE(const mpf_codec_t*) mpf_codec_manager_codec_find(const mpf_codec_man APT_END_EXTERN_C -#endif /*__MPF_CODEC_MANAGER_H__*/ +#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 index d9a20bf9ad..9190970a39 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_context.h +++ b/libs/unimrcp/libs/mpf/include/mpf_context.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_context.h 1709 2010-05-24 17:12:11Z achaloyan $ */ -#ifndef __MPF_CONTEXT_H__ -#define __MPF_CONTEXT_H__ +#ifndef MPF_CONTEXT_H +#define MPF_CONTEXT_H /** * @file mpf_context.h @@ -47,12 +49,14 @@ MPF_DECLARE(apt_bool_t) mpf_context_factory_process(mpf_context_factory_t *facto /** * Create MPF context. * @param factory the factory context belongs to + * @param name the informative name of the 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( mpf_context_factory_t *factory, + const char *name, void *obj, apr_size_t max_termination_count, apr_pool_t *pool); @@ -67,7 +71,7 @@ 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); +MPF_DECLARE(void*) mpf_context_object_get(const mpf_context_t *context); /** * Add termination to context. @@ -126,4 +130,4 @@ MPF_DECLARE(apt_bool_t) mpf_context_process(mpf_context_t *context); APT_END_EXTERN_C -#endif /*__MPF_CONTEXT_H__*/ +#endif /* MPF_CONTEXT_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_decoder.h b/libs/unimrcp/libs/mpf/include/mpf_decoder.h index ea99db8ad1..25402de6db 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_decoder.h +++ b/libs/unimrcp/libs/mpf/include/mpf_decoder.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_decoder.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_DECODER_H__ -#define __MPF_DECODER_H__ +#ifndef MPF_DECODER_H +#define MPF_DECODER_H /** * @file mpf_decoder.h @@ -37,4 +39,4 @@ MPF_DECLARE(mpf_audio_stream_t*) mpf_decoder_create(mpf_audio_stream_t *source, APT_END_EXTERN_C -#endif /*__MPF_ENCODER_H__*/ +#endif /* MPF_ENCODER_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_dtmf_detector.h b/libs/unimrcp/libs/mpf/include/mpf_dtmf_detector.h index 6c6d95768d..4108e3bd9b 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_dtmf_detector.h +++ b/libs/unimrcp/libs/mpf/include/mpf_dtmf_detector.h @@ -1,5 +1,5 @@ /* - * Copyright 2009 Tomas Valenta, Arsen Chaloyan + * Copyright 2009-2010 Tomas Valenta, Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,12 +12,14 @@ * 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. + * + * $Id: mpf_dtmf_detector.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_DTMF_DETECTOR_H__ -#define __MPF_DTMF_DETECTOR_H__ +#ifndef MPF_DTMF_DETECTOR_H +#define MPF_DTMF_DETECTOR_H -/* +/** * @file mpf_dtmf_detector.h * @brief DTMF detector * @@ -118,4 +120,4 @@ MPF_DECLARE(void) mpf_dtmf_detector_destroy(struct mpf_dtmf_detector_t *detector APT_END_EXTERN_C -#endif /*__MPF_DTMF_DETECTOR_H__*/ +#endif /* MPF_DTMF_DETECTOR_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_dtmf_generator.h b/libs/unimrcp/libs/mpf/include/mpf_dtmf_generator.h index 21953c2b5a..ea28bba432 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_dtmf_generator.h +++ b/libs/unimrcp/libs/mpf/include/mpf_dtmf_generator.h @@ -1,5 +1,5 @@ /* - * Copyright 2009 Tomas Valenta, Arsen Chaloyan + * Copyright 2009-2010 Tomas Valenta, Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,11 +14,11 @@ * limitations under the License. */ -#ifndef __MPF_DTMF_GENERATOR_H__ -#define __MPF_DTMF_GENERATOR_H__ +#ifndef MPF_DTMF_GENERATOR_H +#define MPF_DTMF_GENERATOR_H -/* - * @file mpf_named_event.h +/** + * @file mpf_dtmf_generator.h * @brief DTMF generator * * Generator used to send DTMF tones. Capable to send digits @@ -128,4 +128,4 @@ MPF_DECLARE(void) mpf_dtmf_generator_destroy(struct mpf_dtmf_generator_t *genera APT_END_EXTERN_C -#endif /*__MPF_DTMF_GENERATOR_H__*/ +#endif /* MPF_DTMF_GENERATOR_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_encoder.h b/libs/unimrcp/libs/mpf/include/mpf_encoder.h index 529f9a0b7e..5ef8366393 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_encoder.h +++ b/libs/unimrcp/libs/mpf/include/mpf_encoder.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_encoder.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_ENCODER_H__ -#define __MPF_ENCODER_H__ +#ifndef MPF_ENCODER_H +#define MPF_ENCODER_H /** * @file mpf_encoder.h @@ -37,4 +39,4 @@ MPF_DECLARE(mpf_audio_stream_t*) mpf_encoder_create(mpf_audio_stream_t *sink, mp APT_END_EXTERN_C -#endif /*__MPF_ENCODER_H__*/ +#endif /* MPF_ENCODER_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_engine.h b/libs/unimrcp/libs/mpf/include/mpf_engine.h index 149de69ce4..0810c70700 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_engine.h +++ b/libs/unimrcp/libs/mpf/include/mpf_engine.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_engine.h 1709 2010-05-24 17:12:11Z achaloyan $ */ -#ifndef __MPF_ENGINE_H__ -#define __MPF_ENGINE_H__ +#ifndef MPF_ENGINE_H +#define MPF_ENGINE_H /** * @file mpf_engine.h @@ -32,9 +34,10 @@ typedef apt_task_msg_t mpf_task_msg_t; /** * Create MPF engine. + * @param id the identifier of the engine * @param pool the pool to allocate memory from */ -MPF_DECLARE(mpf_engine_t*) mpf_engine_create(apr_pool_t *pool); +MPF_DECLARE(mpf_engine_t*) mpf_engine_create(const char *id, apr_pool_t *pool); /** * Create MPF codec manager. @@ -52,12 +55,14 @@ MPF_DECLARE(apt_bool_t) mpf_engine_codec_manager_register(mpf_engine_t *engine, /** * Create MPF context. * @param engine the engine to create context for + * @param name the informative name of the 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_engine_context_create( - mpf_engine_t *engine, + mpf_engine_t *engine, + const char *name, void *obj, apr_size_t max_termination_count, apr_pool_t *pool); @@ -72,13 +77,13 @@ MPF_DECLARE(apt_bool_t) mpf_engine_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_engine_context_object_get(mpf_context_t *context); +MPF_DECLARE(void*) mpf_engine_context_object_get(const mpf_context_t *context); /** * Get task. * @param engine the engine to get task from */ -MPF_DECLARE(apt_task_t*) mpf_task_get(mpf_engine_t *engine); +MPF_DECLARE(apt_task_t*) mpf_task_get(const mpf_engine_t *engine); /** * Set task msg type to send responses and events with. @@ -148,7 +153,13 @@ MPF_DECLARE(apt_bool_t) mpf_engine_message_send(mpf_engine_t *engine, mpf_task_m */ MPF_DECLARE(apt_bool_t) mpf_engine_scheduler_rate_set(mpf_engine_t *engine, unsigned long rate); +/** + * Get the identifier of the engine . + * @param engine the engine to get name of + */ +MPF_DECLARE(const char*) mpf_engine_id_get(const mpf_engine_t *engine); + APT_END_EXTERN_C -#endif /*__MPF_ENGINE_H__*/ +#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 index df8a05abd7..de5bc30686 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_file_termination_factory.h +++ b/libs/unimrcp/libs/mpf/include/mpf_file_termination_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_file_termination_factory.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_FILE_TERMINATION_FACTORY_H__ -#define __MPF_FILE_TERMINATION_FACTORY_H__ +#ifndef MPF_FILE_TERMINATION_FACTORY_H +#define MPF_FILE_TERMINATION_FACTORY_H /** * @file mpf_file_termination_factory.h @@ -34,4 +36,4 @@ MPF_DECLARE(mpf_termination_factory_t*) mpf_file_termination_factory_create(apr_ APT_END_EXTERN_C -#endif /*__MPF_RTP_TERMINATION_FACTORY_H__*/ +#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 index c5b45a6e61..f490f8b9ba 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_frame.h +++ b/libs/unimrcp/libs/mpf/include/mpf_frame.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_frame.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_FRAME_H__ -#define __MPF_FRAME_H__ +#ifndef MPF_FRAME_H +#define MPF_FRAME_H /** * @file mpf_frame.h @@ -61,4 +63,4 @@ struct mpf_frame_t { APT_END_EXTERN_C -#endif /*__MPF_FRAME_H__*/ +#endif /* MPF_FRAME_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_frame_buffer.h b/libs/unimrcp/libs/mpf/include/mpf_frame_buffer.h index 8573963c6f..97d48d3dcb 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_frame_buffer.h +++ b/libs/unimrcp/libs/mpf/include/mpf_frame_buffer.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_frame_buffer.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_FRAME_BUFFER_H__ -#define __MPF_FRAME_BUFFER_H__ +#ifndef MPF_FRAME_BUFFER_H +#define MPF_FRAME_BUFFER_H /** * @file mpf_frame_buffer.h @@ -47,4 +49,4 @@ apt_bool_t mpf_frame_buffer_read(mpf_frame_buffer_t *buffer, mpf_frame_t *frame) APT_END_EXTERN_C -#endif /*__MPF_FRAME_BUFFER_H__*/ +#endif /* MPF_FRAME_BUFFER_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_jitter_buffer.h b/libs/unimrcp/libs/mpf/include/mpf_jitter_buffer.h index a4cb4c8ba2..5bf142df43 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_jitter_buffer.h +++ b/libs/unimrcp/libs/mpf/include/mpf_jitter_buffer.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_jitter_buffer.h 1802 2011-05-13 02:43:12Z achaloyan $ */ -#ifndef __MPF_JITTER_BUFFER_H__ -#define __MPF_JITTER_BUFFER_H__ +#ifndef MPF_JITTER_BUFFER_H +#define MPF_JITTER_BUFFER_H /** * @file mpf_jitter_buffer.h @@ -50,7 +52,7 @@ void mpf_jitter_buffer_destroy(mpf_jitter_buffer_t *jb); 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, void *buffer, apr_size_t size, apr_uint32_t ts); +jb_result_t mpf_jitter_buffer_write(mpf_jitter_buffer_t *jb, void *buffer, apr_size_t size, apr_uint32_t ts, apr_byte_t marker); /** Write named event to jitter buffer */ jb_result_t mpf_jitter_buffer_event_write(mpf_jitter_buffer_t *jb, const mpf_named_event_frame_t *named_event, apr_uint32_t ts, apr_byte_t marker); @@ -60,4 +62,4 @@ apt_bool_t mpf_jitter_buffer_read(mpf_jitter_buffer_t *jb, mpf_frame_t *media_fr APT_END_EXTERN_C -#endif /*__MPF_JITTER_BUFFER_H__*/ +#endif /* MPF_JITTER_BUFFER_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_message.h b/libs/unimrcp/libs/mpf/include/mpf_message.h index 601b306a9e..95f4092df7 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_message.h +++ b/libs/unimrcp/libs/mpf/include/mpf_message.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_message.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_MESSAGE_H__ -#define __MPF_MESSAGE_H__ +#ifndef MPF_MESSAGE_H +#define MPF_MESSAGE_H /** * @file mpf_message.h @@ -89,4 +91,4 @@ struct mpf_message_container_t { APT_END_EXTERN_C -#endif /*__MPF_MESSAGE_H__*/ +#endif /* MPF_MESSAGE_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_mixer.h b/libs/unimrcp/libs/mpf/include/mpf_mixer.h index fa48f5b9a9..a552634aa8 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_mixer.h +++ b/libs/unimrcp/libs/mpf/include/mpf_mixer.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_mixer.h 1693 2010-05-16 18:33:07Z achaloyan $ */ -#ifndef __MPF_MIXER_H__ -#define __MPF_MIXER_H__ +#ifndef MPF_MIXER_H +#define MPF_MIXER_H /** * @file mpf_mixer.h @@ -32,6 +34,7 @@ APT_BEGIN_EXTERN_C * @param source_count the number of audio sources * @param sink the audio sink * @param codec_manager the codec manager + * @param name the informative name used for debugging * @param pool the pool to allocate memory from */ MPF_DECLARE(mpf_object_t*) mpf_mixer_create( @@ -39,9 +42,10 @@ MPF_DECLARE(mpf_object_t*) mpf_mixer_create( apr_size_t source_count, mpf_audio_stream_t *sink, const mpf_codec_manager_t *codec_manager, + const char *name, apr_pool_t *pool); APT_END_EXTERN_C -#endif /*__MPF_MIXER_H__*/ +#endif /* MPF_MIXER_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_multiplier.h b/libs/unimrcp/libs/mpf/include/mpf_multiplier.h index 380d5b5f16..6e27e8b037 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_multiplier.h +++ b/libs/unimrcp/libs/mpf/include/mpf_multiplier.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_multiplier.h 1693 2010-05-16 18:33:07Z achaloyan $ */ -#ifndef __MPF_MULTIPLIER_H__ -#define __MPF_MULTIPLIER_H__ +#ifndef MPF_MULTIPLIER_H +#define MPF_MULTIPLIER_H /** * @file mpf_multiplier.h @@ -32,6 +34,7 @@ APT_BEGIN_EXTERN_C * @param sink_arr the array of audio sinks * @param sink_count the number of audio sinks * @param codec_manager the codec manager + * @param name the informative name used for debugging * @param pool the pool to allocate memory from */ MPF_DECLARE(mpf_object_t*) mpf_multiplier_create( @@ -39,9 +42,10 @@ MPF_DECLARE(mpf_object_t*) mpf_multiplier_create( mpf_audio_stream_t **sink_arr, apr_size_t sink_count, const mpf_codec_manager_t *codec_manager, + const char *name, apr_pool_t *pool); APT_END_EXTERN_C -#endif /*__MPF_MULTIPLIER_H__*/ +#endif /* MPF_MULTIPLIER_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_named_event.h b/libs/unimrcp/libs/mpf/include/mpf_named_event.h index d8d4dc6750..1e4f04fdab 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_named_event.h +++ b/libs/unimrcp/libs/mpf/include/mpf_named_event.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_named_event.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_NAMED_EVENT_H__ -#define __MPF_NAMED_EVENT_H__ +#ifndef MPF_NAMED_EVENT_H +#define MPF_NAMED_EVENT_H /** * @file mpf_named_event.h @@ -68,4 +70,4 @@ MPF_DECLARE(char) mpf_event_id_to_dtmf_char(const apr_uint32_t event_id); APT_END_EXTERN_C -#endif /*__MPF_NAMED_EVENT_H__*/ +#endif /* MPF_NAMED_EVENT_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_object.h b/libs/unimrcp/libs/mpf/include/mpf_object.h index 8e3e4eee95..cc48f4f879 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_object.h +++ b/libs/unimrcp/libs/mpf/include/mpf_object.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_object.h 1693 2010-05-16 18:33:07Z achaloyan $ */ -#ifndef __MPF_OBJECT_H__ -#define __MPF_OBJECT_H__ +#ifndef MPF_OBJECT_H +#define MPF_OBJECT_H /** * @file mpf_object.h @@ -31,6 +33,8 @@ typedef struct mpf_object_t mpf_object_t; /** Media processing objects base */ struct mpf_object_t { + /** Informative name used for debugging */ + const char *name; /** Virtual destroy */ apt_bool_t (*destroy)(mpf_object_t *object); /** Virtual process */ @@ -40,8 +44,9 @@ struct mpf_object_t { }; /** Initialize object */ -static APR_INLINE void mpf_object_init(mpf_object_t *object) +static APR_INLINE void mpf_object_init(mpf_object_t *object, const char *name) { + object->name = name; object->destroy = NULL; object->process = NULL; object->trace = NULL; @@ -71,4 +76,4 @@ static APR_INLINE void mpf_object_trace(mpf_object_t *object) APT_END_EXTERN_C -#endif /*__MPF_OBJECT_H__*/ +#endif /* MPF_OBJECT_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_resampler.h b/libs/unimrcp/libs/mpf/include/mpf_resampler.h index d674336139..eeac10aaee 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_resampler.h +++ b/libs/unimrcp/libs/mpf/include/mpf_resampler.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_resampler.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_RESAMPLER_H__ -#define __MPF_RESAMPLER_H__ +#ifndef MPF_RESAMPLER_H +#define MPF_RESAMPLER_H /** * @file mpf_resampler.h @@ -37,4 +39,4 @@ MPF_DECLARE(mpf_audio_stream_t*) mpf_resampler_create(mpf_audio_stream_t *source APT_END_EXTERN_C -#endif /*__MPF_RESAMPLER_H__*/ +#endif /* MPF_RESAMPLER_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_rtcp_packet.h b/libs/unimrcp/libs/mpf/include/mpf_rtcp_packet.h index 6773807fcd..ba65d3f695 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_rtcp_packet.h +++ b/libs/unimrcp/libs/mpf/include/mpf_rtcp_packet.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_rtcp_packet.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_RTCP_PACKET_H__ -#define __MPF_RTCP_PACKET_H__ +#ifndef MPF_RTCP_PACKET_H +#define MPF_RTCP_PACKET_H /** * @file mpf_rtcp_packet.h @@ -198,4 +200,4 @@ static APR_INLINE void rtcp_rr_ntoh(rtcp_rr_stat_t *rr_stat) APT_END_EXTERN_C -#endif /*__MPF_RTCP_PACKET_H__*/ +#endif /* MPF_RTCP_PACKET_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_rtp_attribs.h b/libs/unimrcp/libs/mpf/include/mpf_rtp_attribs.h index dbce6b706f..c5212d78e8 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_rtp_attribs.h +++ b/libs/unimrcp/libs/mpf/include/mpf_rtp_attribs.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_rtp_attribs.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_RTP_ATTRIBS_H__ -#define __MPF_RTP_ATTRIBS_H__ +#ifndef MPF_RTP_ATTRIBS_H +#define MPF_RTP_ATTRIBS_H /** * @file mpf_rtp_attribs.h @@ -51,4 +53,4 @@ MPF_DECLARE(const apt_str_t*) mpf_rtp_direction_str_get(mpf_stream_direction_e d APT_END_EXTERN_C -#endif /*__MPF_RTP_ATTRIBS_H__*/ +#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 index 883a1f5896..7d488db3ee 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_rtp_defs.h +++ b/libs/unimrcp/libs/mpf/include/mpf_rtp_defs.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_rtp_defs.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_RTP_DEFS_H__ -#define __MPF_RTP_DEFS_H__ +#ifndef MPF_RTP_DEFS_H +#define MPF_RTP_DEFS_H /** * @file mpf_rtp_defs.h @@ -178,4 +180,4 @@ static APR_INLINE void rtp_transmitter_init(rtp_transmitter_t *transmitter) APT_END_EXTERN_C -#endif /*__MPF_RTP_DEFS_H__*/ +#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 index 906a3c339c..8412c8fc2a 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_rtp_descriptor.h +++ b/libs/unimrcp/libs/mpf/include/mpf_rtp_descriptor.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_rtp_descriptor.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_RTP_DESCRIPTOR_H__ -#define __MPF_RTP_DESCRIPTOR_H__ +#ifndef MPF_RTP_DESCRIPTOR_H +#define MPF_RTP_DESCRIPTOR_H /** * @file mpf_rtp_descriptor.h @@ -36,6 +38,8 @@ typedef struct mpf_rtp_stream_descriptor_t mpf_rtp_stream_descriptor_t; 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; +/** RTP settings declaration */ +typedef struct mpf_rtp_settings_t mpf_rtp_settings_t; /** Jitter buffer configuration declaration */ typedef struct mpf_jb_config_t mpf_jb_config_t; @@ -75,6 +79,8 @@ struct mpf_rtp_stream_descriptor_t { mpf_rtp_media_descriptor_t *local; /** Remote media descriptor */ mpf_rtp_media_descriptor_t *remote; + /** Settings loaded from config */ + mpf_rtp_settings_t *settings; }; /** RTP termination descriptor */ @@ -104,7 +110,7 @@ typedef enum { RTCP_BYE_PER_TALKSPURT /**< transmit RTCP BYE at the end of each talkspurt (input) */ } rtcp_bye_policy_e; -/** RTP config */ +/** RTP factory config */ struct mpf_rtp_config_t { /** Local IP address to bind to */ apt_str_t ip; @@ -116,6 +122,10 @@ struct mpf_rtp_config_t { apr_port_t rtp_port_max; /** Current RTP port */ apr_port_t rtp_port_cur; +}; + +/** RTP settings */ +struct mpf_rtp_settings_t { /** Packetization time */ apr_uint16_t ptime; /** Codec list */ @@ -172,8 +182,8 @@ static APR_INLINE void mpf_jb_config_init(mpf_jb_config_t *jb_config) 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) +/** Allocate RTP config */ +static APR_INLINE mpf_rtp_config_t* mpf_rtp_config_alloc(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); @@ -181,18 +191,25 @@ static APR_INLINE mpf_rtp_config_t* mpf_rtp_config_create(apr_pool_t *pool) 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; - rtp_config->rtcp = FALSE; - rtp_config->rtcp_bye_policy = RTCP_BYE_DISABLE; - rtp_config->rtcp_tx_interval = 0; - rtp_config->rtcp_rx_resolution = 0; - mpf_jb_config_init(&rtp_config->jb_config); - return rtp_config; } +/** Allocate RTP settings */ +static APR_INLINE mpf_rtp_settings_t* mpf_rtp_settings_alloc(apr_pool_t *pool) +{ + mpf_rtp_settings_t *rtp_settings = (mpf_rtp_settings_t*)apr_palloc(pool,sizeof(mpf_rtp_settings_t)); + rtp_settings->ptime = 0; + mpf_codec_list_init(&rtp_settings->codec_list,0,pool); + rtp_settings->own_preferrence = FALSE; + rtp_settings->rtcp = FALSE; + rtp_settings->rtcp_bye_policy = RTCP_BYE_DISABLE; + rtp_settings->rtcp_tx_interval = 0; + rtp_settings->rtcp_rx_resolution = 0; + mpf_jb_config_init(&rtp_settings->jb_config); + return rtp_settings; +} + + APT_END_EXTERN_C -#endif /*__MPF_RTP_DESCRIPTOR_H__*/ +#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 index 398d844dce..a122cb6cc7 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_rtp_header.h +++ b/libs/unimrcp/libs/mpf/include/mpf_rtp_header.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_rtp_header.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_RTP_HEADER_H__ -#define __MPF_RTP_HEADER_H__ +#ifndef MPF_RTP_HEADER_H +#define MPF_RTP_HEADER_H /** * @file mpf_rtp_header.h @@ -83,4 +85,4 @@ struct rtp_extension_header_t { APT_END_EXTERN_C -#endif /*__MPF_RTP_HEADER_H__*/ +#endif /* MPF_RTP_HEADER_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_rtp_pt.h b/libs/unimrcp/libs/mpf/include/mpf_rtp_pt.h index 27114c5e6e..27f88f1c7c 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_rtp_pt.h +++ b/libs/unimrcp/libs/mpf/include/mpf_rtp_pt.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_rtp_pt.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_RTP_PT_H__ -#define __MPF_RTP_PT_H__ +#ifndef MPF_RTP_PT_H +#define MPF_RTP_PT_H /** * @file mpf_rtp_pt.h @@ -41,4 +43,4 @@ typedef enum { APT_END_EXTERN_C -#endif /*__MPF_RTP_PT_H__*/ +#endif /* MPF_RTP_PT_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_rtp_stat.h b/libs/unimrcp/libs/mpf/include/mpf_rtp_stat.h index 2d492ebf4f..e97b58c826 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_rtp_stat.h +++ b/libs/unimrcp/libs/mpf/include/mpf_rtp_stat.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_rtp_stat.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_RTP_STAT_H__ -#define __MPF_RTP_STAT_H__ +#ifndef MPF_RTP_STAT_H +#define MPF_RTP_STAT_H /** * @file mpf_rtp_stat.h @@ -110,4 +112,4 @@ static APR_INLINE void mpf_rtp_rx_stat_reset(rtp_rx_stat_t *rx_stat) APT_END_EXTERN_C -#endif /*__MPF_RTP_STAT_H__*/ +#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 index 803ab34577..76ef8963a5 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_rtp_stream.h +++ b/libs/unimrcp/libs/mpf/include/mpf_rtp_stream.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_rtp_stream.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_RTP_STREAM_H__ -#define __MPF_RTP_STREAM_H__ +#ifndef MPF_RTP_STREAM_H +#define MPF_RTP_STREAM_H /** * @file mpf_rtp_stream.h @@ -30,10 +32,11 @@ APT_BEGIN_EXTERN_C /** * Create RTP stream. * @param termination the back pointer to hold - * @param config the configuration to use + * @param config the configuration of RTP factory + * @param settings the settings 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); +MPF_DECLARE(mpf_audio_stream_t*) mpf_rtp_stream_create(mpf_termination_t *termination, mpf_rtp_config_t *config, mpf_rtp_settings_t *settings, apr_pool_t *pool); /** * Add/enable RTP stream. @@ -56,4 +59,4 @@ MPF_DECLARE(apt_bool_t) mpf_rtp_stream_modify(mpf_audio_stream_t *stream, mpf_rt APT_END_EXTERN_C -#endif /*__MPF_RTP_STREAM_H__*/ +#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 index f881c445af..d34ffcbc3d 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_rtp_termination_factory.h +++ b/libs/unimrcp/libs/mpf/include/mpf_rtp_termination_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_rtp_termination_factory.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_RTP_TERMINATION_FACTORY_H__ -#define __MPF_RTP_TERMINATION_FACTORY_H__ +#ifndef MPF_RTP_TERMINATION_FACTORY_H +#define MPF_RTP_TERMINATION_FACTORY_H /** * @file mpf_rtp_termination_factory.h @@ -37,4 +39,4 @@ MPF_DECLARE(mpf_termination_factory_t*) mpf_rtp_termination_factory_create( APT_END_EXTERN_C -#endif /*__MPF_RTP_TERMINATION_FACTORY_H__*/ +#endif /* MPF_RTP_TERMINATION_FACTORY_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_scheduler.h b/libs/unimrcp/libs/mpf/include/mpf_scheduler.h index 6617511fe7..1e83091b8e 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_scheduler.h +++ b/libs/unimrcp/libs/mpf/include/mpf_scheduler.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_scheduler.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_SCHEDULER_H__ -#define __MPF_SCHEDULER_H__ +#ifndef MPF_SCHEDULER_H +#define MPF_SCHEDULER_H /** * @file mpf_scheduler.h @@ -63,4 +65,4 @@ MPF_DECLARE(apt_bool_t) mpf_scheduler_stop(mpf_scheduler_t *scheduler); APT_END_EXTERN_C -#endif /*__MPF_SCHEDULER_H__*/ +#endif /* MPF_SCHEDULER_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_stream.h b/libs/unimrcp/libs/mpf/include/mpf_stream.h index 4decae5235..93676b7eb0 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_stream.h +++ b/libs/unimrcp/libs/mpf/include/mpf_stream.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_stream.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_STREAM_H__ -#define __MPF_STREAM_H__ +#ifndef MPF_STREAM_H +#define MPF_STREAM_H /** * @file mpf_stream.h @@ -166,4 +168,4 @@ MPF_DECLARE(void) mpf_audio_stream_trace(mpf_audio_stream_t *stream, mpf_stream_ APT_END_EXTERN_C -#endif /*__MPF_STREAM_H__*/ +#endif /* MPF_STREAM_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_stream_descriptor.h b/libs/unimrcp/libs/mpf/include/mpf_stream_descriptor.h index 86b56b1b73..fbdeb5b068 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_stream_descriptor.h +++ b/libs/unimrcp/libs/mpf/include/mpf_stream_descriptor.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_stream_descriptor.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MPF_STREAM_DESCRIPTOR_H__ -#define __MPF_STREAM_DESCRIPTOR_H__ +#ifndef MPF_STREAM_DESCRIPTOR_H +#define MPF_STREAM_DESCRIPTOR_H /** * @file mpf_stream_descriptor.h @@ -85,4 +87,4 @@ static APR_INLINE mpf_stream_direction_e mpf_stream_reverse_direction_get(mpf_st APT_END_EXTERN_C -#endif /*__MPF_STREAM_DESCRIPTOR_H__*/ +#endif /* MPF_STREAM_DESCRIPTOR_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_termination.h b/libs/unimrcp/libs/mpf/include/mpf_termination.h index 06ede3bfd8..8444f2edff 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_termination.h +++ b/libs/unimrcp/libs/mpf/include/mpf_termination.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_termination.h 1693 2010-05-16 18:33:07Z achaloyan $ */ -#ifndef __MPF_TERMINATION_H__ -#define __MPF_TERMINATION_H__ +#ifndef MPF_TERMINATION_H +#define MPF_TERMINATION_H /** * @file mpf_termination.h @@ -23,6 +25,7 @@ */ #include "mpf_types.h" +#include "apt_timer_queue.h" APT_BEGIN_EXTERN_C @@ -50,6 +53,8 @@ struct mpf_termination_vtable_t { struct mpf_termination_t { /** Pool to allocate memory from */ apr_pool_t *pool; + /** Informative name used for debugging */ + const char *name; /** External object */ void *obj; /** Object to send events to */ @@ -58,8 +63,8 @@ struct mpf_termination_t { mpf_termination_event_handler_f event_handler; /** Codec manager */ const mpf_codec_manager_t *codec_manager; - /** Timer manager */ - mpf_timer_manager_t *timer_manager; + /** Timer queue */ + apt_timer_queue_t *timer_queue; /** Termination factory entire termination created by */ mpf_termination_factory_t *termination_factory; /** Table of virtual methods */ @@ -113,4 +118,4 @@ MPF_DECLARE(apt_bool_t) mpf_termination_subtract(mpf_termination_t *termination) APT_END_EXTERN_C -#endif /*__MPF_TERMINATION_H__*/ +#endif /* MPF_TERMINATION_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_termination_factory.h b/libs/unimrcp/libs/mpf/include/mpf_termination_factory.h index 564518657a..973044b888 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_termination_factory.h +++ b/libs/unimrcp/libs/mpf/include/mpf_termination_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_termination_factory.h 1693 2010-05-16 18:33:07Z achaloyan $ */ -#ifndef __MPF_TERMINATION_FACTORY_H__ -#define __MPF_TERMINATION_FACTORY_H__ +#ifndef MPF_TERMINATION_FACTORY_H +#define MPF_TERMINATION_FACTORY_H /** * @file mpf_termination_factory.h @@ -64,25 +66,31 @@ MPF_DECLARE(mpf_termination_t*) mpf_raw_termination_create( */ MPF_DECLARE(apt_bool_t) mpf_termination_destroy(mpf_termination_t *termination); +/** + * Get termination name. + * @param termination the termination to get name of + */ +MPF_DECLARE(const char*) mpf_termination_name_get(const 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); +MPF_DECLARE(void*) mpf_termination_object_get(const mpf_termination_t *termination); /** * Get audio stream. * @param termination the termination to get audio stream from */ -MPF_DECLARE(mpf_audio_stream_t*) mpf_termination_audio_stream_get(mpf_termination_t *termination); +MPF_DECLARE(mpf_audio_stream_t*) mpf_termination_audio_stream_get(const mpf_termination_t *termination); /** * Get video stream. * @param termination the termination to get video stream from */ -MPF_DECLARE(mpf_video_stream_t*) mpf_termination_video_stream_get(mpf_termination_t *termination); +MPF_DECLARE(mpf_video_stream_t*) mpf_termination_video_stream_get(const mpf_termination_t *termination); APT_END_EXTERN_C -#endif /*__MPF_TERMINATION_FACTORY_H__*/ +#endif /* MPF_TERMINATION_FACTORY_H */ diff --git a/libs/unimrcp/libs/mpf/include/mpf_timer_manager.h b/libs/unimrcp/libs/mpf/include/mpf_timer_manager.h deleted file mode 100644 index 4de738c4f6..0000000000 --- a/libs/unimrcp/libs/mpf/include/mpf_timer_manager.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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_MANAGER_H__ -#define __MPF_TIMER_MANAGER_H__ - -/** - * @file mpf_timer_manager.h - * @brief MPF Timer Management - */ - -#include "mpf_types.h" - -APT_BEGIN_EXTERN_C - - -/** Prototype of timer callback */ -typedef void (*mpf_timer_proc_f)(mpf_timer_t *timer, void *obj); - - -/** Create timer manager */ -MPF_DECLARE(mpf_timer_manager_t*) mpf_timer_manager_create(mpf_scheduler_t *scheduler, apr_pool_t *pool); - -/** Destroy timer manager */ -MPF_DECLARE(void) mpf_timer_manager_destroy(mpf_timer_manager_t *timer_manager); - - -/** Create timer */ -MPF_DECLARE(mpf_timer_t*) mpf_timer_create(mpf_timer_manager_t *timer_manager, mpf_timer_proc_f proc, void *obj, apr_pool_t *pool); - -/** Set one-shot timer */ -MPF_DECLARE(apt_bool_t) mpf_timer_set(mpf_timer_t *timer, apr_uint32_t timeout); - -/** Kill timer */ -MPF_DECLARE(apt_bool_t) mpf_timer_kill(mpf_timer_t *timer); - - -APT_END_EXTERN_C - -#endif /*__MPF_TIMER_MANAGER_H__*/ diff --git a/libs/unimrcp/libs/mpf/include/mpf_types.h b/libs/unimrcp/libs/mpf/include/mpf_types.h index 0b9814edb5..f3017489f6 100644 --- a/libs/unimrcp/libs/mpf/include/mpf_types.h +++ b/libs/unimrcp/libs/mpf/include/mpf_types.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mpf_types.h 1543 2010-02-24 21:46:24Z achaloyan $ */ -#ifndef __MPF_TYPES_H__ -#define __MPF_TYPES_H__ +#ifndef MPF_TYPES_H +#define MPF_TYPES_H /** * @file mpf_types.h @@ -35,12 +37,6 @@ typedef struct mpf_scheduler_t mpf_scheduler_t; /** Opaque codec manager declaration */ typedef struct mpf_codec_manager_t mpf_codec_manager_t; -/** Opaque MPF timer manager declaration */ -typedef struct mpf_timer_manager_t mpf_timer_manager_t; - -/** Opaque MPF timer declaration */ -typedef struct mpf_timer_t mpf_timer_t; - /** Opaque MPF context declaration */ typedef struct mpf_context_t mpf_context_t; @@ -59,4 +55,4 @@ typedef struct mpf_video_stream_t mpf_video_stream_t; APT_END_EXTERN_C -#endif /*__MPF_TYPES_H__*/ +#endif /* MPF_TYPES_H */ diff --git a/libs/unimrcp/libs/mpf/mpf.2008.vcproj b/libs/unimrcp/libs/mpf/mpf.2008.vcproj deleted file mode 100644 index 2f02670890..0000000000 --- a/libs/unimrcp/libs/mpf/mpf.2008.vcproj +++ /dev/null @@ -1,567 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/unimrcp/libs/mpf/mpf.2010.vcxproj b/libs/unimrcp/libs/mpf/mpf.2010.vcxproj deleted file mode 100644 index 1b48acef80..0000000000 --- a/libs/unimrcp/libs/mpf/mpf.2010.vcxproj +++ /dev/null @@ -1,193 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - mpf - {B5A00BFA-6083-4FAE-A097-71642D6473B5} - mpf - Win32Proj - - - - StaticLibrary - Unicode - true - - - StaticLibrary - Unicode - - - StaticLibrary - Unicode - true - - - StaticLibrary - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - - - - codecs;%(AdditionalIncludeDirectories) - APT_STATIC_LIB;MPF_STATIC_LIB;%(PreprocessorDefinitions) - - - - - X64 - - - codecs;%(AdditionalIncludeDirectories) - APT_STATIC_LIB;MPF_STATIC_LIB;%(PreprocessorDefinitions) - false - ProgramDatabase - - - - - codecs;%(AdditionalIncludeDirectories) - APT_STATIC_LIB;MPF_STATIC_LIB;%(PreprocessorDefinitions) - - - - - X64 - - - codecs;%(AdditionalIncludeDirectories) - APT_STATIC_LIB;MPF_STATIC_LIB;%(PreprocessorDefinitions) - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/libs/unimrcp/libs/mpf/mpf.2010.vcxproj.filters b/libs/unimrcp/libs/mpf/mpf.2010.vcxproj.filters deleted file mode 100644 index 0e4bc84d13..0000000000 --- a/libs/unimrcp/libs/mpf/mpf.2010.vcxproj.filters +++ /dev/null @@ -1,239 +0,0 @@ - - - - - {3d69fc35-a195-4376-9508-ef77d7b27e71} - - - {81e2eace-c57a-4135-92cd-cc3575dfb088} - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {6fc3533a-b688-477d-914d-e0ffb15aa9a9} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - - - codecs\g711 - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - src - - - - - codecs\g711 - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - \ No newline at end of file diff --git a/libs/unimrcp/libs/mpf/mpf.vcproj b/libs/unimrcp/libs/mpf/mpf.vcproj index bf380d1e31..b3fde36677 100644 --- a/libs/unimrcp/libs/mpf/mpf.vcproj +++ b/libs/unimrcp/libs/mpf/mpf.vcproj @@ -416,10 +416,6 @@ RelativePath=".\include\mpf_termination_factory.h" > - - @@ -541,10 +537,6 @@ RelativePath=".\src\mpf_termination_factory.c" > - - diff --git a/libs/unimrcp/libs/mpf/src/mpf_activity_detector.c b/libs/unimrcp/libs/mpf/src/mpf_activity_detector.c index 6ef66674eb..bf3cd76fc6 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_activity_detector.c +++ b/libs/unimrcp/libs/mpf/src/mpf_activity_detector.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_activity_detector.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include "mpf_activity_detector.h" diff --git a/libs/unimrcp/libs/mpf/src/mpf_audio_file_stream.c b/libs/unimrcp/libs/mpf/src/mpf_audio_file_stream.c index 54010b69b4..c235da38de 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_audio_file_stream.c +++ b/libs/unimrcp/libs/mpf/src/mpf_audio_file_stream.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_audio_file_stream.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include "mpf_audio_file_stream.h" diff --git a/libs/unimrcp/libs/mpf/src/mpf_bridge.c b/libs/unimrcp/libs/mpf/src/mpf_bridge.c index f4028063d3..25c12de2ff 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_bridge.c +++ b/libs/unimrcp/libs/mpf/src/mpf_bridge.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_bridge.c 1693 2010-05-16 18:33:07Z achaloyan $ */ #include "mpf_bridge.h" @@ -31,7 +33,8 @@ struct mpf_bridge_t { mpf_audio_stream_t *source; /** Audio stream sink */ mpf_audio_stream_t *sink; - + /** Codec used in case of null bridge */ + mpf_codec_t *codec; /** Media frame used to read data from source and write it to sink */ mpf_frame_t frame; }; @@ -57,7 +60,14 @@ static apt_bool_t mpf_null_bridge_process(mpf_object_t *object) { mpf_bridge_t *bridge = (mpf_bridge_t*) object; bridge->frame.type = MEDIA_FRAME_TYPE_NONE; + bridge->frame.marker = MPF_MARKER_NONE; bridge->source->vtable->read_frame(bridge->source,&bridge->frame); + + if((bridge->frame.type & MEDIA_FRAME_TYPE_AUDIO) == 0) { + /* generate silence frame */ + mpf_codec_initialize(bridge->codec,&bridge->frame.codec_frame); + } + bridge->sink->vtable->write_frame(bridge->sink,&bridge->frame); return TRUE; } @@ -80,20 +90,20 @@ static void mpf_bridge_trace(mpf_object_t *object) mpf_audio_stream_trace(bridge->sink,STREAM_DIRECTION_SEND,&output); *output.pos = '\0'; - apt_log(APT_LOG_MARK,APT_PRIO_INFO,output.text.buf); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Media Path %s %s",object->name,output.text.buf); } static apt_bool_t mpf_bridge_destroy(mpf_object_t *object) { mpf_bridge_t *bridge = (mpf_bridge_t*) object; - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Destroy Audio Bridge"); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Destroy Audio Bridge %s",object->name); mpf_audio_stream_rx_close(bridge->source); mpf_audio_stream_tx_close(bridge->sink); return TRUE; } -static mpf_bridge_t* mpf_bridge_base_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, apr_pool_t *pool) +static mpf_bridge_t* mpf_bridge_base_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, const char *name, apr_pool_t *pool) { mpf_bridge_t *bridge; if(!source || !sink) { @@ -103,20 +113,21 @@ static mpf_bridge_t* mpf_bridge_base_create(mpf_audio_stream_t *source, mpf_audi bridge = apr_palloc(pool,sizeof(mpf_bridge_t)); bridge->source = source; bridge->sink = sink; - mpf_object_init(&bridge->base); + bridge->codec = NULL; + mpf_object_init(&bridge->base,name); bridge->base.destroy = mpf_bridge_destroy; bridge->base.process = mpf_bridge_process; bridge->base.trace = mpf_bridge_trace; return bridge; } -static mpf_object_t* mpf_linear_bridge_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, const mpf_codec_manager_t *codec_manager, apr_pool_t *pool) +static mpf_object_t* mpf_linear_bridge_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, const mpf_codec_manager_t *codec_manager, const char *name, apr_pool_t *pool) { mpf_codec_descriptor_t *descriptor; apr_size_t frame_size; mpf_bridge_t *bridge; - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Create Linear Audio Bridge"); - bridge = mpf_bridge_base_create(source,sink,pool); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Create Linear Audio Bridge %s",name); + bridge = mpf_bridge_base_create(source,sink,name,pool); if(!bridge) { return NULL; } @@ -136,13 +147,13 @@ static mpf_object_t* mpf_linear_bridge_create(mpf_audio_stream_t *source, mpf_au return &bridge->base; } -static mpf_object_t* mpf_null_bridge_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, const mpf_codec_manager_t *codec_manager, apr_pool_t *pool) +static mpf_object_t* mpf_null_bridge_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, const mpf_codec_manager_t *codec_manager, const char *name, apr_pool_t *pool) { mpf_codec_t *codec; apr_size_t frame_size; mpf_bridge_t *bridge; - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Create Null Audio Bridge"); - bridge = mpf_bridge_base_create(source,sink,pool); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Create Null Audio Bridge %s",name); + bridge = mpf_bridge_base_create(source,sink,name,pool); if(!bridge) { return NULL; } @@ -154,6 +165,7 @@ static mpf_object_t* mpf_null_bridge_create(mpf_audio_stream_t *source, mpf_audi } frame_size = mpf_codec_frame_size_calculate(source->rx_descriptor,codec->attribs); + bridge->codec = codec; bridge->frame.codec_frame.size = frame_size; bridge->frame.codec_frame.buffer = apr_palloc(pool,frame_size); @@ -167,7 +179,12 @@ static mpf_object_t* mpf_null_bridge_create(mpf_audio_stream_t *source, mpf_audi return &bridge->base; } -MPF_DECLARE(mpf_object_t*) mpf_bridge_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, const mpf_codec_manager_t *codec_manager, apr_pool_t *pool) +MPF_DECLARE(mpf_object_t*) mpf_bridge_create( + mpf_audio_stream_t *source, + mpf_audio_stream_t *sink, + const mpf_codec_manager_t *codec_manager, + const char *name, + apr_pool_t *pool) { if(!source || !sink) { return NULL; @@ -179,7 +196,7 @@ MPF_DECLARE(mpf_object_t*) mpf_bridge_create(mpf_audio_stream_t *source, mpf_aud } if(mpf_codec_descriptors_match(source->rx_descriptor,sink->tx_descriptor) == TRUE) { - return mpf_null_bridge_create(source,sink,codec_manager,pool); + return mpf_null_bridge_create(source,sink,codec_manager,name,pool); } if(mpf_codec_lpcm_descriptor_match(source->rx_descriptor) == FALSE) { @@ -209,5 +226,5 @@ MPF_DECLARE(mpf_object_t*) mpf_bridge_create(mpf_audio_stream_t *source, mpf_aud source = resampler; } - return mpf_linear_bridge_create(source,sink,codec_manager,pool); + return mpf_linear_bridge_create(source,sink,codec_manager,name,pool); } diff --git a/libs/unimrcp/libs/mpf/src/mpf_buffer.c b/libs/unimrcp/libs/mpf/src/mpf_buffer.c index f128760277..b253d6ae02 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_buffer.c +++ b/libs/unimrcp/libs/mpf/src/mpf_buffer.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_buffer.c 1709 2010-05-24 17:12:11Z achaloyan $ */ #ifdef WIN32 @@ -165,7 +167,7 @@ apt_bool_t mpf_buffer_frame_read(mpf_buffer_t *buffer, mpf_frame_t *media_frame) return TRUE; } -apr_size_t mpf_buffer_get_size(mpf_buffer_t *buffer) +apr_size_t mpf_buffer_get_size(const 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 index 2995cf94a5..b493f4959b 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_codec_descriptor.c +++ b/libs/unimrcp/libs/mpf/src/mpf_codec_descriptor.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_codec_descriptor.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include "mpf_codec_descriptor.h" diff --git a/libs/unimrcp/libs/mpf/src/mpf_codec_g711.c b/libs/unimrcp/libs/mpf/src/mpf_codec_g711.c index ab20a278f9..5a4a66de2e 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_codec_g711.c +++ b/libs/unimrcp/libs/mpf/src/mpf_codec_g711.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_codec_g711.c 1686 2010-05-08 18:46:08Z achaloyan $ */ #include "mpf_codec.h" @@ -70,6 +72,17 @@ static apt_bool_t g711u_decode(mpf_codec_t *codec, const mpf_codec_frame_t *fram return TRUE; } +static apt_bool_t g711u_init(mpf_codec_t *codec, mpf_codec_frame_t *frame_out) +{ + apr_size_t i; + unsigned char *encode_buf = frame_out->buffer; + for(i=0; isize; i++) { + encode_buf[i] = linear_to_ulaw(0); + } + + 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 apr_int16_t *decode_buf; @@ -106,12 +119,24 @@ static apt_bool_t g711a_decode(mpf_codec_t *codec, const mpf_codec_frame_t *fram return TRUE; } +static apt_bool_t g711a_init(mpf_codec_t *codec, mpf_codec_frame_t *frame_out) +{ + apr_size_t i; + unsigned char *encode_buf = frame_out->buffer; + for(i=0; isize; i++) { + encode_buf[i] = linear_to_alaw(0); + } + + return TRUE; +} + static const mpf_codec_vtable_t g711u_vtable = { g711_open, g711_close, g711u_encode, g711u_decode, - NULL + NULL, + g711u_init }; static const mpf_codec_vtable_t g711a_vtable = { @@ -119,7 +144,8 @@ static const mpf_codec_vtable_t g711a_vtable = { g711_close, g711a_encode, g711a_decode, - NULL + NULL, + g711a_init }; static const mpf_codec_descriptor_t g711u_descriptor = { diff --git a/libs/unimrcp/libs/mpf/src/mpf_codec_linear.c b/libs/unimrcp/libs/mpf/src/mpf_codec_linear.c index 7f342b0a31..7e6b091100 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_codec_linear.c +++ b/libs/unimrcp/libs/mpf/src/mpf_codec_linear.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_codec_linear.c 1686 2010-05-08 18:46:08Z achaloyan $ */ #define APR_WANT_BYTEFUNC @@ -71,6 +73,7 @@ static const mpf_codec_vtable_t l16_vtable = { l16_close, l16_encode, l16_decode, + NULL, NULL }; diff --git a/libs/unimrcp/libs/mpf/src/mpf_codec_manager.c b/libs/unimrcp/libs/mpf/src/mpf_codec_manager.c index b83581a25a..fa0482a610 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_codec_manager.c +++ b/libs/unimrcp/libs/mpf/src/mpf_codec_manager.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_codec_manager.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include diff --git a/libs/unimrcp/libs/mpf/src/mpf_context.c b/libs/unimrcp/libs/mpf/src/mpf_context.c index c6978d8e37..bdd0034ecb 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_context.c +++ b/libs/unimrcp/libs/mpf/src/mpf_context.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_context.c 1709 2010-05-24 17:12:11Z achaloyan $ */ #ifdef WIN32 @@ -46,6 +48,8 @@ struct mpf_context_t { mpf_context_factory_t *factory; /** Pool to allocate memory from */ apr_pool_t *pool; + /** Informative name of the context used for debugging */ + const char *name; /** External object */ void *obj; @@ -109,6 +113,7 @@ MPF_DECLARE(apt_bool_t) mpf_context_factory_process(mpf_context_factory_t *facto MPF_DECLARE(mpf_context_t*) mpf_context_create( mpf_context_factory_t *factory, + const char *name, void *obj, apr_size_t max_termination_count, apr_pool_t *pool) @@ -120,6 +125,10 @@ MPF_DECLARE(mpf_context_t*) mpf_context_create( context->factory = factory; context->obj = obj; context->pool = pool; + context->name = name; + if(!context->name) { + context->name = apr_psprintf(pool,"0x%pp",context); + } context->capacity = max_termination_count; context->count = 0; context->mpf_objects = apr_array_make(pool,1,sizeof(mpf_object_t*)); @@ -154,7 +163,7 @@ MPF_DECLARE(apt_bool_t) mpf_context_destroy(mpf_context_t *context) return TRUE; } -MPF_DECLARE(void*) mpf_context_object_get(mpf_context_t *context) +MPF_DECLARE(void*) mpf_context_object_get(const mpf_context_t *context) { return context->obj; } @@ -169,11 +178,10 @@ MPF_DECLARE(apt_bool_t) mpf_context_termination_add(mpf_context_t *context, mpf_ continue; } if(!context->count) { - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add Context"); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add Media Context %s",context->name); APR_RING_INSERT_TAIL(&context->factory->head,context,mpf_context_t,link); } - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add Termination"); header_item->termination = termination; header_item->tx_count = 0; header_item->rx_count = 0; @@ -200,7 +208,6 @@ MPF_DECLARE(apt_bool_t) mpf_context_termination_subtract(mpf_context_t *context, return FALSE; } - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Subtract Termination"); for(j=0,k=0; jcapacity && kcount; j++) { header_item2 = &context->header[j]; if(!header_item2->termination) { @@ -227,7 +234,7 @@ MPF_DECLARE(apt_bool_t) mpf_context_termination_subtract(mpf_context_t *context, termination->slot = (apr_size_t)-1; context->count--; if(!context->count) { - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Remove Context"); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Remove Media Context %s",context->name); APR_RING_REMOVE(context,link); } return TRUE; @@ -463,6 +470,7 @@ static mpf_object_t* mpf_context_bridge_create(mpf_context_t *context, apr_size_ header_item1->termination->audio_stream, header_item2->termination->audio_stream, header_item1->termination->codec_manager, + context->name, context->pool); } } @@ -494,6 +502,7 @@ static mpf_object_t* mpf_context_multiplier_create(mpf_context_t *context, apr_s sink_arr, header_item1->tx_count, header_item1->termination->codec_manager, + context->name, context->pool); } @@ -522,6 +531,7 @@ static mpf_object_t* mpf_context_mixer_create(mpf_context_t *context, apr_size_t header_item1->rx_count, header_item1->termination->audio_stream, header_item1->termination->codec_manager, + context->name, context->pool); } diff --git a/libs/unimrcp/libs/mpf/src/mpf_decoder.c b/libs/unimrcp/libs/mpf/src/mpf_decoder.c index 878dbbf459..e01d438803 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_decoder.c +++ b/libs/unimrcp/libs/mpf/src/mpf_decoder.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_decoder.c 1530 2010-02-19 18:40:08Z achaloyan $ */ #include "mpf_decoder.h" @@ -36,12 +38,14 @@ static apt_bool_t mpf_decoder_destroy(mpf_audio_stream_t *stream) static apt_bool_t mpf_decoder_open(mpf_audio_stream_t *stream, mpf_codec_t *codec) { mpf_decoder_t *decoder = stream->obj; + mpf_codec_open(decoder->codec); return mpf_audio_stream_rx_open(decoder->source,decoder->codec); } static apt_bool_t mpf_decoder_close(mpf_audio_stream_t *stream) { mpf_decoder_t *decoder = stream->obj; + mpf_codec_close(decoder->codec); return mpf_audio_stream_rx_close(decoder->source); } diff --git a/libs/unimrcp/libs/mpf/src/mpf_dtmf_detector.c b/libs/unimrcp/libs/mpf/src/mpf_dtmf_detector.c index e40096a2ed..f22da57a8d 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_dtmf_detector.c +++ b/libs/unimrcp/libs/mpf/src/mpf_dtmf_detector.c @@ -1,5 +1,5 @@ /* - * Copyright 2009 Tomas Valenta, Arsen Chaloyan + * Copyright 2009-2010 Tomas Valenta, Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_dtmf_detector.c 1788 2010-11-22 19:45:38Z tomas.valenta@speechtech.cz $ */ #include "mpf_dtmf_detector.h" @@ -217,8 +219,8 @@ static void goertzel_energies_digit(struct mpf_dtmf_detector_t *detector) } } - if ((reng < 8.0e8 * detector->wsamples / GOERTZEL_SAMPLES_8K) || - (ceng < 8.0e8 * detector->wsamples / GOERTZEL_SAMPLES_8K)) + if ((reng < 8.0e10 * detector->wsamples / GOERTZEL_SAMPLES_8K) || + (ceng < 8.0e10 * detector->wsamples / GOERTZEL_SAMPLES_8K)) { /* energy not high enough */ } else if ((ceng > reng) && (reng < ceng * 0.398)) { /* twist > 4dB, error */ @@ -233,7 +235,7 @@ static void goertzel_energies_digit(struct mpf_dtmf_detector_t *detector) */ } else if ((ceng < reng) && (ceng < reng * 0.158)) { /* twist > 8db, error */ /* Reverse twist check failed */ - } else if (0.025 * detector->totenergy > (reng + ceng)) { /* 16db */ + } else if (0.25 * detector->totenergy > (reng + ceng)) { /* 16db */ /* Signal energy to total energy ratio test failed */ } else { digit = freq2digits[rmax][cmax - DTMF_FREQUENCIES/2]; diff --git a/libs/unimrcp/libs/mpf/src/mpf_dtmf_generator.c b/libs/unimrcp/libs/mpf/src/mpf_dtmf_generator.c index 836561db01..a31240be4a 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_dtmf_generator.c +++ b/libs/unimrcp/libs/mpf/src/mpf_dtmf_generator.c @@ -1,5 +1,5 @@ /* - * Copyright 2009 Tomas Valenta, Arsen Chaloyan + * Copyright 2009-2010 Tomas Valenta, Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_dtmf_generator.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include "mpf_dtmf_generator.h" diff --git a/libs/unimrcp/libs/mpf/src/mpf_encoder.c b/libs/unimrcp/libs/mpf/src/mpf_encoder.c index 797600192f..c80d98fb45 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_encoder.c +++ b/libs/unimrcp/libs/mpf/src/mpf_encoder.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_encoder.c 1530 2010-02-19 18:40:08Z achaloyan $ */ #include "mpf_encoder.h" @@ -36,12 +38,14 @@ static apt_bool_t mpf_encoder_destroy(mpf_audio_stream_t *stream) static apt_bool_t mpf_encoder_open(mpf_audio_stream_t *stream, mpf_codec_t *codec) { mpf_encoder_t *encoder = stream->obj; + mpf_codec_open(encoder->codec); return mpf_audio_stream_tx_open(encoder->sink,encoder->codec); } static apt_bool_t mpf_encoder_close(mpf_audio_stream_t *stream) { mpf_encoder_t *encoder = stream->obj; + mpf_codec_close(encoder->codec); return mpf_audio_stream_tx_close(encoder->sink); } diff --git a/libs/unimrcp/libs/mpf/src/mpf_engine.c b/libs/unimrcp/libs/mpf/src/mpf_engine.c index 087b248884..06ef5db33f 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_engine.c +++ b/libs/unimrcp/libs/mpf/src/mpf_engine.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_engine.c 1709 2010-05-24 17:12:11Z achaloyan $ */ #include "mpf_engine.h" @@ -21,12 +23,11 @@ #include "mpf_scheduler.h" #include "mpf_codec_descriptor.h" #include "mpf_codec_manager.h" -#include "mpf_timer_manager.h" #include "apt_obj_list.h" #include "apt_cyclic_queue.h" #include "apt_log.h" -#define MPF_TASK_NAME "Media Processing Engine" +#define MPF_TIMER_RESOLUTION 100 /* 100 ms */ struct mpf_engine_t { apr_pool_t *pool; @@ -36,11 +37,12 @@ struct mpf_engine_t { apt_cyclic_queue_t *request_queue; mpf_context_factory_t *context_factory; mpf_scheduler_t *scheduler; - mpf_timer_manager_t *timer_manager; + apt_timer_queue_t *timer_queue; const mpf_codec_manager_t *codec_manager; }; -static void mpf_engine_main(mpf_scheduler_t *scheduler, void *data); +static void mpf_engine_main(mpf_scheduler_t *scheduler, void *obj); +static void mpf_engine_timer_proc(mpf_scheduler_t *scheduler, void *obj); 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); @@ -52,7 +54,7 @@ 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) +MPF_DECLARE(mpf_engine_t*) mpf_engine_create(const char *id, apr_pool_t *pool) { apt_task_vtable_t *vtable; apt_task_msg_pool_t *msg_pool; @@ -64,13 +66,13 @@ MPF_DECLARE(mpf_engine_t*) mpf_engine_create(apr_pool_t *pool) msg_pool = apt_task_msg_pool_create_dynamic(sizeof(mpf_message_container_t),pool); - apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create "MPF_TASK_NAME); + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create Media Engine [%s]",id); engine->task = apt_task_create(engine,msg_pool,pool); if(!engine->task) { return NULL; } - apt_task_name_set(engine->task,MPF_TASK_NAME); + apt_task_name_set(engine->task,id); vtable = apt_task_vtable_get(engine->task); if(vtable) { @@ -90,17 +92,19 @@ MPF_DECLARE(mpf_engine_t*) mpf_engine_create(apr_pool_t *pool) engine->scheduler = mpf_scheduler_create(engine->pool); mpf_scheduler_media_clock_set(engine->scheduler,CODEC_FRAME_TIME_BASE,mpf_engine_main,engine); - engine->timer_manager = mpf_timer_manager_create(engine->scheduler,engine->pool); + engine->timer_queue = apt_timer_queue_create(engine->pool); + mpf_scheduler_timer_clock_set(engine->scheduler,MPF_TIMER_RESOLUTION,mpf_engine_timer_proc,engine); return engine; } MPF_DECLARE(mpf_context_t*) mpf_engine_context_create( - mpf_engine_t *engine, - void *obj, - apr_size_t max_termination_count, + mpf_engine_t *engine, + const char *name, + void *obj, + apr_size_t max_termination_count, apr_pool_t *pool) { - return mpf_context_create(engine->context_factory,obj,max_termination_count,pool); + return mpf_context_create(engine->context_factory,name,obj,max_termination_count,pool); } MPF_DECLARE(apt_bool_t) mpf_engine_context_destroy(mpf_context_t *context) @@ -108,12 +112,12 @@ MPF_DECLARE(apt_bool_t) mpf_engine_context_destroy(mpf_context_t *context) return mpf_context_destroy(context); } -MPF_DECLARE(void*) mpf_engine_context_object_get(mpf_context_t *context) +MPF_DECLARE(void*) mpf_engine_context_object_get(const mpf_context_t *context) { return mpf_context_object_get(context); } -MPF_DECLARE(apt_task_t*) mpf_task_get(mpf_engine_t *engine) +MPF_DECLARE(apt_task_t*) mpf_task_get(const mpf_engine_t *engine) { return engine->task; } @@ -223,7 +227,7 @@ static apt_bool_t mpf_engine_destroy(apt_task_t *task) { mpf_engine_t *engine = apt_task_object_get(task); - mpf_timer_manager_destroy(engine->timer_manager); + apt_timer_queue_destroy(engine->timer_queue); mpf_scheduler_destroy(engine->scheduler); mpf_context_factory_destroy(engine->context_factory); apt_cyclic_queue_destroy(engine->request_queue); @@ -282,7 +286,7 @@ static apt_bool_t mpf_engine_msg_signal(apt_task_t *task, apt_task_msg_t *msg) 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"); + apt_log(APT_LOG_MARK,APT_PRIO_ERROR,"MPF Request Queue is Full [%s]",apt_task_name_get(task)); } apr_thread_mutex_unlock(engine->request_queue_guard); return TRUE; @@ -299,7 +303,6 @@ static apt_bool_t mpf_engine_msg_process(apt_task_t *task, apt_task_msg_t *msg) mpf_termination_t *termination; const mpf_message_t *mpf_request; const mpf_message_container_t *request = (const mpf_message_container_t*) msg->data; - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process MPF Message"); response_msg = apt_task_msg_get(engine->task); response_msg->type = engine->task_msg_type; @@ -324,7 +327,7 @@ static apt_bool_t mpf_engine_msg_process(apt_task_t *task, apt_task_msg_t *msg) termination->event_handler_obj = engine; termination->event_handler = mpf_engine_event_raise; termination->codec_manager = engine->codec_manager; - termination->timer_manager = engine->timer_manager; + termination->timer_queue = engine->timer_queue; mpf_termination_add(termination,mpf_request->descriptor); if(mpf_context_termination_add(context,termination) == FALSE) { @@ -383,9 +386,9 @@ static apt_bool_t mpf_engine_msg_process(apt_task_t *task, apt_task_msg_t *msg) return apt_task_msg_parent_signal(engine->task,response_msg); } -static void mpf_engine_main(mpf_scheduler_t *scheduler, void *data) +static void mpf_engine_main(mpf_scheduler_t *scheduler, void *obj) { - mpf_engine_t *engine = data; + mpf_engine_t *engine = obj; apt_task_msg_t *msg; /* process request queue */ @@ -403,6 +406,12 @@ static void mpf_engine_main(mpf_scheduler_t *scheduler, void *data) mpf_context_factory_process(engine->context_factory); } +static void mpf_engine_timer_proc(mpf_scheduler_t *scheduler, void *obj) +{ + mpf_engine_t *engine = obj; + apt_timer_queue_advance(engine->timer_queue,MPF_TIMER_RESOLUTION); +} + 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(4,pool); @@ -431,3 +440,8 @@ MPF_DECLARE(apt_bool_t) mpf_engine_scheduler_rate_set(mpf_engine_t *engine, unsi { return mpf_scheduler_rate_set(engine->scheduler,rate); } + +MPF_DECLARE(const char*) mpf_engine_id_get(const mpf_engine_t *engine) +{ + return apt_task_name_get(engine->task); +} diff --git a/libs/unimrcp/libs/mpf/src/mpf_file_termination_factory.c b/libs/unimrcp/libs/mpf/src/mpf_file_termination_factory.c index dd1bc6e280..5da0815fe3 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_file_termination_factory.c +++ b/libs/unimrcp/libs/mpf/src/mpf_file_termination_factory.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_file_termination_factory.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include "mpf_termination.h" diff --git a/libs/unimrcp/libs/mpf/src/mpf_frame_buffer.c b/libs/unimrcp/libs/mpf/src/mpf_frame_buffer.c index d93e5c56aa..6f1d568377 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_frame_buffer.c +++ b/libs/unimrcp/libs/mpf/src/mpf_frame_buffer.c @@ -1,5 +1,5 @@ /* - * Copyright 2009 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_frame_buffer.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include "mpf_frame_buffer.h" diff --git a/libs/unimrcp/libs/mpf/src/mpf_jitter_buffer.c b/libs/unimrcp/libs/mpf/src/mpf_jitter_buffer.c index 0235e762c4..5ddfb2e7be 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_jitter_buffer.c +++ b/libs/unimrcp/libs/mpf/src/mpf_jitter_buffer.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_jitter_buffer.c 1802 2011-05-13 02:43:12Z achaloyan $ */ #include "mpf_jitter_buffer.h" @@ -102,6 +104,10 @@ mpf_jitter_buffer_t* mpf_jitter_buffer_create(mpf_jb_config_t *jb_config, mpf_co frame->codec_frame.buffer = jb->raw_data + i*jb->frame_size; } + if(jb->config->initial_playout_delay % CODEC_FRAME_TIME_BASE != 0) { + jb->config->initial_playout_delay += CODEC_FRAME_TIME_BASE - jb->config->initial_playout_delay % CODEC_FRAME_TIME_BASE; + } + jb->playout_delay_ts = (apr_uint32_t)(jb->config->initial_playout_delay * descriptor->channel_count * descriptor->sampling_rate / 1000); @@ -149,17 +155,28 @@ static APR_INLINE jb_result_t mpf_jitter_buffer_write_prepare(mpf_jitter_buffer_ *write_ts = ts - jb->write_ts_offset + jb->playout_delay_ts; if(*write_ts % jb->frame_ts != 0) { /* not frame alligned */ + JB_TRACE("JB write ts=%"APR_SIZE_T_FMT" not alligned -> discard\n",write_ts); return JB_DISCARD_NOT_ALLIGNED; } return JB_OK; } -jb_result_t mpf_jitter_buffer_write(mpf_jitter_buffer_t *jb, void *buffer, apr_size_t size, apr_uint32_t ts) +jb_result_t mpf_jitter_buffer_write(mpf_jitter_buffer_t *jb, void *buffer, apr_size_t size, apr_uint32_t ts, apr_byte_t marker) { mpf_frame_t *media_frame; apr_uint32_t write_ts; apr_size_t available_frame_count; - jb_result_t result = mpf_jitter_buffer_write_prepare(jb,ts,&write_ts); + jb_result_t result; + + if(marker) { + /* new talkspurt */ + if(jb->write_ts <= jb->read_ts) { + /* buffer is empty => it's safe to restart */ + mpf_jitter_buffer_restart(jb); + } + } + + result = mpf_jitter_buffer_write_prepare(jb,ts,&write_ts); if(result != JB_OK) { return result; } diff --git a/libs/unimrcp/libs/mpf/src/mpf_mixer.c b/libs/unimrcp/libs/mpf/src/mpf_mixer.c index 9d46990c30..3c36dd449d 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_mixer.c +++ b/libs/unimrcp/libs/mpf/src/mpf_mixer.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_mixer.c 1693 2010-05-16 18:33:07Z achaloyan $ */ #include "mpf_mixer.h" @@ -90,6 +92,7 @@ static apt_bool_t mpf_mixer_destroy(mpf_object_t *object) mpf_audio_stream_t *source; mpf_mixer_t *mixer = (mpf_mixer_t*) object; + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Destroy Mixer %s",object->name); for(i=0; isource_count; i++) { source = mixer->source_arr[i]; if(source) { @@ -126,7 +129,9 @@ static void mpf_mixer_trace(mpf_object_t *object) mpf_audio_stream_trace(mixer->sink,STREAM_DIRECTION_SEND,&output); *output.pos = '\0'; - apt_log(APT_LOG_MARK,APT_PRIO_INFO,output.text.buf); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Media Path %s %s", + object->name, + output.text.buf); } MPF_DECLARE(mpf_object_t*) mpf_mixer_create( @@ -134,6 +139,7 @@ MPF_DECLARE(mpf_object_t*) mpf_mixer_create( apr_size_t source_count, mpf_audio_stream_t *sink, const mpf_codec_manager_t *codec_manager, + const char *name, apr_pool_t *pool) { apr_size_t i; @@ -145,11 +151,12 @@ MPF_DECLARE(mpf_object_t*) mpf_mixer_create( return NULL; } + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Create Mixer %s",name); mixer = apr_palloc(pool,sizeof(mpf_mixer_t)); mixer->source_arr = NULL; mixer->source_count = 0; mixer->sink = NULL; - mpf_object_init(&mixer->base); + mpf_object_init(&mixer->base,name); mixer->base.process = mpf_mixer_process; mixer->base.destroy = mpf_mixer_destroy; mixer->base.trace = mpf_mixer_trace; diff --git a/libs/unimrcp/libs/mpf/src/mpf_multiplier.c b/libs/unimrcp/libs/mpf/src/mpf_multiplier.c index 7ea9b88690..2014932841 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_multiplier.c +++ b/libs/unimrcp/libs/mpf/src/mpf_multiplier.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_multiplier.c 1693 2010-05-16 18:33:07Z achaloyan $ */ #include "mpf_multiplier.h" @@ -69,6 +71,7 @@ static apt_bool_t mpf_multiplier_destroy(mpf_object_t *object) mpf_audio_stream_t *sink; mpf_multiplier_t *multiplier = (mpf_multiplier_t*) object; + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Destroy Multiplier %s",object->name); mpf_audio_stream_rx_close(multiplier->source); for(i=0; isink_count; i++) { sink = multiplier->sink_arr[i]; @@ -105,7 +108,9 @@ static void mpf_multiplier_trace(mpf_object_t *object) } *output.pos = '\0'; - apt_log(APT_LOG_MARK,APT_PRIO_INFO,output.text.buf); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Media Path %s %s", + object->name, + output.text.buf); } MPF_DECLARE(mpf_object_t*) mpf_multiplier_create( @@ -113,6 +118,7 @@ MPF_DECLARE(mpf_object_t*) mpf_multiplier_create( mpf_audio_stream_t **sink_arr, apr_size_t sink_count, const mpf_codec_manager_t *codec_manager, + const char *name, apr_pool_t *pool) { apr_size_t i; @@ -124,11 +130,12 @@ MPF_DECLARE(mpf_object_t*) mpf_multiplier_create( return NULL; } + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Create Multiplier %s",name); multiplier = apr_palloc(pool,sizeof(mpf_multiplier_t)); multiplier->source = NULL; multiplier->sink_arr = NULL; multiplier->sink_count = 0; - mpf_object_init(&multiplier->base); + mpf_object_init(&multiplier->base,name); multiplier->base.process = mpf_multiplier_process; multiplier->base.destroy = mpf_multiplier_destroy; multiplier->base.trace = mpf_multiplier_trace; diff --git a/libs/unimrcp/libs/mpf/src/mpf_named_event.c b/libs/unimrcp/libs/mpf/src/mpf_named_event.c index f8bc75363f..22c319dae4 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_named_event.c +++ b/libs/unimrcp/libs/mpf/src/mpf_named_event.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_named_event.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include "mpf_named_event.h" diff --git a/libs/unimrcp/libs/mpf/src/mpf_resampler.c b/libs/unimrcp/libs/mpf/src/mpf_resampler.c index 113ffac8fb..fe4a45c9fc 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_resampler.c +++ b/libs/unimrcp/libs/mpf/src/mpf_resampler.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_resampler.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include "mpf_resampler.h" diff --git a/libs/unimrcp/libs/mpf/src/mpf_rtp_attribs.c b/libs/unimrcp/libs/mpf/src/mpf_rtp_attribs.c index a34f05fc93..5e9e184f0f 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_rtp_attribs.c +++ b/libs/unimrcp/libs/mpf/src/mpf_rtp_attribs.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_rtp_attribs.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include "apt_string_table.h" diff --git a/libs/unimrcp/libs/mpf/src/mpf_rtp_stream.c b/libs/unimrcp/libs/mpf/src/mpf_rtp_stream.c index 0e8ac028a9..f94b3295c2 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_rtp_stream.c +++ b/libs/unimrcp/libs/mpf/src/mpf_rtp_stream.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,14 +12,16 @@ * 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. + * + * $Id: mpf_rtp_stream.c 1802 2011-05-13 02:43:12Z achaloyan $ */ #include #include "apt_net.h" +#include "apt_timer_queue.h" #include "mpf_rtp_stream.h" #include "mpf_termination.h" #include "mpf_codec_manager.h" -#include "mpf_timer_manager.h" #include "mpf_rtp_header.h" #include "mpf_rtcp_packet.h" #include "mpf_rtp_defs.h" @@ -55,6 +57,7 @@ struct mpf_rtp_stream_t { rtp_receiver_t receiver; mpf_rtp_config_t *config; + mpf_rtp_settings_t *settings; apr_socket_t *rtp_socket; apr_socket_t *rtcp_socket; @@ -63,8 +66,8 @@ struct mpf_rtp_stream_t { apr_sockaddr_t *rtcp_l_sockaddr; apr_sockaddr_t *rtcp_r_sockaddr; - mpf_timer_t *rtcp_tx_timer; - mpf_timer_t *rtcp_rx_timer; + apt_timer_t *rtcp_tx_timer; + apt_timer_t *rtcp_rx_timer; apr_pool_t *pool; }; @@ -92,11 +95,11 @@ static void mpf_rtp_socket_pair_close(mpf_rtp_stream_t *stream); static apt_bool_t mpf_rtcp_report_send(mpf_rtp_stream_t *stream); static apt_bool_t mpf_rtcp_bye_send(mpf_rtp_stream_t *stream, apt_str_t *reason); -static void mpf_rtcp_tx_timer_proc(mpf_timer_t *timer, void *obj); -static void mpf_rtcp_rx_timer_proc(mpf_timer_t *timer, void *obj); +static void mpf_rtcp_tx_timer_proc(apt_timer_t *timer, void *obj); +static void mpf_rtcp_rx_timer_proc(apt_timer_t *timer, void *obj); -MPF_DECLARE(mpf_audio_stream_t*) mpf_rtp_stream_create(mpf_termination_t *termination, mpf_rtp_config_t *config, apr_pool_t *pool) +MPF_DECLARE(mpf_audio_stream_t*) mpf_rtp_stream_create(mpf_termination_t *termination, mpf_rtp_config_t *config, mpf_rtp_settings_t *settings, apr_pool_t *pool) { mpf_rtp_stream_t *rtp_stream = apr_palloc(pool,sizeof(mpf_rtp_stream_t)); mpf_stream_capabilities_t *capabilities = mpf_stream_capabilities_create(STREAM_DIRECTION_DUPLEX,pool); @@ -111,6 +114,7 @@ MPF_DECLARE(mpf_audio_stream_t*) mpf_rtp_stream_create(mpf_termination_t *termin rtp_stream->base = audio_stream; rtp_stream->pool = pool; rtp_stream->config = config; + rtp_stream->settings = settings; rtp_stream->local_media = NULL; rtp_stream->remote_media = NULL; rtp_stream->rtp_socket = NULL; @@ -126,16 +130,16 @@ MPF_DECLARE(mpf_audio_stream_t*) mpf_rtp_stream_create(mpf_termination_t *termin rtp_transmitter_init(&rtp_stream->transmitter); rtp_stream->transmitter.sr_stat.ssrc = (apr_uint32_t)apr_time_now(); - if(config->rtcp == TRUE) { - if(config->rtcp_tx_interval) { - rtp_stream->rtcp_tx_timer = mpf_timer_create( - termination->timer_manager, + if(settings->rtcp == TRUE) { + if(settings->rtcp_tx_interval) { + rtp_stream->rtcp_tx_timer = apt_timer_create( + termination->timer_queue, mpf_rtcp_tx_timer_proc, rtp_stream, pool); } - if(config->rtcp_rx_resolution) { - rtp_stream->rtcp_rx_timer = mpf_timer_create( - termination->timer_manager, + if(settings->rtcp_rx_resolution) { + rtp_stream->rtcp_rx_timer = apt_timer_create( + termination->timer_queue, mpf_rtcp_rx_timer_proc, rtp_stream, pool); } @@ -163,21 +167,25 @@ static apt_bool_t mpf_rtp_stream_local_media_create(mpf_rtp_stream_t *rtp_stream } if(local_media->port == 0) { /* RTP port management */ - apr_port_t first_port_in_search = rtp_stream->config->rtp_port_cur; + mpf_rtp_config_t *rtp_config = rtp_stream->config; + apr_port_t first_port_in_search = rtp_config->rtp_port_cur; apt_bool_t is_port_ok = FALSE; do { - local_media->port = rtp_stream->config->rtp_port_cur; - rtp_stream->config->rtp_port_cur += 2; - if(rtp_stream->config->rtp_port_cur == rtp_stream->config->rtp_port_max) { - rtp_stream->config->rtp_port_cur = rtp_stream->config->rtp_port_min; + local_media->port = rtp_config->rtp_port_cur; + rtp_config->rtp_port_cur += 2; + if(rtp_config->rtp_port_cur == rtp_config->rtp_port_max) { + rtp_config->rtp_port_cur = rtp_config->rtp_port_min; } if(mpf_rtp_socket_pair_create(rtp_stream,local_media) == TRUE) { is_port_ok = TRUE; } - } while((is_port_ok == FALSE) && (first_port_in_search != rtp_stream->config->rtp_port_cur)); + } while((is_port_ok == FALSE) && (first_port_in_search != rtp_config->rtp_port_cur)); if(is_port_ok == FALSE) { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Find Free RTP Port"); + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Find Free RTP Port %s:[%hu,%hu]", + rtp_config->ip.buf, + rtp_config->rtp_port_min, + rtp_config->rtp_port_max); local_media->state = MPF_MEDIA_DISABLED; status = FALSE; } @@ -187,12 +195,12 @@ static apt_bool_t mpf_rtp_stream_local_media_create(mpf_rtp_stream_t *rtp_stream status = FALSE; } - if(rtp_stream->config->ptime) { - local_media->ptime = rtp_stream->config->ptime; + if(rtp_stream->settings->ptime) { + local_media->ptime = rtp_stream->settings->ptime; } if(mpf_codec_list_is_empty(&local_media->codec_list) == TRUE) { - if(mpf_codec_list_is_empty(&rtp_stream->config->codec_list) == TRUE) { + if(mpf_codec_list_is_empty(&rtp_stream->settings->codec_list) == TRUE) { mpf_codec_manager_codec_list_get( rtp_stream->base->termination->codec_manager, &local_media->codec_list, @@ -200,7 +208,7 @@ static apt_bool_t mpf_rtp_stream_local_media_create(mpf_rtp_stream_t *rtp_stream } else { mpf_codec_list_copy(&local_media->codec_list, - &rtp_stream->config->codec_list, + &rtp_stream->settings->codec_list, rtp_stream->pool); } @@ -297,10 +305,10 @@ static apt_bool_t mpf_rtp_stream_media_negotiate(mpf_rtp_stream_t *rtp_stream) } if(rtp_stream->rtcp_tx_timer) { - mpf_timer_set(rtp_stream->rtcp_tx_timer,rtp_stream->config->rtcp_tx_interval); + apt_timer_set(rtp_stream->rtcp_tx_timer,rtp_stream->settings->rtcp_tx_interval); } if(rtp_stream->rtcp_rx_timer) { - mpf_timer_set(rtp_stream->rtcp_rx_timer,rtp_stream->config->rtcp_rx_resolution); + apt_timer_set(rtp_stream->rtcp_rx_timer,rtp_stream->settings->rtcp_rx_resolution); } } else if(rtp_stream->state == MPF_MEDIA_ENABLED && remote_media->state == MPF_MEDIA_DISABLED) { @@ -313,12 +321,12 @@ static apt_bool_t mpf_rtp_stream_media_negotiate(mpf_rtp_stream_t *rtp_stream) } if(rtp_stream->rtcp_tx_timer) { - mpf_timer_kill(rtp_stream->rtcp_tx_timer); + apt_timer_kill(rtp_stream->rtcp_tx_timer); } if(rtp_stream->rtcp_rx_timer) { - mpf_timer_kill(rtp_stream->rtcp_rx_timer); + apt_timer_kill(rtp_stream->rtcp_rx_timer); } - if(rtp_stream->config->rtcp == TRUE && rtp_stream->config->rtcp_bye_policy != RTCP_BYE_DISABLE) { + if(rtp_stream->settings->rtcp == TRUE && rtp_stream->settings->rtcp_bye_policy != RTCP_BYE_DISABLE) { apt_str_t reason = {RTCP_BYE_SESSION_ENDED, sizeof(RTCP_BYE_SESSION_ENDED)-1}; mpf_rtcp_bye_send(rtp_stream,&reason); } @@ -337,7 +345,7 @@ static apt_bool_t mpf_rtp_stream_media_negotiate(mpf_rtp_stream_t *rtp_stream) } /* intersect local and remote codecs */ - if(rtp_stream->config->own_preferrence == TRUE) { + if(rtp_stream->settings->own_preferrence == TRUE) { mpf_codec_lists_intersect( &local_media->codec_list, &remote_media->codec_list); @@ -371,12 +379,12 @@ MPF_DECLARE(apt_bool_t) mpf_rtp_stream_remove(mpf_audio_stream_t *stream) } if(rtp_stream->rtcp_tx_timer) { - mpf_timer_kill(rtp_stream->rtcp_tx_timer); + apt_timer_kill(rtp_stream->rtcp_tx_timer); } if(rtp_stream->rtcp_rx_timer) { - mpf_timer_kill(rtp_stream->rtcp_rx_timer); + apt_timer_kill(rtp_stream->rtcp_rx_timer); } - if(rtp_stream->config->rtcp == TRUE && rtp_stream->config->rtcp_bye_policy != RTCP_BYE_DISABLE) { + if(rtp_stream->settings->rtcp == TRUE && rtp_stream->settings->rtcp_bye_policy != RTCP_BYE_DISABLE) { apt_str_t reason = {RTCP_BYE_SESSION_ENDED, sizeof(RTCP_BYE_SESSION_ENDED)-1}; mpf_rtcp_bye_send(rtp_stream,&reason); } @@ -451,7 +459,7 @@ static apt_bool_t mpf_rtp_rx_stream_open(mpf_audio_stream_t *stream, mpf_codec_t } receiver->jb = mpf_jitter_buffer_create( - &rtp_stream->config->jb_config, + &rtp_stream->settings->jb_config, stream->rx_descriptor, codec, rtp_stream->pool); @@ -461,7 +469,7 @@ static apt_bool_t mpf_rtp_rx_stream_open(mpf_audio_stream_t *stream, mpf_codec_t rtp_stream->rtp_l_sockaddr->port, rtp_stream->rtp_r_sockaddr->hostname, rtp_stream->rtp_r_sockaddr->port, - rtp_stream->config->jb_config.initial_playout_delay); + rtp_stream->settings->jb_config.initial_playout_delay); return TRUE; } @@ -484,14 +492,16 @@ static apt_bool_t mpf_rtp_rx_stream_close(mpf_audio_stream_t *stream) } mpf_jitter_buffer_destroy(receiver->jb); - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close RTP Receiver %s:%hu <- %s:%hu [r:%lu l:%lu j:%lu]", + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close RTP Receiver %s:%hu <- %s:%hu [r:%u l:%u j:%u d:%u i:%u]", rtp_stream->rtp_l_sockaddr->hostname, rtp_stream->rtp_l_sockaddr->port, rtp_stream->rtp_r_sockaddr->hostname, rtp_stream->rtp_r_sockaddr->port, receiver->stat.received_packets, receiver->stat.lost_packets, - receiver->rr_stat.jitter); + receiver->rr_stat.jitter, + receiver->stat.discarded_packets, + receiver->stat.ignored_packets); return TRUE; } @@ -557,8 +567,13 @@ static APR_INLINE void rtp_periodic_history_update(rtp_receiver_t *receiver) apr_uint32_t lost_interval; /* calculate expected packets */ - expected_packets = receiver->history.seq_cycles + - receiver->history.seq_num_max - receiver->history.seq_num_base + 1; + if(receiver->stat.received_packets) { + expected_packets = receiver->history.seq_cycles + + receiver->history.seq_num_max - receiver->history.seq_num_base + 1; + } + else { + expected_packets = 0; + } /* calculate expected interval */ expected_interval = expected_packets - receiver->periodic_history.expected_prior; @@ -709,7 +724,7 @@ static APR_INLINE void rtp_rx_failure_threshold_check(rtp_receiver_t *receiver) discarded = receiver->stat.discarded_packets - receiver->periodic_history.discarded_prior; if(discarded * 100 > received * DISCARDED_TO_RECEIVED_RATIO_THRESHOLD) { - /* failure threshold hired, restart */ + /* failure threshold reached -> restart */ rtp_rx_restart(receiver); } } @@ -733,7 +748,7 @@ static apt_bool_t rtp_rx_packet_receive(mpf_rtp_stream_t *rtp_stream, void *buff time = apr_time_now(); - RTP_TRACE("RTP time=%6lu ssrc=%8lx pt=%3u %cts=%9lu seq=%5u size=%lu\n", + RTP_TRACE("RTP time=%6u ssrc=%8x pt=%3u %cts=%9u seq=%5u size=%"APR_SIZE_T_FMT"\n", (apr_uint32_t)apr_time_usec(time), header->ssrc, header->type, (header->marker == 1) ? '*' : ' ', header->timestamp, header->sequence, size); @@ -761,7 +776,7 @@ static apt_bool_t rtp_rx_packet_receive(mpf_rtp_stream_t *rtp_stream, void *buff return FALSE; } - if(mpf_jitter_buffer_write(receiver->jb,buffer,size,header->timestamp) != JB_OK) { + if(mpf_jitter_buffer_write(receiver->jb,buffer,size,header->timestamp,(apr_byte_t)header->marker) != JB_OK) { receiver->stat.discarded_packets++; rtp_rx_failure_threshold_check(receiver); } @@ -825,8 +840,8 @@ static apt_bool_t mpf_rtp_tx_stream_open(mpf_audio_stream_t *stream, mpf_codec_t } if(!transmitter->ptime) { - if(rtp_stream->config && rtp_stream->config->ptime) { - transmitter->ptime = rtp_stream->config->ptime; + if(rtp_stream->settings && rtp_stream->settings->ptime) { + transmitter->ptime = rtp_stream->settings->ptime; } else { transmitter->ptime = 20; @@ -857,10 +872,10 @@ static apt_bool_t mpf_rtp_tx_stream_close(mpf_audio_stream_t *stream) if(!rtp_stream->rtp_l_sockaddr || !rtp_stream->rtp_r_sockaddr) { return FALSE; } - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close RTP Transmitter %s:%hu -> %s:%hu [s:%lu o:%lu]", + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close RTP Transmitter %s:%hu -> %s:%hu [s:%u o:%u]", rtp_stream->rtp_l_sockaddr->hostname, rtp_stream->rtp_l_sockaddr->port, - rtp_stream->rtp_l_sockaddr->hostname, + rtp_stream->rtp_r_sockaddr->hostname, rtp_stream->rtp_r_sockaddr->port, rtp_stream->transmitter.sr_stat.sent_packets, rtp_stream->transmitter.sr_stat.sent_octets); @@ -973,7 +988,7 @@ static apt_bool_t mpf_rtp_stream_transmit(mpf_audio_stream_t *stream, const mpf_ if(transmitter->current_frames == 0) { /* set inactivity (ptime alligned) */ transmitter->inactivity = 1; - if(rtp_stream->config->rtcp == TRUE && rtp_stream->config->rtcp_bye_policy == RTCP_BYE_PER_TALKSPURT) { + if(rtp_stream->settings->rtcp == TRUE && rtp_stream->settings->rtcp_bye_policy == RTCP_BYE_PER_TALKSPURT) { apt_str_t reason = {RTCP_BYE_TALKSPURT_ENDED, sizeof(RTCP_BYE_TALKSPURT_ENDED)-1}; mpf_rtcp_bye_send(rtp_stream,&reason); } @@ -1089,7 +1104,7 @@ static APR_INLINE void rtcp_sr_generate(mpf_rtp_stream_t *rtp_stream, rtcp_sr_st apt_ntp_time_get(&sr_stat->ntp_sec, &sr_stat->ntp_frac); sr_stat->rtp_ts = rtp_stream->transmitter.timestamp; - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Generate RTCP SR [ssrc:%lu s:%lu o:%lu ts:%lu]", + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Generate RTCP SR [ssrc:%u s:%u o:%u ts:%u]", sr_stat->ssrc, sr_stat->sent_packets, sr_stat->sent_octets, @@ -1102,7 +1117,7 @@ static APR_INLINE void rtcp_rr_generate(mpf_rtp_stream_t *rtp_stream, rtcp_rr_st *rr_stat = rtp_stream->receiver.rr_stat; rr_stat->last_seq = rtp_stream->receiver.history.seq_num_max; - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Generate RTCP RR [ssrc:%lu last_seq:%lu j:%lu lost:%lu frac:%d]", + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Generate RTCP RR [ssrc:%u last_seq:%u j:%u lost:%u frac:%d]", rr_stat->ssrc, rr_stat->last_seq, rr_stat->jitter, @@ -1302,7 +1317,7 @@ static apt_bool_t mpf_rtcp_bye_send(mpf_rtp_stream_t *rtp_stream, apt_str_t *rea static APR_INLINE void rtcp_sr_get(mpf_rtp_stream_t *rtp_stream, rtcp_sr_stat_t *sr_stat) { rtcp_sr_ntoh(sr_stat); - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Get RTCP SR [ssrc:%lu s:%lu o:%lu ts:%lu]", + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Get RTCP SR [ssrc:%u s:%u o:%u ts:%u]", sr_stat->ssrc, sr_stat->sent_packets, sr_stat->sent_octets, @@ -1312,7 +1327,7 @@ static APR_INLINE void rtcp_sr_get(mpf_rtp_stream_t *rtp_stream, rtcp_sr_stat_t static APR_INLINE void rtcp_rr_get(mpf_rtp_stream_t *rtp_stream, rtcp_rr_stat_t *rr_stat) { rtcp_rr_ntoh(rr_stat); - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Get RTCP RR [ssrc:%lu last_seq:%lu j:%lu lost:%lu frac:%d]", + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Get RTCP RR [ssrc:%u last_seq:%u j:%u lost:%u frac:%d]", rr_stat->ssrc, rr_stat->last_seq, rr_stat->jitter, @@ -1366,7 +1381,7 @@ static apt_bool_t mpf_rtcp_compound_packet_receive(mpf_rtp_stream_t *rtp_stream, return TRUE; } -static void mpf_rtcp_tx_timer_proc(mpf_timer_t *timer, void *obj) +static void mpf_rtcp_tx_timer_proc(apt_timer_t *timer, void *obj) { mpf_rtp_stream_t *rtp_stream = obj; @@ -1374,10 +1389,10 @@ static void mpf_rtcp_tx_timer_proc(mpf_timer_t *timer, void *obj) mpf_rtcp_report_send(rtp_stream); /* re-schedule timer */ - mpf_timer_set(timer,rtp_stream->config->rtcp_tx_interval); + apt_timer_set(timer,rtp_stream->settings->rtcp_tx_interval); } -static void mpf_rtcp_rx_timer_proc(mpf_timer_t *timer, void *obj) +static void mpf_rtcp_rx_timer_proc(apt_timer_t *timer, void *obj) { mpf_rtp_stream_t *rtp_stream = obj; if(rtp_stream->rtcp_socket && rtp_stream->rtcp_l_sockaddr && rtp_stream->rtcp_r_sockaddr) { @@ -1396,5 +1411,5 @@ static void mpf_rtcp_rx_timer_proc(mpf_timer_t *timer, void *obj) } /* re-schedule timer */ - mpf_timer_set(timer,rtp_stream->config->rtcp_rx_resolution); + apt_timer_set(timer,rtp_stream->settings->rtcp_rx_resolution); } diff --git a/libs/unimrcp/libs/mpf/src/mpf_rtp_termination_factory.c b/libs/unimrcp/libs/mpf/src/mpf_rtp_termination_factory.c index 0202e2e498..7b3cfa144f 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_rtp_termination_factory.c +++ b/libs/unimrcp/libs/mpf/src/mpf_rtp_termination_factory.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_rtp_termination_factory.c 1693 2010-05-16 18:33:07Z achaloyan $ */ #include "mpf_termination.h" @@ -37,7 +39,11 @@ static apt_bool_t mpf_rtp_termination_add(mpf_termination_t *termination, void * 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); + audio_stream = mpf_rtp_stream_create( + termination, + termination_factory->config, + rtp_descriptor->audio.settings, + termination->pool); if(!audio_stream) { return FALSE; } @@ -85,7 +91,11 @@ static const mpf_termination_vtable_t rtp_vtable = { 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_termination_t *termination = mpf_termination_base_create(termination_factory,obj,&rtp_vtable,NULL,NULL,pool); + if(termination) { + termination->name = "rtp-tm"; + } + return termination; } MPF_DECLARE(mpf_termination_factory_t*) mpf_rtp_termination_factory_create( diff --git a/libs/unimrcp/libs/mpf/src/mpf_scheduler.c b/libs/unimrcp/libs/mpf/src/mpf_scheduler.c index 24a4c8adf2..452799cbf9 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_scheduler.c +++ b/libs/unimrcp/libs/mpf/src/mpf_scheduler.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_scheduler.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include "mpf_scheduler.h" diff --git a/libs/unimrcp/libs/mpf/src/mpf_stream.c b/libs/unimrcp/libs/mpf/src/mpf_stream.c index 1135e46e01..fa474c39c4 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_stream.c +++ b/libs/unimrcp/libs/mpf/src/mpf_stream.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_stream.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include "mpf_stream.h" diff --git a/libs/unimrcp/libs/mpf/src/mpf_termination.c b/libs/unimrcp/libs/mpf/src/mpf_termination.c index 05eff5c419..e32589eed5 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_termination.c +++ b/libs/unimrcp/libs/mpf/src/mpf_termination.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_termination.c 1693 2010-05-16 18:33:07Z achaloyan $ */ #include "mpf_termination.h" @@ -28,11 +30,12 @@ MPF_DECLARE(mpf_termination_t*) mpf_termination_base_create( { mpf_termination_t *termination = apr_palloc(pool,sizeof(mpf_termination_t)); termination->pool = pool; + termination->name = "media-tm"; termination->obj = obj; termination->event_handler_obj = NULL; termination->event_handler = NULL; termination->codec_manager = NULL; - termination->timer_manager = NULL; + termination->timer_queue = NULL; termination->termination_factory = termination_factory; termination->vtable = vtable; termination->slot = 0; diff --git a/libs/unimrcp/libs/mpf/src/mpf_termination_factory.c b/libs/unimrcp/libs/mpf/src/mpf_termination_factory.c index ba89f51064..1823fd826a 100644 --- a/libs/unimrcp/libs/mpf/src/mpf_termination_factory.c +++ b/libs/unimrcp/libs/mpf/src/mpf_termination_factory.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mpf_termination_factory.c 1693 2010-05-16 18:33:07Z achaloyan $ */ #include "mpf_termination_factory.h" @@ -47,20 +49,26 @@ MPF_DECLARE(apt_bool_t) mpf_termination_destroy(mpf_termination_t *termination) return TRUE; } +/** Get termination name */ +MPF_DECLARE(const char*) mpf_termination_name_get(const mpf_termination_t *termination) +{ + return termination->name; +} + /** Get associated object. */ -MPF_DECLARE(void*) mpf_termination_object_get(mpf_termination_t *termination) +MPF_DECLARE(void*) mpf_termination_object_get(const mpf_termination_t *termination) { return termination->obj; } /** Get audio stream. */ -MPF_DECLARE(mpf_audio_stream_t*) mpf_termination_audio_stream_get(mpf_termination_t *termination) +MPF_DECLARE(mpf_audio_stream_t*) mpf_termination_audio_stream_get(const mpf_termination_t *termination) { return termination->audio_stream; } /** Get video stream. */ -MPF_DECLARE(mpf_video_stream_t*) mpf_termination_video_stream_get(mpf_termination_t *termination) +MPF_DECLARE(mpf_video_stream_t*) mpf_termination_video_stream_get(const mpf_termination_t *termination) { return termination->video_stream; } diff --git a/libs/unimrcp/libs/mpf/src/mpf_timer_manager.c b/libs/unimrcp/libs/mpf/src/mpf_timer_manager.c deleted file mode 100644 index a3c8735869..0000000000 --- a/libs/unimrcp/libs/mpf/src/mpf_timer_manager.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * 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 -#include "mpf_timer_manager.h" -#include "mpf_scheduler.h" -#include "apt_log.h" - -/** MPF timer manager */ -struct mpf_timer_manager_t { - /** Ring head */ - APR_RING_HEAD(mpf_timer_head_t, mpf_timer_t) head; - - /** Clock resolution */ - apr_uint32_t resolution; - /** Elapsed time */ - apr_uint32_t elapsed_time; -}; - -/** MPF timer */ -struct mpf_timer_t { - /** Ring entry */ - APR_RING_ENTRY(mpf_timer_t) link; - - /** Back pointer to manager */ - mpf_timer_manager_t *manager; - /** Time next report is scheduled at */ - apr_uint32_t scheduled_time; - - /** Timer proc */ - mpf_timer_proc_f proc; - /** Timer object */ - void *obj; -}; - -static void mpf_scheduler_proc(mpf_scheduler_t *scheduler, void *obj); - -/** Create timer manager */ -MPF_DECLARE(mpf_timer_manager_t*) mpf_timer_manager_create(mpf_scheduler_t *scheduler, apr_pool_t *pool) -{ - mpf_timer_manager_t *timer_manager = apr_palloc(pool,sizeof(mpf_timer_manager_t)); - APR_RING_INIT(&timer_manager->head, mpf_timer_t, link); - timer_manager->elapsed_time = 0; - timer_manager->resolution = 100; /* 100 ms */ - - mpf_scheduler_timer_clock_set(scheduler,timer_manager->resolution,mpf_scheduler_proc,timer_manager); - return timer_manager; -} - -/** Destroy timer manager */ -MPF_DECLARE(void) mpf_timer_manager_destroy(mpf_timer_manager_t *timer_manager) -{ -} - - -/** Create timer */ -MPF_DECLARE(mpf_timer_t*) mpf_timer_create(mpf_timer_manager_t *timer_manager, mpf_timer_proc_f proc, void *obj, apr_pool_t *pool) -{ - mpf_timer_t *timer = apr_palloc(pool,sizeof(mpf_timer_t)); - timer->manager = timer_manager; - timer->scheduled_time = 0; - timer->proc = proc; - timer->obj = obj; - return timer; -} - -static APR_INLINE apt_bool_t mpf_timer_insert(mpf_timer_manager_t *manager, mpf_timer_t *timer) -{ - mpf_timer_t *it; - for(it = APR_RING_LAST(&manager->head); - it != APR_RING_SENTINEL(&manager->head, mpf_timer_t, link); - it = APR_RING_PREV(it, link)) { - - if(it->scheduled_time <= timer->scheduled_time) { - APR_RING_INSERT_AFTER(it,timer,link); - return TRUE; - } - } - APR_RING_INSERT_HEAD(&manager->head,timer,mpf_timer_t,link); - return TRUE; -} - -/** Set one-shot timer */ -MPF_DECLARE(apt_bool_t) mpf_timer_set(mpf_timer_t *timer, apr_uint32_t timeout) - -{ - mpf_timer_manager_t *manager = timer->manager; - - if(timeout <= 0 || !timer->proc) { - return FALSE; - } - - /* calculate time to elapse */ - timer->scheduled_time = manager->elapsed_time + timeout; - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Set Timer 0x%x [%lu]",timer,timer->scheduled_time); - - if(APR_RING_EMPTY(&timer->manager->head, mpf_timer_t, link)) { - APR_RING_INSERT_TAIL(&manager->head,timer,mpf_timer_t,link); - return TRUE; - } - - /* insert new node (timer) to sorted by scheduled time list */ - return mpf_timer_insert(manager,timer); -} - -/** Kill timer */ -MPF_DECLARE(apt_bool_t) mpf_timer_kill(mpf_timer_t *timer) -{ - if(!timer->scheduled_time) { - return FALSE; - } - - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Kill Timer 0x%x [%lu]",timer,timer->scheduled_time); - /* remove node (timer) from the list */ - APR_RING_REMOVE(timer,link); - timer->scheduled_time = 0; - - if(APR_RING_EMPTY(&timer->manager->head, mpf_timer_t, link)) { - /* reset elapsed time if no timers set */ - timer->manager->elapsed_time = 0; - } - return TRUE; -} - -static void mpf_timers_reschedule(mpf_timer_manager_t *manager) -{ - mpf_timer_t *it; - for(it = APR_RING_LAST(&manager->head); - it != APR_RING_SENTINEL(&manager->head, mpf_timer_t, link); - it = APR_RING_PREV(it, link)) { - - it->scheduled_time -= manager->elapsed_time; - } - manager->elapsed_time = 0; -} - -static void mpf_scheduler_proc(mpf_scheduler_t *scheduler, void *obj) -{ - mpf_timer_manager_t *manager = obj; - mpf_timer_t *timer; - - if(APR_RING_EMPTY(&manager->head, mpf_timer_t, link)) { - /* just return, nothing to do */ - return; - } - - /* increment elapsed time */ - manager->elapsed_time += manager->resolution; - if(manager->elapsed_time >= 0xFFFF) { - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Reschedule Timers [%lu]",manager->elapsed_time); - mpf_timers_reschedule(manager); - } - - /* process timers */ - do { - /* get first node (timer) */ - timer = APR_RING_FIRST(&manager->head); - - if(timer->scheduled_time > manager->elapsed_time) { - /* scheduled time is not elapsed yet */ - break; - } - - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Timer Elapsed 0x%x [%lu]",timer,timer->scheduled_time); - /* remove the elapsed timer from the list */ - APR_RING_REMOVE(timer, link); - timer->scheduled_time = 0; - /* process the elapsed timer */ - timer->proc(timer,timer->obj); - } - while(!APR_RING_EMPTY(&manager->head, mpf_timer_t, link)); -} diff --git a/libs/unimrcp/libs/mrcp-client/Makefile.am b/libs/unimrcp/libs/mrcp-client/Makefile.am index ec749369be..f2d306fb96 100644 --- a/libs/unimrcp/libs/mrcp-client/Makefile.am +++ b/libs/unimrcp/libs/mrcp-client/Makefile.am @@ -19,4 +19,5 @@ include_HEADERS = include/mrcp_client_types.h \ include/mrcp_application.h libmrcpclient_la_SOURCES = src/mrcp_client.c \ - src/mrcp_client_session.c + src/mrcp_client_session.c \ + src/mrcp_application.c diff --git a/libs/unimrcp/libs/mrcp-client/include/mrcp_application.h b/libs/unimrcp/libs/mrcp-client/include/mrcp_application.h index 629c445526..66b097b962 100644 --- a/libs/unimrcp/libs/mrcp-client/include/mrcp_application.h +++ b/libs/unimrcp/libs/mrcp-client/include/mrcp_application.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_application.h 1779 2010-09-01 05:54:34Z achaloyan $ */ -#ifndef __MRCP_APPLICATION_H__ -#define __MRCP_APPLICATION_H__ +#ifndef MRCP_APPLICATION_H +#define MRCP_APPLICATION_H /** * @file mrcp_application.h @@ -152,13 +154,13 @@ MRCP_DECLARE(apt_bool_t) mrcp_application_destroy(mrcp_application_t *applicatio * 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); +MRCP_DECLARE(void*) mrcp_application_object_get(const 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); +MRCP_DECLARE(const apt_dir_layout_t*) mrcp_application_dir_layout_get(const mrcp_application_t *application); /** * Create session. @@ -173,19 +175,19 @@ MRCP_DECLARE(mrcp_session_t*) mrcp_application_session_create(mrcp_application_t * Get memory pool the session object is created out of. * @param session the session to get pool from */ -MRCP_DECLARE(apr_pool_t*) mrcp_application_session_pool_get(mrcp_session_t *session); +MRCP_DECLARE(apr_pool_t*) mrcp_application_session_pool_get(const mrcp_session_t *session); /** * Get session identifier. * @param session the session to get identifier of */ -MRCP_DECLARE(const apt_str_t*) mrcp_application_session_id_get(mrcp_session_t *session); +MRCP_DECLARE(const apt_str_t*) mrcp_application_session_id_get(const mrcp_session_t *session); /** * 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); +MRCP_DECLARE(void*) mrcp_application_session_object_get(const mrcp_session_t *session); /** * Set (associate) external object to the session. @@ -194,6 +196,13 @@ MRCP_DECLARE(void*) mrcp_application_session_object_get(mrcp_session_t *session) */ MRCP_DECLARE(void) mrcp_application_session_object_set(mrcp_session_t *session, void *obj); +/** + * Set name of the session (informative only used for debugging). + * @param session the session to set name for + * @param name the name to set + */ +MRCP_DECLARE(void) mrcp_application_session_name_set(mrcp_session_t *session, const char *name); + /** * Send session update request. * @param session the session to update @@ -232,25 +241,31 @@ MRCP_DECLARE(mrcp_channel_t*) mrcp_application_channel_create( * 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); +MRCP_DECLARE(void*) mrcp_application_channel_object_get(const 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); +MRCP_DECLARE(mpf_rtp_termination_descriptor_t*) mrcp_application_rtp_descriptor_get(const mrcp_channel_t *channel); /** * Get codec descriptor of source stream. * @param channel the channel to get descriptor from */ -MRCP_DECLARE(const mpf_codec_descriptor_t*) mrcp_application_source_descriptor_get(mrcp_channel_t *channel); +MRCP_DECLARE(const mpf_codec_descriptor_t*) mrcp_application_source_descriptor_get(const mrcp_channel_t *channel); /** * Get codec descriptor of sink stream. * @param channel the channel to get descriptor from */ -MRCP_DECLARE(const mpf_codec_descriptor_t*) mrcp_application_sink_descriptor_get(mrcp_channel_t *channel); +MRCP_DECLARE(const mpf_codec_descriptor_t*) mrcp_application_sink_descriptor_get(const mrcp_channel_t *channel); + +/** + * Get associated audio stream. + * @param channel the channel to get associated stream from + */ +MRCP_DECLARE(const mpf_audio_stream_t*) mrcp_application_audio_stream_get(const mrcp_channel_t *channel); /** * Send channel add request. @@ -336,4 +351,4 @@ MRCP_DECLARE(mpf_termination_t*) mrcp_application_sink_termination_create( APT_END_EXTERN_C -#endif /*__MRCP_APPLICATION_H__*/ +#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 index c62f0e8baf..9ddd5643bf 100644 --- a/libs/unimrcp/libs/mrcp-client/include/mrcp_client.h +++ b/libs/unimrcp/libs/mrcp-client/include/mrcp_client.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_client.h 1733 2010-06-07 17:26:49Z achaloyan $ */ -#ifndef __MRCP_CLIENT_H__ -#define __MRCP_CLIENT_H__ +#ifndef MRCP_CLIENT_H +#define MRCP_CLIENT_H /** * @file mrcp_client.h @@ -23,6 +25,7 @@ */ #include "mrcp_client_types.h" +#include "mpf_rtp_descriptor.h" #include "apt_task.h" APT_BEGIN_EXTERN_C @@ -82,15 +85,14 @@ MRCP_DECLARE(apt_bool_t) mrcp_client_codec_manager_register(mrcp_client_t *clien * 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); +MRCP_DECLARE(const mpf_codec_manager_t*) mrcp_client_codec_manager_get(const 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); +MRCP_DECLARE(apt_bool_t) mrcp_client_media_engine_register(mrcp_client_t *client, mpf_engine_t *media_engine); /** * Register RTP termination factory. @@ -100,21 +102,35 @@ MRCP_DECLARE(apt_bool_t) mrcp_client_media_engine_register(mrcp_client_t *client */ 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 RTP settings. + * @param client the MRCP client to set RTP settings for + * @param rtp_settings the settings to set + * @param name the name of the settings + */ +MRCP_DECLARE(apt_bool_t) mrcp_client_rtp_settings_register(mrcp_client_t *client, mpf_rtp_settings_t *rtp_settings, 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 + */ +MRCP_DECLARE(apt_bool_t) mrcp_client_signaling_agent_register(mrcp_client_t *client, mrcp_sig_agent_t *signaling_agent); + +/** + * Register MRCP signaling settings. + * @param client the MRCP client to set signaling settings for + * @param signaling_settings the signaling settings 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); +MRCP_DECLARE(apt_bool_t) mrcp_client_signaling_settings_register(mrcp_client_t *client, mrcp_sig_settings_t *signaling_settings, 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); +MRCP_DECLARE(apt_bool_t) mrcp_client_connection_agent_register(mrcp_client_t *client, mrcp_connection_agent_t *connection_agent); /** Create MRCP profile */ MRCP_DECLARE(mrcp_profile_t*) mrcp_client_profile_create( @@ -123,6 +139,8 @@ MRCP_DECLARE(mrcp_profile_t*) mrcp_client_profile_create( mrcp_connection_agent_t *connection_agent, mpf_engine_t *media_engine, mpf_termination_factory_t *rtp_factory, + mpf_rtp_settings_t *rtp_settings, + mrcp_sig_settings_t *signaling_settings, apr_pool_t *pool); /** @@ -145,43 +163,63 @@ MRCP_DECLARE(apt_bool_t) mrcp_client_application_register(mrcp_client_t *client, * 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); +MRCP_DECLARE(apr_pool_t*) mrcp_client_memory_pool_get(const 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); +MRCP_DECLARE(mpf_engine_t*) mrcp_client_media_engine_get(const 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); +MRCP_DECLARE(mpf_termination_factory_t*) mrcp_client_rtp_factory_get(const mrcp_client_t *client, const char *name); + +/** + * Get RTP settings by name + * @param client the MRCP client to get from + * @param name the name to lookup + */ +MRCP_DECLARE(mpf_rtp_settings_t*) mrcp_client_rtp_settings_get(const 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); +MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_client_signaling_agent_get(const mrcp_client_t *client, const char *name); + +/** + * Get signaling settings by name. + * @param client the MRCP client to get from + * @param name the name to lookup + */ +MRCP_DECLARE(mrcp_sig_settings_t*) mrcp_client_signaling_settings_get(const 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); +MRCP_DECLARE(mrcp_connection_agent_t*) mrcp_client_connection_agent_get(const 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); +MRCP_DECLARE(mrcp_profile_t*) mrcp_client_profile_get(const mrcp_client_t *client, const char *name); + +/** + * Get directory layout. + * @param client the MRCP client to get from + */ +MRCP_DECLARE(apt_dir_layout_t*) mrcp_client_dir_layout_get(const mrcp_client_t *client); APT_END_EXTERN_C -#endif /*__MRCP_CLIENT_H__*/ +#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 index 40a444a825..8944e122a9 100644 --- a/libs/unimrcp/libs/mrcp-client/include/mrcp_client_session.h +++ b/libs/unimrcp/libs/mrcp-client/include/mrcp_client_session.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_client_session.h 1733 2010-06-07 17:26:49Z achaloyan $ */ -#ifndef __MRCP_CLIENT_SESSION_H__ -#define __MRCP_CLIENT_SESSION_H__ +#ifndef MRCP_CLIENT_SESSION_H +#define MRCP_CLIENT_SESSION_H /** * @file mrcp_client_session.h @@ -142,6 +144,11 @@ struct mrcp_profile_t { mrcp_sig_agent_t *signaling_agent; /** Connection agent */ mrcp_connection_agent_t *connection_agent; + + /** Signaling settings */ + mrcp_sig_settings_t *signaling_settings; + /** RTP settings */ + mpf_rtp_settings_t *rtp_settings; }; /** MRCP application */ @@ -156,14 +163,12 @@ struct mrcp_application_t { 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_t *resource, - mpf_termination_t *termination, - mpf_rtp_termination_descriptor_t *rtp_descriptor, + mrcp_client_session_t *session, + mrcp_resource_t *resource, + mpf_termination_t *termination, + mpf_rtp_termination_descriptor_t *rtp_descriptor, void *obj); /** Create signaling app_message_t request */ @@ -202,4 +207,4 @@ apt_bool_t mrcp_client_on_disconnect(mrcp_channel_t *channel); APT_END_EXTERN_C -#endif /*__MRCP_CLIENT_SESSION_H__*/ +#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 index 4da19f0081..4e3b783f06 100644 --- a/libs/unimrcp/libs/mrcp-client/include/mrcp_client_types.h +++ b/libs/unimrcp/libs/mrcp-client/include/mrcp_client_types.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_client_types.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MRCP_CLIENT_TYPES_H__ -#define __MRCP_CLIENT_TYPES_H__ +#ifndef MRCP_CLIENT_TYPES_H +#define MRCP_CLIENT_TYPES_H /** * @file mrcp_client_types.h @@ -43,4 +45,4 @@ typedef struct mrcp_channel_t mrcp_channel_t; APT_END_EXTERN_C -#endif /*__MRCP_CLIENT_TYPES_H__*/ +#endif /* MRCP_CLIENT_TYPES_H */ diff --git a/libs/unimrcp/libs/mrcp-client/mrcpclient.2008.vcproj b/libs/unimrcp/libs/mrcp-client/mrcpclient.2008.vcproj deleted file mode 100644 index ee8c9b4375..0000000000 --- a/libs/unimrcp/libs/mrcp-client/mrcpclient.2008.vcproj +++ /dev/null @@ -1,289 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/unimrcp/libs/mrcp-client/mrcpclient.2010.vcxproj b/libs/unimrcp/libs/mrcp-client/mrcpclient.2010.vcxproj deleted file mode 100644 index 1c861d58b5..0000000000 --- a/libs/unimrcp/libs/mrcp-client/mrcpclient.2010.vcxproj +++ /dev/null @@ -1,121 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - mrcpclient - {72782932-37CC-46AE-8C7F-9A7B1A6EE108} - mrcpclient - Win32Proj - - - - StaticLibrary - Unicode - true - - - StaticLibrary - Unicode - - - StaticLibrary - Unicode - true - - - StaticLibrary - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - - - - APT_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;%(PreprocessorDefinitions) - - - - - X64 - - - APT_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;%(PreprocessorDefinitions) - ProgramDatabase - - - - - APT_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;%(PreprocessorDefinitions) - - - - - X64 - - - APT_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/libs/unimrcp/libs/mrcp-client/mrcpclient.2010.vcxproj.filters b/libs/unimrcp/libs/mrcp-client/mrcpclient.2010.vcxproj.filters deleted file mode 100644 index 4054110771..0000000000 --- a/libs/unimrcp/libs/mrcp-client/mrcpclient.2010.vcxproj.filters +++ /dev/null @@ -1,35 +0,0 @@ - - - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {890ddc88-1a65-4b89-996c-625f8ef76b90} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - - - include - - - include - - - include - - - include - - - - - src - - - src - - - \ No newline at end of file diff --git a/libs/unimrcp/libs/mrcp-client/mrcpclient.vcproj b/libs/unimrcp/libs/mrcp-client/mrcpclient.vcproj index 1b156212e2..046c3e4695 100644 --- a/libs/unimrcp/libs/mrcp-client/mrcpclient.vcproj +++ b/libs/unimrcp/libs/mrcp-client/mrcpclient.vcproj @@ -261,6 +261,10 @@ Name="src" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" > + + diff --git a/libs/unimrcp/libs/mrcp-client/src/mrcp_application.c b/libs/unimrcp/libs/mrcp-client/src/mrcp_application.c new file mode 100644 index 0000000000..f3b73af544 --- /dev/null +++ b/libs/unimrcp/libs/mrcp-client/src/mrcp_application.c @@ -0,0 +1,538 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: mrcp_application.c 1792 2011-01-10 21:08:52Z achaloyan $ + */ + +#include "mrcp_application.h" +#include "mrcp_client.h" +#include "mrcp_client_session.h" +#include "mrcp_message.h" +#include "mrcp_sig_agent.h" +#include "mrcp_resource_factory.h" +#include "mpf_termination_factory.h" +#include "apt_dir_layout.h" +#include "apt_log.h" + +mrcp_client_session_t* mrcp_client_session_create(mrcp_client_t *client); + +apt_bool_t mrcp_app_signaling_task_msg_signal(mrcp_sig_command_e command_id, mrcp_session_t *session, mrcp_channel_t *channel); +apt_bool_t mrcp_app_control_task_msg_signal(mrcp_session_t *session, mrcp_channel_t *channel, mrcp_message_t *message); + + +/** 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(const mrcp_application_t *application) +{ + return application->obj; +} + +/** Get dir layout structure */ +MRCP_DECLARE(const apt_dir_layout_t*) mrcp_application_dir_layout_get(const mrcp_application_t *application) +{ + return mrcp_client_dir_layout_get(application->client); +} + + + +/** 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 || !profile_name) { + 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->client); + if(!session) { + return NULL; + } + session->application = application; + session->app_obj = obj; + session->base.log_obj = obj; + session->profile = profile; + + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create MRCP Handle "APT_PTR_FMT" [%s]", + MRCP_SESSION_PTR(session), + profile_name); + return &session->base; +} + +/** Get memory pool the session object is created out of */ +MRCP_DECLARE(apr_pool_t*) mrcp_application_session_pool_get(const mrcp_session_t *session) +{ + if(!session) { + return NULL; + } + return session->pool; +} + +/** Get session identifier */ +MRCP_DECLARE(const apt_str_t*) mrcp_application_session_id_get(const mrcp_session_t *session) +{ + if(!session) { + return NULL; + } + return &session->id; +} + +/** Get external object associated with the session */ +MRCP_DECLARE(void*) mrcp_application_session_object_get(const 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; +} + +/** Set (associate) external object to the session */ +MRCP_DECLARE(void) mrcp_application_session_object_set(mrcp_session_t *session, void *obj) +{ + mrcp_client_session_t *client_session = (mrcp_client_session_t*)session; + if(client_session) { + client_session->app_obj = obj; + } +} + +/** Set name of the session (informative only used for debugging) */ +MRCP_DECLARE(void) mrcp_application_session_name_set(mrcp_session_t *session, const char *name) +{ + if(session && name) { + session->name = apr_pstrdup(session->pool,name); + } +} + + +/** 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 %s",session->name); + 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_resource_t *resource; + mrcp_profile_t *profile; + mrcp_client_session_t *client_session = (mrcp_client_session_t*)session; + if(!client_session || !client_session->profile) { + /* Invalid params */ + return FALSE; + } + profile = client_session->profile; + + if(!profile->resource_factory) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Channel: invalid profile"); + return FALSE; + } + resource = mrcp_resource_get(profile->resource_factory,resource_id); + if(!resource) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Channel: no such resource"); + return FALSE; + } + + if(termination) { + /* Media engine and RTP factory must be specified in this case */ + if(!profile->media_engine || !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(client_session,resource,termination,rtp_descriptor,obj); +} + +/** Get external object associated with the channel */ +MRCP_DECLARE(void*) mrcp_application_channel_object_get(const 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(const mrcp_channel_t *channel) +{ + if(!channel || !channel->rtp_termination_slot) { + return NULL; + } + return channel->rtp_termination_slot->descriptor; +} + +/** Get codec descriptor of source stream */ +MRCP_DECLARE(const mpf_codec_descriptor_t*) mrcp_application_source_descriptor_get(const mrcp_channel_t *channel) +{ + mpf_audio_stream_t *audio_stream; + if(!channel || !channel->termination) { + return NULL; + } + audio_stream = mpf_termination_audio_stream_get(channel->termination); + if(!audio_stream) { + return NULL; + } + return audio_stream->rx_descriptor; +} + +/** Get codec descriptor of sink stream */ +MRCP_DECLARE(const mpf_codec_descriptor_t*) mrcp_application_sink_descriptor_get(const mrcp_channel_t *channel) +{ + mpf_audio_stream_t *audio_stream; + if(!channel || !channel->termination) { + return NULL; + } + audio_stream = mpf_termination_audio_stream_get(channel->termination); + if(!audio_stream) { + return NULL; + } + return audio_stream->tx_descriptor; +} + +/** Get associated audio stream */ +MRCP_DECLARE(const mpf_audio_stream_t*) mrcp_application_audio_stream_get(const mrcp_channel_t *channel) +{ + if(!channel || !channel->termination) { + return NULL; + } + + return mpf_termination_audio_stream_get(channel->termination); +} + +/** 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 || !channel->resource) { + return NULL; + } + profile = client_session->profile; + if(!profile || !profile->resource_factory) { + return NULL; + } + mrcp_message = mrcp_request_create( + channel->resource, + profile->signaling_agent->mrcp_version, + method_id, + session->pool); + 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 audio termination */ +MRCP_DECLARE(mpf_termination_t*) mrcp_application_audio_termination_create( + mrcp_session_t *session, + const mpf_audio_stream_vtable_t *stream_vtable, + mpf_stream_capabilities_t *capabilities, + void *obj) +{ + mpf_audio_stream_t *audio_stream; + + if(!capabilities) { + return NULL; + } + + if(mpf_codec_capabilities_validate(&capabilities->codecs) == FALSE) { + return NULL; + } + + /* create audio stream */ + audio_stream = mpf_audio_stream_create( + obj, /* object to associate */ + stream_vtable, /* virtual methods table of audio stream */ + capabilities, /* stream capabilities */ + session->pool); /* memory pool to allocate memory from */ + if(!audio_stream) { + return NULL; + } + + /* 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 */ +} + +/** 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_stream_capabilities_t *capabilities; + mpf_audio_stream_t *audio_stream; + + capabilities = mpf_source_stream_capabilities_create(session->pool); + if(codec_descriptor) { + mpf_codec_capabilities_add( + &capabilities->codecs, + mpf_sample_rate_mask_get(codec_descriptor->sampling_rate), + codec_descriptor->name.buf); + } + else { + mpf_codec_default_capabilities_add(&capabilities->codecs); + } + + /* create audio stream */ + audio_stream = mpf_audio_stream_create( + obj, /* object to associate */ + stream_vtable, /* virtual methods table of audio stream */ + capabilities, /* stream capabilities */ + session->pool); /* memory pool to allocate memory from */ + + if(!audio_stream) { + return NULL; + } + + audio_stream->rx_descriptor = codec_descriptor; + + /* 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 */ +} + +/** Create sink media termination */ +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_stream_capabilities_t *capabilities; + mpf_audio_stream_t *audio_stream; + + capabilities = mpf_sink_stream_capabilities_create(session->pool); + if(codec_descriptor) { + mpf_codec_capabilities_add( + &capabilities->codecs, + mpf_sample_rate_mask_get(codec_descriptor->sampling_rate), + codec_descriptor->name.buf); + } + else { + mpf_codec_default_capabilities_add(&capabilities->codecs); + } + + /* create audio stream */ + audio_stream = mpf_audio_stream_create( + obj, /* object to associate */ + stream_vtable, /* virtual methods table of audio stream */ + capabilities, /* stream capabilities */ + session->pool); /* memory pool to allocate memory from */ + if(!audio_stream) { + return NULL; + } + + audio_stream->tx_descriptor = codec_descriptor; + + /* 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 */ +} + +/** 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_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; +} diff --git a/libs/unimrcp/libs/mrcp-client/src/mrcp_client.c b/libs/unimrcp/libs/mrcp-client/src/mrcp_client.c index 6fee8c09d7..7689cf37ef 100644 --- a/libs/unimrcp/libs/mrcp-client/src/mrcp_client.c +++ b/libs/unimrcp/libs/mrcp-client/src/mrcp_client.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,22 +12,18 @@ * 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. + * + * $Id: mrcp_client.c 1733 2010-06-07 17:26:49Z achaloyan $ */ #include #include #include "mrcp_client.h" -#include "mrcp_resource_factory.h" -#include "mrcp_resource.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_factory.h" -#include "mpf_codec_manager.h" -#include "apt_pool.h" #include "apt_consumer_task.h" +#include "apt_pool.h" #include "apt_log.h" #define CLIENT_TASK_NAME "MRCP Client" @@ -47,8 +43,12 @@ struct mrcp_client_t { apr_hash_t *rtp_factory_table; /** Table of signaling agents (mrcp_sig_agent_t*) */ apr_hash_t *sig_agent_table; + /** Table of signaling settings (mrcp_sig_settings_t*) */ + apr_hash_t *sig_settings_table; /** Table of connection agents (mrcp_connection_agent_t*) */ apr_hash_t *cnt_agent_table; + /** Table of RTP settings (mpf_rtp_settings_t*) */ + apr_hash_t *rtp_settings_table; /** Table of profiles (mrcp_profile_t*) */ apr_hash_t *profile_table; @@ -151,8 +151,6 @@ static const mrcp_connection_event_vtable_t connection_method_vtable = { 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 */ @@ -177,7 +175,9 @@ MRCP_DECLARE(mrcp_client_t*) mrcp_client_create(apt_dir_layout_t *dir_layout) client->media_engine_table = NULL; client->rtp_factory_table = NULL; client->sig_agent_table = NULL; + client->sig_settings_table = NULL; client->cnt_agent_table = NULL; + client->rtp_settings_table = NULL; client->profile_table = NULL; client->app_table = NULL; client->session_table = NULL; @@ -201,7 +201,9 @@ MRCP_DECLARE(mrcp_client_t*) mrcp_client_create(apt_dir_layout_t *dir_layout) 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->sig_settings_table = apr_hash_make(client->pool); client->cnt_agent_table = apr_hash_make(client->pool); + client->rtp_settings_table = apr_hash_make(client->pool); client->profile_table = apr_hash_make(client->pool); client->app_table = apr_hash_make(client->pool); @@ -326,20 +328,25 @@ MRCP_DECLARE(apt_bool_t) mrcp_client_codec_manager_register(mrcp_client_t *clien } /** Get registered codec manager */ -MRCP_DECLARE(const mpf_codec_manager_t*) mrcp_client_codec_manager_get(mrcp_client_t *client) +MRCP_DECLARE(const mpf_codec_manager_t*) mrcp_client_codec_manager_get(const 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) +MRCP_DECLARE(apt_bool_t) mrcp_client_media_engine_register(mrcp_client_t *client, mpf_engine_t *media_engine) { - if(!media_engine || !name) { + const char *id; + if(!media_engine) { + return FALSE; + } + id = mpf_engine_id_get(media_engine); + if(!id) { return FALSE; } - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Media Engine [%s]",name); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Media Engine [%s]",id); mpf_engine_codec_manager_register(media_engine,client->codec_manager); - apr_hash_set(client->media_engine_table,name,APR_HASH_KEY_STRING,media_engine); + apr_hash_set(client->media_engine_table,id,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); @@ -350,7 +357,7 @@ MRCP_DECLARE(apt_bool_t) mrcp_client_media_engine_register(mrcp_client_t *client } /** Get media engine by name */ -MRCP_DECLARE(mpf_engine_t*) mrcp_client_media_engine_get(mrcp_client_t *client, const char *name) +MRCP_DECLARE(mpf_engine_t*) mrcp_client_media_engine_get(const mrcp_client_t *client, const char *name) { return apr_hash_get(client->media_engine_table,name,APR_HASH_KEY_STRING); } @@ -367,22 +374,39 @@ MRCP_DECLARE(apt_bool_t) mrcp_client_rtp_factory_register(mrcp_client_t *client, } /** Get RTP termination factory by name */ -MRCP_DECLARE(mpf_termination_factory_t*) mrcp_client_rtp_factory_get(mrcp_client_t *client, const char *name) +MRCP_DECLARE(mpf_termination_factory_t*) mrcp_client_rtp_factory_get(const mrcp_client_t *client, const char *name) { return apr_hash_get(client->rtp_factory_table,name,APR_HASH_KEY_STRING); } +/** Register RTP settings */ +MRCP_DECLARE(apt_bool_t) mrcp_client_rtp_settings_register(mrcp_client_t *client, mpf_rtp_settings_t *rtp_settings, const char *name) +{ + if(!rtp_settings || !name) { + return FALSE; + } + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register RTP Settings [%s]",name); + apr_hash_set(client->rtp_settings_table,name,APR_HASH_KEY_STRING,rtp_settings); + return TRUE; +} + +/** Get RTP settings by name */ +MRCP_DECLARE(mpf_rtp_settings_t*) mrcp_client_rtp_settings_get(const mrcp_client_t *client, const char *name) +{ + return apr_hash_get(client->rtp_settings_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) +MRCP_DECLARE(apt_bool_t) mrcp_client_signaling_agent_register(mrcp_client_t *client, mrcp_sig_agent_t *signaling_agent) { - if(!signaling_agent || !name) { + if(!signaling_agent || !signaling_agent->id) { return FALSE; } - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Signaling Agent [%s]",name); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Signaling Agent [%s]",signaling_agent->id); 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); + apr_hash_set(client->sig_agent_table,signaling_agent->id,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); @@ -391,22 +415,45 @@ MRCP_DECLARE(apt_bool_t) mrcp_client_signaling_agent_register(mrcp_client_t *cli } /** Get signaling agent by name */ -MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_client_signaling_agent_get(mrcp_client_t *client, const char *name) +MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_client_signaling_agent_get(const mrcp_client_t *client, const char *name) { return apr_hash_get(client->sig_agent_table,name,APR_HASH_KEY_STRING); } +/** Register MRCP signaling settings */ +MRCP_DECLARE(apt_bool_t) mrcp_client_signaling_settings_register(mrcp_client_t *client, mrcp_sig_settings_t *signaling_settings, const char *name) +{ + if(!signaling_settings || !name) { + return FALSE; + } + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Signaling Settings [%s]",name); + apr_hash_set(client->sig_settings_table,name,APR_HASH_KEY_STRING,signaling_settings); + return TRUE; +} + +/** Get signaling settings by name */ +MRCP_DECLARE(mrcp_sig_settings_t*) mrcp_client_signaling_settings_get(const mrcp_client_t *client, const char *name) +{ + return apr_hash_get(client->sig_settings_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) +MRCP_DECLARE(apt_bool_t) mrcp_client_connection_agent_register(mrcp_client_t *client, mrcp_connection_agent_t *connection_agent) { - if(!connection_agent || !name) { + const char *id; + if(!connection_agent) { + return FALSE; + } + id = mrcp_client_connection_agent_id_get(connection_agent); + if(!id) { return FALSE; } - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Connection Agent [%s]",name); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Connection Agent [%s]",id); 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); + apr_hash_set(client->cnt_agent_table,id,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); @@ -416,7 +463,7 @@ MRCP_DECLARE(apt_bool_t) mrcp_client_connection_agent_register(mrcp_client_t *cl } /** Get connection agent by name */ -MRCP_DECLARE(mrcp_connection_agent_t*) mrcp_client_connection_agent_get(mrcp_client_t *client, const char *name) +MRCP_DECLARE(mrcp_connection_agent_t*) mrcp_client_connection_agent_get(const mrcp_client_t *client, const char *name) { return apr_hash_get(client->cnt_agent_table,name,APR_HASH_KEY_STRING); } @@ -428,14 +475,18 @@ MRCP_DECLARE(mrcp_profile_t*) mrcp_client_profile_create( mrcp_connection_agent_t *connection_agent, mpf_engine_t *media_engine, mpf_termination_factory_t *rtp_factory, + mpf_rtp_settings_t *rtp_settings, + mrcp_sig_settings_t *signaling_settings, 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->rtp_settings = rtp_settings; profile->signaling_agent = signaling_agent; profile->connection_agent = connection_agent; + profile->signaling_settings = signaling_settings; return profile; } @@ -459,13 +510,18 @@ MRCP_DECLARE(apt_bool_t) mrcp_client_profile_register(mrcp_client_t *client, mrc return FALSE; } + if(!profile->signaling_settings) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Register Profile [%s]: missing signaling settings",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) +MRCP_DECLARE(mrcp_profile_t*) mrcp_client_profile_get(const mrcp_client_t *client, const char *name) { return apr_hash_get(client->profile_table,name,APR_HASH_KEY_STRING); } @@ -484,421 +540,52 @@ MRCP_DECLARE(apt_bool_t) mrcp_client_application_register(mrcp_client_t *client, } /** Get memory pool */ -MRCP_DECLARE(apr_pool_t*) mrcp_client_memory_pool_get(mrcp_client_t *client) +MRCP_DECLARE(apr_pool_t*) mrcp_client_memory_pool_get(const 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) +/** Get directory layout */ +MRCP_DECLARE(apt_dir_layout_t*) mrcp_client_dir_layout_get(const mrcp_client_t *client) { - return application->obj; + return client->dir_layout; } -/** Get dir layout structure */ -MRCP_DECLARE(const apt_dir_layout_t*) mrcp_application_dir_layout_get(mrcp_application_t *application) +mrcp_client_session_t* mrcp_client_session_create(mrcp_client_t *client) { - 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; - } + 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)); - 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; + pool = session->base.pool; + session->base.name = apr_psprintf(pool,"0x%pp",session); session->base.response_vtable = &session_response_vtable; session->base.event_vtable = &session_event_vtable; - return &session->base; -} - -/** Get memory pool the session object is created out of */ -MRCP_DECLARE(apr_pool_t*) mrcp_application_session_pool_get(mrcp_session_t *session) -{ - if(!session) { - return NULL; - } - return session->pool; -} - -/** Get session identifier */ -MRCP_DECLARE(const apt_str_t*) mrcp_application_session_id_get(mrcp_session_t *session) -{ - if(!session) { - return NULL; - } - return &session->id; -} - -/** 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; -} - -/** Set (associate) external object to the session */ -MRCP_DECLARE(void) mrcp_application_session_object_set(mrcp_session_t *session, void *obj) -{ - mrcp_client_session_t *client_session = (mrcp_client_session_t*)session; - if(client_session) { - client_session->app_obj = 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_resource_t *resource; - mrcp_profile_t *profile; - mrcp_client_session_t *client_session = (mrcp_client_session_t*)session; - if(!client_session || !client_session->profile) { - /* Invalid params */ - return FALSE; - } - profile = client_session->profile; - - if(!profile->resource_factory) { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Channel: invalid profile"); - return FALSE; - } - resource = mrcp_resource_get(profile->resource_factory,resource_id); - if(!resource) { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Channel: no such resource"); - return FALSE; - } - - if(termination) { - /* Media engine and RTP factory must be specified in this case */ - if(!profile->media_engine || !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,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 NULL; - } - return channel->rtp_termination_slot->descriptor; -} - -/** Get codec descriptor of source stream */ -MRCP_DECLARE(const mpf_codec_descriptor_t*) mrcp_application_source_descriptor_get(mrcp_channel_t *channel) -{ - mpf_audio_stream_t *audio_stream; - if(!channel || !channel->termination) { - return NULL; - } - audio_stream = mpf_termination_audio_stream_get(channel->termination); - if(!audio_stream) { - return NULL; - } - return audio_stream->rx_descriptor; -} - -/** Get codec descriptor of sink stream */ -MRCP_DECLARE(const mpf_codec_descriptor_t*) mrcp_application_sink_descriptor_get(mrcp_channel_t *channel) -{ - mpf_audio_stream_t *audio_stream; - if(!channel || !channel->termination) { - return NULL; - } - audio_stream = mpf_termination_audio_stream_get(channel->termination); - if(!audio_stream) { - return NULL; - } - return audio_stream->tx_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 || !channel->resource) { - return NULL; - } - profile = client_session->profile; - if(!profile || !profile->resource_factory) { - return NULL; - } - mrcp_message = mrcp_request_create( - channel->resource, - profile->signaling_agent->mrcp_version, - method_id, - session->pool); - 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 audio termination - * @param session the session to create termination for - * @param stream_vtable the virtual table of audio stream - * @param capabilities the capabilities of the stream - * @param obj the external object - */ -MRCP_DECLARE(mpf_termination_t*) mrcp_application_audio_termination_create( - mrcp_session_t *session, - const mpf_audio_stream_vtable_t *stream_vtable, - mpf_stream_capabilities_t *capabilities, - void *obj) -{ - mpf_audio_stream_t *audio_stream; - - if(!capabilities) { - return NULL; - } - - if(mpf_codec_capabilities_validate(&capabilities->codecs) == FALSE) { - return NULL; - } - - /* create audio stream */ - audio_stream = mpf_audio_stream_create( - obj, /* object to associate */ - stream_vtable, /* virtual methods table of audio stream */ - capabilities, /* stream capabilities */ - session->pool); /* memory pool to allocate memory from */ - if(!audio_stream) { - return NULL; - } - - /* 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 */ -} - -/** 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_stream_capabilities_t *capabilities; - mpf_audio_stream_t *audio_stream; - - capabilities = mpf_source_stream_capabilities_create(session->pool); - if(codec_descriptor) { - mpf_codec_capabilities_add( - &capabilities->codecs, - mpf_sample_rate_mask_get(codec_descriptor->sampling_rate), - codec_descriptor->name.buf); - } - else { - mpf_codec_default_capabilities_add(&capabilities->codecs); - } - - /* create audio stream */ - audio_stream = mpf_audio_stream_create( - obj, /* object to associate */ - stream_vtable, /* virtual methods table of audio stream */ - capabilities, /* stream capabilities */ - session->pool); /* memory pool to allocate memory from */ - - if(!audio_stream) { - return NULL; - } - - audio_stream->rx_descriptor = codec_descriptor; - - /* 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_stream_capabilities_t *capabilities; - mpf_audio_stream_t *audio_stream; - - capabilities = mpf_sink_stream_capabilities_create(session->pool); - if(codec_descriptor) { - mpf_codec_capabilities_add( - &capabilities->codecs, - mpf_sample_rate_mask_get(codec_descriptor->sampling_rate), - codec_descriptor->name.buf); - } - else { - mpf_codec_default_capabilities_add(&capabilities->codecs); - } - - /* create audio stream */ - audio_stream = mpf_audio_stream_create( - obj, /* object to associate */ - stream_vtable, /* virtual methods table of audio stream */ - capabilities, /* stream capabilities */ - session->pool); /* memory pool to allocate memory from */ - if(!audio_stream) { - return NULL; - } - - audio_stream->tx_descriptor = codec_descriptor; - - /* 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 */ + session->application = NULL; + session->app_obj = NULL; + session->profile = NULL; + session->context = NULL; + session->codec_manager = client->codec_manager; + 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->mpf_task_msg = NULL; + session->subrequest_count = 0; + session->state = SESSION_STATE_NONE; + session->status = MRCP_SIG_STATUS_CODE_SUCCESS; + return session; } 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)); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Add MRCP Handle "APT_NAMESID_FMT, + session->base.name, + MRCP_SESSION_SID(&session->base)); apr_hash_set(client->session_table,session,sizeof(session),session); } } @@ -906,7 +593,9 @@ void mrcp_client_session_add(mrcp_client_t *client, mrcp_client_session_t *sessi 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)); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remove MRCP Handle "APT_NAMESID_FMT, + session->base.name, + MRCP_SESSION_SID(&session->base)); apr_hash_set(client->session_table,session,sizeof(session),NULL); } } @@ -946,7 +635,6 @@ static apt_bool_t mrcp_client_msg_process(apt_task_t *task, apt_task_msg_t *msg) 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); @@ -971,7 +659,6 @@ static apt_bool_t mrcp_client_msg_process(apt_task_t *task, apt_task_msg_t *msg) 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); @@ -996,27 +683,25 @@ static apt_bool_t mrcp_client_msg_process(apt_task_t *task, apt_task_msg_t *msg) case MRCP_CLIENT_MEDIA_TASK_MSG: { mpf_message_container_t *container = (mpf_message_container_t*) msg->data; - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Receive Media Task Message"); mrcp_client_mpf_message_process(container); 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); + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Task Message Received [%d;%d]", msg->type,msg->sub_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) +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; @@ -1035,11 +720,10 @@ static apt_bool_t mrcp_app_signaling_task_msg_signal(mrcp_sig_command_e command_ 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) +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; @@ -1057,7 +741,6 @@ static apt_bool_t mrcp_app_control_task_msg_signal(mrcp_session_t *session, mrcp 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); } @@ -1072,7 +755,6 @@ static apt_bool_t mrcp_client_signaling_task_msg_signal(sig_agent_task_msg_type_ 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); } @@ -1101,12 +783,10 @@ static apt_bool_t mrcp_client_connection_task_msg_signal( 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); diff --git a/libs/unimrcp/libs/mrcp-client/src/mrcp_client_session.c b/libs/unimrcp/libs/mrcp-client/src/mrcp_client_session.c index a2659e0f3c..b7c8db3bb7 100644 --- a/libs/unimrcp/libs/mrcp-client/src/mrcp_client_session.c +++ b/libs/unimrcp/libs/mrcp-client/src/mrcp_client_session.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_client_session.c 1799 2011-05-12 02:32:32Z achaloyan $ */ #include "mrcp_client_session.h" @@ -29,6 +31,10 @@ #include "apt_obj_list.h" #include "apt_log.h" +/** Macro to log session name and identifier */ +#define MRCP_SESSION_NAMESID(session) \ + session->base.name, MRCP_SESSION_SID(&session->base) + 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); @@ -88,41 +94,17 @@ static mrcp_app_message_t* mrcp_client_app_response_create(const mrcp_app_messag } -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->mpf_task_msg = NULL; - session->subrequest_count = 0; - session->state = SESSION_STATE_NONE; - session->status = MRCP_SIG_STATUS_CODE_SUCCESS; - return session; -} - mrcp_channel_t* mrcp_client_channel_create( - mrcp_session_t *session, + mrcp_client_session_t *session, mrcp_resource_t *resource, 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; + mrcp_channel_t *channel = apr_palloc(session->base.pool,sizeof(mrcp_channel_t)); + channel->pool = session->base.pool; channel->obj = obj; - channel->session = session; + channel->session = &session->base; channel->control_channel = NULL; channel->termination = termination; channel->rtp_termination_slot = NULL; @@ -131,7 +113,7 @@ mrcp_channel_t* mrcp_client_channel_create( channel->waiting_for_termination = FALSE; if(rtp_descriptor) { - rtp_termination_slot_t *termination_slot = apr_palloc(session->pool,sizeof(rtp_termination_slot_t)); + rtp_termination_slot_t *termination_slot = apr_palloc(channel->pool,sizeof(rtp_termination_slot_t)); termination_slot->descriptor = rtp_descriptor; termination_slot->termination = NULL; termination_slot->waiting = FALSE; @@ -139,7 +121,8 @@ mrcp_channel_t* mrcp_client_channel_create( termination_slot->id = 0; channel->rtp_termination_slot = termination_slot; } - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create Channel "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(session)); + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->base.log_obj,"Create Channel "APT_NAMESID_FMT, + MRCP_SESSION_NAMESID(session)); return channel; } @@ -149,14 +132,15 @@ apt_bool_t mrcp_client_session_answer_process(mrcp_client_session_t *session, mr return FALSE; } if(!descriptor) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive Answer "APT_PTRSID_FMT" [null descriptor]", MRCP_SESSION_PTRSID(&session->base)); + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->base.log_obj,"Receive Answer "APT_NAMESID_FMT" [null descriptor]", + MRCP_SESSION_NAMESID(session)); session->status = MRCP_SIG_STATUS_CODE_FAILURE; /* raise app response */ return mrcp_app_sig_response_raise(session,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), + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->base.log_obj,"Receive Answer "APT_NAMESID_FMT" [c:%d a:%d v:%d]", + MRCP_SESSION_NAMESID(session), descriptor->control_media_arr->nelts, descriptor->audio_media_arr->nelts, descriptor->video_media_arr->nelts); @@ -207,7 +191,7 @@ apt_bool_t mrcp_client_session_answer_process(mrcp_client_session_t *session, mr 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)); + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->base.log_obj,"Session Terminated "APT_NAMESID_FMT, MRCP_SESSION_NAMESID(session)); if(mrcp_client_session_subrequest_remove(session) == TRUE) { mrcp_app_session_terminate_raise(session,MRCP_SIG_STATUS_CODE_SUCCESS); @@ -220,7 +204,8 @@ apt_bool_t mrcp_client_session_terminate_event_process(mrcp_client_session_t *se if(session->state == SESSION_STATE_TERMINATING) { /* session termination request has been sent, still waiting for the response, all the events must be ignored at this stage */ - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unexpected Event! "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base)); + apt_obj_log(APT_LOG_MARK,APT_PRIO_WARNING,session->base.log_obj,"Unexpected Event! "APT_NAMESID_FMT, + MRCP_SESSION_NAMESID(session)); return FALSE; } @@ -266,7 +251,7 @@ apt_bool_t mrcp_client_session_control_response_process(mrcp_client_session_t *s 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)); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Resources Discovered %s", session->base.name); if(!session->active_request) { return FALSE; } @@ -288,13 +273,16 @@ apt_bool_t mrcp_client_session_discover_response_process(mrcp_client_session_t * control_media->resource_name = descriptor->resource_name; } } + else { + session->answer = descriptor; + } if(mrcp_client_session_subrequest_remove(session) == TRUE) { 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)); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Raise App Resource Discovery Response %s", session->base.name); session->application->handler(response); session->active_request = apt_list_pop_front(session->request_queue); @@ -308,7 +296,9 @@ apt_bool_t mrcp_client_session_discover_response_process(mrcp_client_session_t * 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)); + apt_obj_log(APT_LOG_MARK,APT_PRIO_DEBUG,session->base.log_obj,"Control Channel Added "APT_NAMESIDRES_FMT, + MRCP_SESSION_NAMESID(session), + channel->resource->name.buf); if(!channel->waiting_for_channel) { return FALSE; } @@ -323,7 +313,9 @@ apt_bool_t mrcp_client_on_channel_add(mrcp_channel_t *channel, mrcp_control_desc 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)); + apt_obj_log(APT_LOG_MARK,APT_PRIO_DEBUG,session->base.log_obj,"Control Channel Modified "APT_NAMESIDRES_FMT, + MRCP_SESSION_NAMESID(session), + channel->resource->name.buf); if(!channel->waiting_for_channel) { return FALSE; } @@ -341,7 +333,9 @@ apt_bool_t mrcp_client_on_channel_modify(mrcp_channel_t *channel, mrcp_control_d 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)); + apt_obj_log(APT_LOG_MARK,APT_PRIO_DEBUG,session->base.log_obj,"Control Channel Removed "APT_NAMESIDRES_FMT, + MRCP_SESSION_NAMESID(session), + channel->resource->name.buf); if(!channel->waiting_for_channel) { return FALSE; } @@ -395,16 +389,18 @@ 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), + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->base.log_obj,"Receive App Request "APT_NAMESID_FMT" [%d]", + MRCP_SESSION_NAMESID(session), 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)); + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->base.log_obj,"Receive App MRCP Request "APT_NAMESID_FMT, + MRCP_SESSION_NAMESID(session)); } 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_obj_log(APT_LOG_MARK,APT_PRIO_DEBUG,session->base.log_obj,"Push Request to Queue "APT_NAMESID_FMT, + MRCP_SESSION_NAMESID(session)); apt_list_push_back(session->request_queue,app_message,session->base.pool); return TRUE; } @@ -417,11 +413,13 @@ apt_bool_t mrcp_client_app_message_process(mrcp_app_message_t *app_message) 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), + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->base.log_obj,"Send Offer "APT_NAMESID_FMT" [c:%d a:%d v:%d] to %s:%hu", + MRCP_SESSION_NAMESID(session), descriptor->control_media_arr->nelts, descriptor->audio_media_arr->nelts, - descriptor->video_media_arr->nelts); + descriptor->video_media_arr->nelts, + session->profile->signaling_settings->server_ip, + session->profile->signaling_settings->server_port); return mrcp_session_offer(&session->base,descriptor); } @@ -456,8 +454,8 @@ static apt_bool_t mrcp_app_sig_response_raise(mrcp_client_session_t *session, ap } session->active_request = NULL; response = mrcp_client_app_response_create(request,session->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), + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->base.log_obj,"Raise App Response "APT_NAMESID_FMT" [%d] %s [%d]", + MRCP_SESSION_NAMESID(session), response->sig_message.command_id, session->status == MRCP_SIG_STATUS_CODE_SUCCESS ? "SUCCESS" : "FAILURE", session->status); @@ -482,8 +480,8 @@ static apt_bool_t mrcp_app_sig_event_raise(mrcp_client_session_t *session, mrcp_ 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), + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->base.log_obj,"Raise App Event "APT_NAMESID_FMT" [%d]", + MRCP_SESSION_NAMESID(session), app_event->sig_message.event_id); return session->application->handler(app_event); } @@ -501,7 +499,8 @@ static apt_bool_t mrcp_app_control_message_raise(mrcp_client_session_t *session, 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)); + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->base.log_obj,"Raise App MRCP Response "APT_NAMESID_FMT, + MRCP_SESSION_NAMESID(session)); session->application->handler(response); session->active_request = apt_list_pop_front(session->request_queue); @@ -516,7 +515,8 @@ static apt_bool_t mrcp_app_control_message_raise(mrcp_client_session_t *session, 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)); + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->base.log_obj,"Raise App MRCP Event "APT_NAMESID_FMT, + MRCP_SESSION_NAMESID(session)); session->application->handler(app_message); } return TRUE; @@ -532,8 +532,8 @@ static apt_bool_t mrcp_app_failure_message_raise(mrcp_client_session_t *session) session->active_request = NULL; response = mrcp_client_app_response_create(request,session->status,session->base.pool); if(response->message_type == MRCP_APP_MESSAGE_TYPE_SIGNALING) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Raise App Response "APT_PTRSID_FMT" [%d] %s [%d]", - MRCP_SESSION_PTRSID(&session->base), + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->base.log_obj,"Raise App Response "APT_NAMESID_FMT" [%d] %s [%d]", + MRCP_SESSION_NAMESID(session), response->sig_message.command_id, session->status == MRCP_SIG_STATUS_CODE_SUCCESS ? "SUCCESS" : "FAILURE", session->status); @@ -542,7 +542,8 @@ static apt_bool_t mrcp_app_failure_message_raise(mrcp_client_session_t *session) mrcp_message_t *mrcp_response = mrcp_response_create(response->control_message,response->control_message->pool); mrcp_response->start_line.status_code = MRCP_STATUS_CODE_METHOD_FAILED; response->control_message = mrcp_response; - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Raise App MRCP Response "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base)); + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->base.log_obj,"Raise App MRCP Response "APT_NAMESID_FMT, + MRCP_SESSION_NAMESID(session)); } session->application->handler(response); return TRUE; @@ -612,15 +613,16 @@ static apt_bool_t mrcp_client_message_send(mrcp_client_session_t *session, mrcp_ 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)); + apt_obj_log(APT_LOG_MARK,APT_PRIO_DEBUG,session->base.log_obj,"Raise App Failure MRCP Response "APT_NAMESID_FMT, + MRCP_SESSION_NAMESID(session)); 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" [%"MRCP_REQUEST_ID_FMT"]", - MRCP_SESSION_PTRSID(&session->base), + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->base.log_obj,"Send MRCP Request "APT_NAMESIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_SESSION_NAMESID(session), channel->resource->name.buf, message->start_line.request_id); @@ -646,8 +648,8 @@ static apt_bool_t mrcp_client_channel_modify(mrcp_client_session_t *session, mrc return FALSE; } - apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Modify Control Channel "APT_PTRSIDRES_FMT" [%d]", - MRCP_SESSION_PTRSID(&session->base), + apt_obj_log(APT_LOG_MARK,APT_PRIO_NOTICE,session->base.log_obj,"Modify Control Channel "APT_NAMESIDRES_FMT" [%d]", + MRCP_SESSION_NAMESID(session), channel->resource->name.buf, enable); if(mrcp_client_channel_find(session,channel,&index) == TRUE) { @@ -704,6 +706,7 @@ static apt_bool_t mrcp_client_channel_add(mrcp_client_session_t *session, mrcp_c mrcp_control_descriptor_t *control_media; if(!channel->control_channel) { channel->control_channel = mrcp_client_control_channel_create(profile->connection_agent,channel,pool); + mrcp_client_control_channel_log_obj_set(channel->control_channel,session->base.log_obj); } control_media = mrcp_control_offer_create(pool); control_media->id = mrcp_session_control_media_add(session->offer,control_media); @@ -715,8 +718,8 @@ static apt_bool_t mrcp_client_channel_add(mrcp_client_session_t *session, mrcp_c } } - apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Add Control Channel "APT_PTRSIDRES_FMT, - MRCP_SESSION_PTRSID(&session->base), + apt_obj_log(APT_LOG_MARK,APT_PRIO_NOTICE,session->base.log_obj,"Add Control Channel "APT_NAMESIDRES_FMT, + MRCP_SESSION_NAMESID(session), channel->resource->name.buf); /* add control channel */ APR_ARRAY_PUSH(session->channels,mrcp_channel_t*) = channel; @@ -736,8 +739,14 @@ static apt_bool_t mrcp_client_channel_add(mrcp_client_session_t *session, mrcp_c if(!session->context) { /* create media context first */ - session->context = mpf_engine_context_create(profile->media_engine,session,5,pool); + session->context = mpf_engine_context_create( + profile->media_engine, + session->base.name, + session,5,pool); } + apt_obj_log(APT_LOG_MARK,APT_PRIO_DEBUG,session->base.log_obj,"Add Media Termination "APT_NAMESIDRES_FMT, + MRCP_SESSION_NAMESID(session), + mpf_termination_name_get(channel->termination)); if(mpf_engine_termination_message_add( profile->media_engine, MPF_ADD_TERMINATION,session->context,channel->termination,NULL, @@ -749,6 +758,7 @@ static apt_bool_t mrcp_client_channel_add(mrcp_client_session_t *session, mrcp_c /* initialize rtp descriptor */ rtp_descriptor = apr_palloc(pool,sizeof(mpf_rtp_termination_descriptor_t)); mpf_rtp_termination_descriptor_init(rtp_descriptor); + rtp_descriptor->audio.settings = profile->rtp_settings; audio_stream = mpf_termination_audio_stream_get(channel->termination); if(audio_stream) { mpf_rtp_media_descriptor_t *media; @@ -759,10 +769,12 @@ static apt_bool_t mrcp_client_channel_add(mrcp_client_session_t *session, mrcp_c rtp_descriptor->audio.local = media; } - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add RTP Termination "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base)); /* create rtp termination */ termination = mpf_termination_create(profile->rtp_termination_factory,session,pool); slot->termination = termination; + apt_obj_log(APT_LOG_MARK,APT_PRIO_DEBUG,session->base.log_obj,"Add Media Termination "APT_NAMESIDRES_FMT, + MRCP_SESSION_NAMESID(session), + mpf_termination_name_get(termination)); /* send add termination request (add to media context) */ if(mpf_engine_termination_message_add( @@ -805,7 +817,8 @@ 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)); + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->base.log_obj,"Update Session "APT_NAMESID_FMT, + MRCP_SESSION_NAMESID(session)); return mrcp_client_session_offer_send(session); } @@ -816,7 +829,8 @@ static apt_bool_t mrcp_client_session_terminate(mrcp_client_session_t *session) 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)); + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->base.log_obj,"Terminate Session "APT_NAMESID_FMT, + MRCP_SESSION_NAMESID(session)); profile = session->profile; mrcp_client_session_state_set(session,SESSION_STATE_TERMINATING); @@ -837,7 +851,8 @@ static apt_bool_t mrcp_client_session_terminate(mrcp_client_session_t *session) 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)); + apt_obj_log(APT_LOG_MARK,APT_PRIO_DEBUG,session->base.log_obj,"Remove Control Channel "APT_NAMESID_FMT, + MRCP_SESSION_NAMESID(session)); if(mrcp_client_control_channel_remove(channel->control_channel) == TRUE) { channel->waiting_for_channel = TRUE; mrcp_client_session_subrequest_add(session); @@ -846,7 +861,9 @@ static apt_bool_t mrcp_client_session_terminate(mrcp_client_session_t *session) /* 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)); + apt_obj_log(APT_LOG_MARK,APT_PRIO_DEBUG,session->base.log_obj,"Subtract Media Termination "APT_NAMESIDRES_FMT, + MRCP_SESSION_NAMESID(session), + mpf_termination_name_get(channel->termination)); if(mpf_engine_termination_message_add( profile->media_engine, MPF_SUBTRACT_TERMINATION,session->context,channel->termination,NULL, @@ -865,7 +882,9 @@ static apt_bool_t mrcp_client_session_terminate(mrcp_client_session_t *session) 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)); + apt_obj_log(APT_LOG_MARK,APT_PRIO_DEBUG,session->base.log_obj,"Subtract Media Termination "APT_NAMESIDRES_FMT, + MRCP_SESSION_NAMESID(session), + mpf_termination_name_get(slot->termination)); if(mpf_engine_termination_message_add( profile->media_engine, MPF_SUBTRACT_TERMINATION,session->context,slot->termination,NULL, @@ -887,7 +906,7 @@ 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)); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Discover Resources "APT_PTR_FMT, MRCP_SESSION_PTR(&session->base)); session->answer = NULL; mrcp_client_session_state_set(session,SESSION_STATE_DISCOVERING); @@ -925,6 +944,9 @@ static apt_bool_t mrcp_client_on_termination_add(mrcp_client_session_t *session, if(!session) { return FALSE; } + apt_obj_log(APT_LOG_MARK,APT_PRIO_DEBUG,session->base.log_obj,"Media Termination Added "APT_NAMESIDRES_FMT, + MRCP_SESSION_NAMESID(session), + mpf_termination_name_get(mpf_message->termination)); termination_slot = mrcp_client_rtp_termination_find(session,mpf_message->termination); if(termination_slot) { /* rtp termination */ @@ -966,6 +988,9 @@ static apt_bool_t mrcp_client_on_termination_modify(mrcp_client_session_t *sessi if(!session) { return FALSE; } + apt_obj_log(APT_LOG_MARK,APT_PRIO_DEBUG,session->base.log_obj,"Media Termination Modified "APT_NAMESIDRES_FMT, + MRCP_SESSION_NAMESID(session), + mpf_termination_name_get(mpf_message->termination)); termination_slot = mrcp_client_rtp_termination_find(session,mpf_message->termination); if(termination_slot) { /* rtp termination */ @@ -995,6 +1020,9 @@ static apt_bool_t mrcp_client_on_termination_subtract(mrcp_client_session_t *ses if(!session) { return FALSE; } + apt_obj_log(APT_LOG_MARK,APT_PRIO_DEBUG,session->base.log_obj,"Media Termination Subtracted "APT_NAMESIDRES_FMT, + MRCP_SESSION_NAMESID(session), + mpf_termination_name_get(mpf_message->termination)); termination_slot = mrcp_client_rtp_termination_find(session,mpf_message->termination); if(termination_slot) { /* rtp termination */ @@ -1036,15 +1064,12 @@ apt_bool_t mrcp_client_mpf_message_process(mpf_message_container_t *mpf_message_ if(mpf_message->message_type == MPF_MESSAGE_TYPE_RESPONSE) { switch(mpf_message->command_id) { case MPF_ADD_TERMINATION: - 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_MODIFY_TERMINATION: - 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_SUBTRACT_TERMINATION: - 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; case MPF_ADD_ASSOCIATION: @@ -1068,7 +1093,8 @@ apt_bool_t mrcp_client_mpf_message_process(mpf_message_container_t *mpf_message_ } } 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)); + apt_obj_log(APT_LOG_MARK,APT_PRIO_DEBUG,session->base.log_obj,"Process MPF Event "APT_NAMESID_FMT, + MRCP_SESSION_NAMESID(session)); } } return TRUE; @@ -1117,7 +1143,8 @@ static apt_bool_t mrcp_client_control_media_answer_process(mrcp_client_session_t /* 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)); + apt_obj_log(APT_LOG_MARK,APT_PRIO_DEBUG,session->base.log_obj,"Modify Control Channel "APT_NAMESID_FMT, + MRCP_SESSION_NAMESID(session)); if(mrcp_client_control_channel_modify(channel->control_channel,control_descriptor) == TRUE) { channel->waiting_for_channel = TRUE; mrcp_client_session_subrequest_add(session); @@ -1157,7 +1184,9 @@ static apt_bool_t mrcp_client_av_media_answer_process(mrcp_client_session_t *ses 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)); + apt_obj_log(APT_LOG_MARK,APT_PRIO_DEBUG,session->base.log_obj,"Modify Media Termination "APT_NAMESIDRES_FMT, + MRCP_SESSION_NAMESID(session), + mpf_termination_name_get(slot->termination)); if(mpf_engine_termination_message_add( session->profile->media_engine, MPF_MODIFY_TERMINATION,session->context,slot->termination,rtp_descriptor, @@ -1183,15 +1212,15 @@ static apt_bool_t mrcp_app_request_dispatch(mrcp_client_session_t *session, cons if(session->state == SESSION_STATE_TERMINATING) { /* no more requests are allowed, as session is being terminated! just return, it is horribly wrong and can crash anytime here */ - apt_log(APT_LOG_MARK,APT_PRIO_ERROR,"Inappropriate Application Request "APT_PTRSID_FMT" [%d]", - MRCP_SESSION_PTRSID(&session->base), + apt_obj_log(APT_LOG_MARK,APT_PRIO_ERROR,session->base.log_obj,"Inappropriate Application Request "APT_NAMESID_FMT" [%d]", + MRCP_SESSION_NAMESID(session), app_message->sig_message.command_id); return FALSE; } if(session->registered == FALSE) { session->base.signaling_agent = session->profile->signaling_agent; - session->base.signaling_agent->create_client_session(&session->base); + session->base.signaling_agent->create_client_session(&session->base,session->profile->signaling_settings); mrcp_client_session_add(session->application->client,session); session->registered = TRUE; @@ -1200,8 +1229,8 @@ static apt_bool_t mrcp_app_request_dispatch(mrcp_client_session_t *session, cons 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), + apt_obj_log(APT_LOG_MARK,APT_PRIO_DEBUG,session->base.log_obj,"Dispatch App Request "APT_NAMESID_FMT" [%d]", + MRCP_SESSION_NAMESID(session), app_message->sig_message.command_id); switch(app_message->sig_message.command_id) { case MRCP_SIG_COMMAND_SESSION_UPDATE: @@ -1232,90 +1261,3 @@ static apt_bool_t mrcp_app_request_dispatch(mrcp_client_session_t *session, cons } 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_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; -} diff --git a/libs/unimrcp/libs/mrcp-engine/Makefile.am b/libs/unimrcp/libs/mrcp-engine/Makefile.am index 74bac2d06b..f30e21a2bd 100644 --- a/libs/unimrcp/libs/mrcp-engine/Makefile.am +++ b/libs/unimrcp/libs/mrcp-engine/Makefile.am @@ -18,13 +18,15 @@ include_HEADERS = include/mrcp_engine_types.h \ include/mrcp_synth_engine.h \ include/mrcp_recog_engine.h \ include/mrcp_recorder_engine.h \ + include/mrcp_verifier_engine.h \ include/mrcp_resource_engine.h \ include/mrcp_engine_factory.h \ include/mrcp_engine_loader.h \ include/mrcp_state_machine.h \ include/mrcp_synth_state_machine.h \ include/mrcp_recog_state_machine.h \ - include/mrcp_recorder_state_machine.h + include/mrcp_recorder_state_machine.h \ + include/mrcp_verifier_state_machine.h libmrcpengine_la_SOURCES = src/mrcp_engine_iface.c \ src/mrcp_engine_impl.c \ @@ -32,4 +34,5 @@ libmrcpengine_la_SOURCES = src/mrcp_engine_iface.c \ src/mrcp_engine_loader.c \ src/mrcp_synth_state_machine.c \ src/mrcp_recog_state_machine.c \ - src/mrcp_recorder_state_machine.c + src/mrcp_recorder_state_machine.c \ + src/mrcp_verifier_state_machine.c diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_factory.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_factory.h index ac8ccd78da..b86192eff6 100644 --- a/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_factory.h +++ b/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_engine_factory.h 1710 2010-05-24 17:36:19Z achaloyan $ */ -#ifndef __MRCP_ENGINE_FACTORY_H__ -#define __MRCP_ENGINE_FACTORY_H__ +#ifndef MRCP_ENGINE_FACTORY_H +#define MRCP_ENGINE_FACTORY_H /** * @file mrcp_engine_factory.h @@ -43,15 +45,18 @@ MRCP_DECLARE(apt_bool_t) mrcp_engine_factory_close(mrcp_engine_factory_t *factor /** Register engine */ -MRCP_DECLARE(apt_bool_t) mrcp_engine_factory_engine_register(mrcp_engine_factory_t *factory, mrcp_engine_t *engine, const char *name); +MRCP_DECLARE(apt_bool_t) mrcp_engine_factory_engine_register(mrcp_engine_factory_t *factory, mrcp_engine_t *engine); /** Get engine by name */ -MRCP_DECLARE(mrcp_engine_t*) mrcp_engine_factory_engine_get(mrcp_engine_factory_t *factory, const char *name); +MRCP_DECLARE(mrcp_engine_t*) mrcp_engine_factory_engine_get(const mrcp_engine_factory_t *factory, const char *name); /** Find engine by resource identifier */ -MRCP_DECLARE(mrcp_engine_t*) mrcp_engine_factory_engine_find(mrcp_engine_factory_t *factory, mrcp_resource_id resource_id); +MRCP_DECLARE(mrcp_engine_t*) mrcp_engine_factory_engine_find(const mrcp_engine_factory_t *factory, mrcp_resource_id resource_id); + +/** Start iterating over the engines in a factory */ +MRCP_DECLARE(apr_hash_index_t*) mrcp_engine_factory_engine_first(const mrcp_engine_factory_t *factory); APT_END_EXTERN_C -#endif /*__MRCP_ENGINE_FACTORY_H__*/ +#endif /* MRCP_ENGINE_FACTORY_H */ diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_iface.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_iface.h index ee123fee0f..e602b7d836 100644 --- a/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_iface.h +++ b/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_iface.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_engine_iface.h 1677 2010-05-01 18:45:50Z achaloyan $ */ -#ifndef __MRCP_ENGINE_IFACE_H__ -#define __MRCP_ENGINE_IFACE_H__ +#ifndef MRCP_ENGINE_IFACE_H +#define MRCP_ENGINE_IFACE_H /** * @file mrcp_engine_iface.h @@ -27,30 +29,20 @@ APT_BEGIN_EXTERN_C /** Destroy engine */ -static APR_INLINE apt_bool_t mrcp_engine_virtual_destroy(mrcp_engine_t *engine) -{ - return engine->method_vtable->destroy(engine); -} +apt_bool_t mrcp_engine_virtual_destroy(mrcp_engine_t *engine); /** Open engine */ -static APR_INLINE apt_bool_t mrcp_engine_virtual_open(mrcp_engine_t *engine) -{ - if(engine->is_open == FALSE) { - engine->is_open = engine->method_vtable->open(engine); - return engine->is_open; - } - return FALSE; -} +apt_bool_t mrcp_engine_virtual_open(mrcp_engine_t *engine); + +/** Response to open engine request */ +void mrcp_engine_on_open(mrcp_engine_t *engine, apt_bool_t status); /** Close engine */ -static APR_INLINE apt_bool_t mrcp_engine_virtual_close(mrcp_engine_t *engine) -{ - if(engine->is_open == TRUE) { - engine->is_open = FALSE; - return engine->method_vtable->close(engine); - } - return FALSE; -} +apt_bool_t mrcp_engine_virtual_close(mrcp_engine_t *engine); + +/** Response to close engine request */ +void mrcp_engine_on_close(mrcp_engine_t *engine); + /** Create engine channel */ mrcp_engine_channel_t* mrcp_engine_channel_virtual_create(mrcp_engine_t *engine, mrcp_version_e mrcp_version, apr_pool_t *pool); @@ -90,4 +82,4 @@ mrcp_engine_config_t* mrcp_engine_config_alloc(apr_pool_t *pool); APT_END_EXTERN_C -#endif /*__MRCP_ENGINE_IFACE_H__*/ +#endif /* MRCP_ENGINE_IFACE_H */ diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_impl.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_impl.h index 32de2ad6b2..915d1e53f5 100644 --- a/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_impl.h +++ b/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_engine_impl.h 1710 2010-05-24 17:36:19Z achaloyan $ */ -#ifndef __MRCP_ENGINE_IMPL_H__ -#define __MRCP_ENGINE_IMPL_H__ +#ifndef MRCP_ENGINE_IMPL_H +#define MRCP_ENGINE_IMPL_H /** * @file mrcp_engine_impl.h @@ -34,6 +36,18 @@ mrcp_engine_t* mrcp_engine_create( const mrcp_engine_method_vtable_t *vtable, apr_pool_t *pool); +/** Send engine open response */ +static APR_INLINE apt_bool_t mrcp_engine_open_respond(mrcp_engine_t *engine, apt_bool_t status) +{ + return engine->event_vtable->on_open(engine,status); +} + +/** Send engine close response */ +static APR_INLINE apt_bool_t mrcp_engine_close_respond(mrcp_engine_t *engine) +{ + return engine->event_vtable->on_close(engine); +} + /** Get engine config */ const mrcp_engine_config_t* mrcp_engine_config_get(const mrcp_engine_t *engine); @@ -104,18 +118,18 @@ static APR_INLINE const char* mrcp_engine_channel_id_get(mrcp_engine_channel_t * } /** Get MRCP version channel is created in the scope of */ -static APR_INLINE mrcp_version_e mrcp_engine_channel_version_get(mrcp_engine_channel_t *channel) +static APR_INLINE mrcp_version_e mrcp_engine_channel_version_get(const mrcp_engine_channel_t *channel) { return channel->mrcp_version; } /** Get codec descriptor of the audio source stream */ -const mpf_codec_descriptor_t* mrcp_engine_source_stream_codec_get(mrcp_engine_channel_t *channel); +const mpf_codec_descriptor_t* mrcp_engine_source_stream_codec_get(const mrcp_engine_channel_t *channel); /** Get codec descriptor of the audio sink stream */ -const mpf_codec_descriptor_t* mrcp_engine_sink_stream_codec_get(mrcp_engine_channel_t *channel); +const mpf_codec_descriptor_t* mrcp_engine_sink_stream_codec_get(const mrcp_engine_channel_t *channel); APT_END_EXTERN_C -#endif /*__MRCP_ENGINE_IMPL_H__*/ +#endif /* MRCP_ENGINE_IMPL_H */ diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_loader.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_loader.h index a4fc9d2e39..f6a47b8fa2 100644 --- a/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_loader.h +++ b/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_loader.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_engine_loader.h 1700 2010-05-21 18:56:06Z achaloyan $ */ -#ifndef __MRCP_ENGINE_LOADER_H__ -#define __MRCP_ENGINE_LOADER_H__ +#ifndef MRCP_ENGINE_LOADER_H +#define MRCP_ENGINE_LOADER_H /** * @file mrcp_engine_loader.h @@ -40,9 +42,13 @@ MRCP_DECLARE(apt_bool_t) mrcp_engine_loader_plugins_unload(mrcp_engine_loader_t /** Load engine plugin */ -MRCP_DECLARE(mrcp_engine_t*) mrcp_engine_loader_plugin_load(mrcp_engine_loader_t *loader, const char *path, const char *name); +MRCP_DECLARE(mrcp_engine_t*) mrcp_engine_loader_plugin_load( + mrcp_engine_loader_t *loader, + const char *id, + const char *path, + mrcp_engine_config_t *config); APT_END_EXTERN_C -#endif /*__MRCP_ENGINE_LOADER_H__*/ +#endif /* MRCP_ENGINE_LOADER_H */ diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_plugin.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_plugin.h index afa5e334c3..50a5391ef3 100644 --- a/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_plugin.h +++ b/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_plugin.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_engine_plugin.h 1724 2010-06-02 18:42:20Z achaloyan $ */ -#ifndef __MRCP_ENGINE_PLUGIN_H__ -#define __MRCP_ENGINE_PLUGIN_H__ +#ifndef MRCP_ENGINE_PLUGIN_H +#define MRCP_ENGINE_PLUGIN_H /** * @file mrcp_engine_plugin.h @@ -64,13 +66,13 @@ typedef apt_bool_t (*mrcp_plugin_log_accessor_f)(apt_logger_t *logger); * plugins such as structure size changes. No binary compatibility is * possible across a change in the major version. */ -#define PLUGIN_MAJOR_VERSION 0 +#define PLUGIN_MAJOR_VERSION 1 /** minor version * Minor API changes that do not cause binary compatibility problems. * Reset to 0 when upgrading PLUGIN_MAJOR_VERSION */ -#define PLUGIN_MINOR_VERSION 6 +#define PLUGIN_MINOR_VERSION 0 /** patch level * The Patch Level never includes API changes, simply bug fixes. @@ -113,4 +115,4 @@ static APR_INLINE int mrcp_plugin_version_check(mrcp_plugin_version_t *version) APT_END_EXTERN_C -#endif /*__MRCP_ENGINE_PLUGIN_H__*/ +#endif /* MRCP_ENGINE_PLUGIN_H */ diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_types.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_types.h index eec9ec89a5..2187d19829 100644 --- a/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_types.h +++ b/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_types.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_engine_types.h 1700 2010-05-21 18:56:06Z achaloyan $ */ -#ifndef __MRCP_ENGINE_TYPES_H__ -#define __MRCP_ENGINE_TYPES_H__ +#ifndef MRCP_ENGINE_TYPES_H +#define MRCP_ENGINE_TYPES_H /** * @file mrcp_engine_types.h @@ -35,6 +37,8 @@ typedef struct mrcp_engine_t mrcp_engine_t; typedef struct mrcp_engine_config_t mrcp_engine_config_t; /** MRCP engine vtable declaration */ typedef struct mrcp_engine_method_vtable_t mrcp_engine_method_vtable_t; +/** MRCP engine event vtable declaration */ +typedef struct mrcp_engine_event_vtable_t mrcp_engine_event_vtable_t; /** MRCP engine channel declaration */ typedef struct mrcp_engine_channel_t mrcp_engine_channel_t; /** MRCP engine channel virtual method table declaration */ @@ -100,14 +104,28 @@ struct mrcp_engine_method_vtable_t { mrcp_engine_channel_t* (*create_channel)(mrcp_engine_t *engine, apr_pool_t *pool); }; +/** Table of MRCP engine virtual event handlers */ +struct mrcp_engine_event_vtable_t { + /** Open event handler */ + apt_bool_t (*on_open)(mrcp_engine_t *channel, apt_bool_t status); + /** Close event handler */ + apt_bool_t (*on_close)(mrcp_engine_t *channel); +}; + /** MRCP engine */ struct mrcp_engine_t { + /** Identifier of the engine */ + const char *id; /** 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; + /** Table of virtual event handlers */ + const mrcp_engine_event_vtable_t *event_vtable; + /** External object used with event handlers */ + void *event_obj; /** Codec manager */ const mpf_codec_manager_t *codec_manager; /** Dir layout structure */ @@ -121,15 +139,12 @@ struct mrcp_engine_t { /** Pool to allocate memory from */ apr_pool_t *pool; - /** Create state machine */ mrcp_state_machine_t* (*create_state_machine)(void *obj, mrcp_version_e version, apr_pool_t *pool); }; /** MRCP engine config */ struct mrcp_engine_config_t { - /** Name of the engine */ - const char *name; /** Max number of simultaneous channels */ apr_size_t max_channel_count; /** Table of name/value string params */ @@ -138,4 +153,4 @@ struct mrcp_engine_config_t { APT_END_EXTERN_C -#endif /*__MRCP_ENGINE_TYPES_H__*/ +#endif /* MRCP_ENGINE_TYPES_H */ diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_recog_engine.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_recog_engine.h index 2e58c0663c..7a79f7e536 100644 --- a/libs/unimrcp/libs/mrcp-engine/include/mrcp_recog_engine.h +++ b/libs/unimrcp/libs/mrcp-engine/include/mrcp_recog_engine.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_recog_engine.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MRCP_RECOG_ENGINE_H__ -#define __MRCP_RECOG_ENGINE_H__ +#ifndef MRCP_RECOG_ENGINE_H +#define MRCP_RECOG_ENGINE_H /** * @file mrcp_recog_engine.h @@ -30,4 +32,4 @@ #include "mrcp_generic_header.h" #include "mrcp_message.h" -#endif /*__MRCP_RECOG_ENGINE_H__*/ +#endif /* MRCP_RECOG_ENGINE_H */ diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_recog_state_machine.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_recog_state_machine.h index 32d5482593..f03ebf13de 100644 --- a/libs/unimrcp/libs/mrcp-engine/include/mrcp_recog_state_machine.h +++ b/libs/unimrcp/libs/mrcp-engine/include/mrcp_recog_state_machine.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_recog_state_machine.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MRCP_RECOG_STATE_MACHINE_H__ -#define __MRCP_RECOG_STATE_MACHINE_H__ +#ifndef MRCP_RECOG_STATE_MACHINE_H +#define MRCP_RECOG_STATE_MACHINE_H /** * @file mrcp_recog_state_machine.h @@ -31,4 +33,4 @@ mrcp_state_machine_t* mrcp_recog_state_machine_create(void *obj, mrcp_version_e APT_END_EXTERN_C -#endif /*__MRCP_RECOG_STATE_MACHINE_H__*/ +#endif /* MRCP_RECOG_STATE_MACHINE_H */ diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_recorder_engine.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_recorder_engine.h index 3e4e818d4d..9c2c239145 100644 --- a/libs/unimrcp/libs/mrcp-engine/include/mrcp_recorder_engine.h +++ b/libs/unimrcp/libs/mrcp-engine/include/mrcp_recorder_engine.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_recorder_engine.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MRCP_RECORDER_ENGINE_H__ -#define __MRCP_RECORDER_ENGINE_H__ +#ifndef MRCP_RECORDER_ENGINE_H +#define MRCP_RECORDER_ENGINE_H /** * @file mrcp_recorder_engine.h @@ -30,4 +32,4 @@ #include "mrcp_generic_header.h" #include "mrcp_message.h" -#endif /*__MRCP_RECORDER_ENGINE_H__*/ +#endif /* MRCP_RECORDER_ENGINE_H */ diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_recorder_state_machine.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_recorder_state_machine.h index ccd6096d95..2c2f19bb58 100644 --- a/libs/unimrcp/libs/mrcp-engine/include/mrcp_recorder_state_machine.h +++ b/libs/unimrcp/libs/mrcp-engine/include/mrcp_recorder_state_machine.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_recorder_state_machine.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MRCP_RECORDER_STATE_MACHINE_H__ -#define __MRCP_RECORDER_STATE_MACHINE_H__ +#ifndef MRCP_RECORDER_STATE_MACHINE_H +#define MRCP_RECORDER_STATE_MACHINE_H /** * @file mrcp_recorder_state_machine.h @@ -31,4 +33,4 @@ mrcp_state_machine_t* mrcp_recorder_state_machine_create(void *obj, mrcp_version APT_END_EXTERN_C -#endif /*__MRCP_RECORDER_STATE_MACHINE_H__*/ +#endif /* MRCP_RECORDER_STATE_MACHINE_H */ diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_resource_engine.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_resource_engine.h index c69e5d0b93..650e47a9e1 100644 --- a/libs/unimrcp/libs/mrcp-engine/include/mrcp_resource_engine.h +++ b/libs/unimrcp/libs/mrcp-engine/include/mrcp_resource_engine.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_resource_engine.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MRCP_RESOURCE_ENGINE_H__ -#define __MRCP_RESOURCE_ENGINE_H__ +#ifndef MRCP_RESOURCE_ENGINE_H +#define MRCP_RESOURCE_ENGINE_H /** * @file mrcp_resource_engine.h @@ -46,4 +48,4 @@ static APR_INLINE mrcp_engine_t* mrcp_resource_engine_create( APT_END_EXTERN_C -#endif /*__MRCP_RESOURCE_ENGINE_H__*/ +#endif /* MRCP_RESOURCE_ENGINE_H */ diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_state_machine.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_state_machine.h index 4089a8bd07..a34a280443 100644 --- a/libs/unimrcp/libs/mrcp-engine/include/mrcp_state_machine.h +++ b/libs/unimrcp/libs/mrcp-engine/include/mrcp_state_machine.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_state_machine.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MRCP_STATE_MACHINE_H__ -#define __MRCP_STATE_MACHINE_H__ +#ifndef MRCP_STATE_MACHINE_H +#define MRCP_STATE_MACHINE_H /** * @file mrcp_state_machine.h @@ -81,4 +83,4 @@ static APR_INLINE apt_bool_t mrcp_state_machine_deactivate(mrcp_state_machine_t APT_END_EXTERN_C -#endif /*__MRCP_STATE_MACHINE_H__*/ +#endif /* MRCP_STATE_MACHINE_H */ diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_synth_engine.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_synth_engine.h index 305f7eadaa..8cdc18dcef 100644 --- a/libs/unimrcp/libs/mrcp-engine/include/mrcp_synth_engine.h +++ b/libs/unimrcp/libs/mrcp-engine/include/mrcp_synth_engine.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_synth_engine.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MRCP_SYNTH_ENGINE_H__ -#define __MRCP_SYNTH_ENGINE_H__ +#ifndef MRCP_SYNTH_ENGINE_H +#define MRCP_SYNTH_ENGINE_H /** * @file mrcp_synth_engine.h @@ -30,4 +32,4 @@ #include "mrcp_generic_header.h" #include "mrcp_message.h" -#endif /*__MRCP_SYNTH_ENGINE_H__*/ +#endif /* MRCP_SYNTH_ENGINE_H */ diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_synth_state_machine.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_synth_state_machine.h index efe26dcc73..08ae5716c1 100644 --- a/libs/unimrcp/libs/mrcp-engine/include/mrcp_synth_state_machine.h +++ b/libs/unimrcp/libs/mrcp-engine/include/mrcp_synth_state_machine.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_synth_state_machine.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MRCP_SYNTH_STATE_MACHINE_H__ -#define __MRCP_SYNTH_STATE_MACHINE_H__ +#ifndef MRCP_SYNTH_STATE_MACHINE_H +#define MRCP_SYNTH_STATE_MACHINE_H /** * @file mrcp_synth_state_machine.h @@ -31,4 +33,4 @@ mrcp_state_machine_t* mrcp_synth_state_machine_create(void *obj, mrcp_version_e APT_END_EXTERN_C -#endif /*__MRCP_SYNTH_STATE_MACHINE_H__*/ +#endif /* MRCP_SYNTH_STATE_MACHINE_H */ diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_verifier_engine.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_verifier_engine.h new file mode 100644 index 0000000000..20e4de31f1 --- /dev/null +++ b/libs/unimrcp/libs/mrcp-engine/include/mrcp_verifier_engine.h @@ -0,0 +1,35 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: mrcp_verifier_engine.h 1755 2010-08-18 19:35:08Z achaloyan $ + */ + +#ifndef MRCP_VERIFIER_ENGINE_H +#define MRCP_VERIFIER_ENGINE_H + +/** + * @file mrcp_verifier_engine.h + * @brief Verifier Engine Includes + */ + +#include "mrcp_engine_plugin.h" +#include "mrcp_engine_impl.h" + +#include "mrcp_verifier_resource.h" +#include "mrcp_verifier_header.h" +#include "mrcp_generic_header.h" +#include "mrcp_message.h" + +#endif /* MRCP_VERIFIER_ENGINE_H */ diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_verifier_state_machine.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_verifier_state_machine.h new file mode 100644 index 0000000000..a3b5e8e2b4 --- /dev/null +++ b/libs/unimrcp/libs/mrcp-engine/include/mrcp_verifier_state_machine.h @@ -0,0 +1,36 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: mrcp_verifier_state_machine.h 1755 2010-08-18 19:35:08Z achaloyan $ + */ + +#ifndef MRCP_VERIFIER_STATE_MACHINE_H +#define MRCP_VERIFIER_STATE_MACHINE_H + +/** + * @file mrcp_verifier_state_machine.h + * @brief MRCP Verifier State Machine + */ + +#include "mrcp_state_machine.h" + +APT_BEGIN_EXTERN_C + +/** Create MRCP verifier state machine */ +mrcp_state_machine_t* mrcp_verifier_state_machine_create(void *obj, mrcp_version_e version, apr_pool_t *pool); + +APT_END_EXTERN_C + +#endif /* MRCP_VERIFIER_STATE_MACHINE_H */ diff --git a/libs/unimrcp/libs/mrcp-engine/mrcpengine.2008.vcproj b/libs/unimrcp/libs/mrcp-engine/mrcpengine.2008.vcproj deleted file mode 100644 index fbc62b016a..0000000000 --- a/libs/unimrcp/libs/mrcp-engine/mrcpengine.2008.vcproj +++ /dev/null @@ -1,154 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/unimrcp/libs/mrcp-engine/mrcpengine.vcproj b/libs/unimrcp/libs/mrcp-engine/mrcpengine.vcproj index c5b163eae1..8966705a4e 100644 --- a/libs/unimrcp/libs/mrcp-engine/mrcpengine.vcproj +++ b/libs/unimrcp/libs/mrcp-engine/mrcpengine.vcproj @@ -296,6 +296,14 @@ RelativePath=".\include\mrcp_synth_state_machine.h" > + + + + + + diff --git a/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_factory.c b/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_factory.c index 2faaabfd2c..8de989af0a 100644 --- a/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_factory.c +++ b/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_factory.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_engine_factory.c 1761 2010-08-20 17:35:28Z achaloyan $ */ #include @@ -19,6 +21,7 @@ #include "mrcp_synth_state_machine.h" #include "mrcp_recog_state_machine.h" #include "mrcp_recorder_state_machine.h" +#include "mrcp_verifier_state_machine.h" #include "apt_log.h" /** Engine factory declaration */ @@ -61,7 +64,6 @@ MRCP_DECLARE(apt_bool_t) mrcp_engine_factory_open(mrcp_engine_factory_t *factory mrcp_engine_t *engine; apr_hash_index_t *it; void *val; - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open MRCP Engines"); it = apr_hash_first(factory->pool,factory->engines); for(; it; it = apr_hash_next(it)) { apr_hash_this(it,NULL,NULL,&val); @@ -79,7 +81,6 @@ MRCP_DECLARE(apt_bool_t) mrcp_engine_factory_close(mrcp_engine_factory_t *factor mrcp_engine_t *engine; apr_hash_index_t *it; void *val; - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close MRCP Engines"); it=apr_hash_first(factory->pool,factory->engines); for(; it; it = apr_hash_next(it)) { apr_hash_this(it,NULL,NULL,&val); @@ -92,9 +93,9 @@ MRCP_DECLARE(apt_bool_t) mrcp_engine_factory_close(mrcp_engine_factory_t *factor } /** Register new engine */ -MRCP_DECLARE(apt_bool_t) mrcp_engine_factory_engine_register(mrcp_engine_factory_t *factory, mrcp_engine_t *engine, const char *name) +MRCP_DECLARE(apt_bool_t) mrcp_engine_factory_engine_register(mrcp_engine_factory_t *factory, mrcp_engine_t *engine) { - if(!engine || !name) { + if(!engine || !engine->id) { return FALSE; } @@ -108,6 +109,9 @@ MRCP_DECLARE(apt_bool_t) mrcp_engine_factory_engine_register(mrcp_engine_factory case MRCP_RECORDER_RESOURCE: engine->create_state_machine = mrcp_recorder_state_machine_create; break; + case MRCP_VERIFIER_RESOURCE: + engine->create_state_machine = mrcp_verifier_state_machine_create; + break; default: break; } @@ -116,12 +120,12 @@ MRCP_DECLARE(apt_bool_t) mrcp_engine_factory_engine_register(mrcp_engine_factory return FALSE; } - apr_hash_set(factory->engines,name,APR_HASH_KEY_STRING,engine); + apr_hash_set(factory->engines,engine->id,APR_HASH_KEY_STRING,engine); return TRUE; } /** Get engine by name */ -MRCP_DECLARE(mrcp_engine_t*) mrcp_engine_factory_engine_get(mrcp_engine_factory_t *factory, const char *name) +MRCP_DECLARE(mrcp_engine_t*) mrcp_engine_factory_engine_get(const mrcp_engine_factory_t *factory, const char *name) { if(!name) { return NULL; @@ -130,7 +134,7 @@ MRCP_DECLARE(mrcp_engine_t*) mrcp_engine_factory_engine_get(mrcp_engine_factory_ } /** Find engine by resource identifier */ -MRCP_DECLARE(mrcp_engine_t*) mrcp_engine_factory_engine_find(mrcp_engine_factory_t *factory, mrcp_resource_id resource_id) +MRCP_DECLARE(mrcp_engine_t*) mrcp_engine_factory_engine_find(const mrcp_engine_factory_t *factory, mrcp_resource_id resource_id) { mrcp_engine_t *engine; void *val; @@ -145,3 +149,9 @@ MRCP_DECLARE(mrcp_engine_t*) mrcp_engine_factory_engine_find(mrcp_engine_factory } return NULL; } + +/** Start iterating over the engines in a factory */ +MRCP_DECLARE(apr_hash_index_t*) mrcp_engine_factory_engine_first(const mrcp_engine_factory_t *factory) +{ + return apr_hash_first(factory->pool,factory->engines); +} diff --git a/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_iface.c b/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_iface.c index 137af17827..e8f45a4f98 100644 --- a/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_iface.c +++ b/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_iface.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,9 +12,55 @@ * 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. + * + * $Id: mrcp_engine_iface.c 1700 2010-05-21 18:56:06Z achaloyan $ */ #include "mrcp_engine_iface.h" +#include "apt_log.h" + +/** Destroy engine */ +apt_bool_t mrcp_engine_virtual_destroy(mrcp_engine_t *engine) +{ + return engine->method_vtable->destroy(engine); +} + +/** Open engine */ +apt_bool_t mrcp_engine_virtual_open(mrcp_engine_t *engine) +{ + if(engine->is_open == FALSE) { + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open Engine [%s]",engine->id); + return engine->method_vtable->open(engine); + } + return FALSE; +} + +/** Response to open engine request */ +void mrcp_engine_on_open(mrcp_engine_t *engine, apt_bool_t status) +{ + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Engine Opened [%s] status [%s]", + engine->id, + status == TRUE ? "success" : "failure"); + engine->is_open = status; +} + +/** Close engine */ +apt_bool_t mrcp_engine_virtual_close(mrcp_engine_t *engine) +{ + if(engine->is_open == TRUE) { + engine->is_open = FALSE; + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close Engine [%s]",engine->id); + return engine->method_vtable->close(engine); + } + return FALSE; +} + +/** Response to close engine request */ +void mrcp_engine_on_close(mrcp_engine_t *engine) +{ + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Engine Closed [%s]",engine->id); + engine->is_open = FALSE; +} /** Create engine channel */ mrcp_engine_channel_t* mrcp_engine_channel_virtual_create(mrcp_engine_t *engine, mrcp_version_e mrcp_version, apr_pool_t *pool) @@ -48,7 +94,6 @@ apt_bool_t mrcp_engine_channel_virtual_destroy(mrcp_engine_channel_t *channel) mrcp_engine_config_t* mrcp_engine_config_alloc(apr_pool_t *pool) { mrcp_engine_config_t *config = apr_palloc(pool,sizeof(mrcp_engine_config_t)); - config->name = NULL; config->max_channel_count = 0; config->params = NULL; return config; diff --git a/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_impl.c b/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_impl.c index e2c7a24dae..969dee4675 100644 --- a/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_impl.c +++ b/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_impl.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_engine_impl.c 1710 2010-05-24 17:36:19Z achaloyan $ */ #include "mrcp_engine_impl.h" @@ -25,9 +27,12 @@ mrcp_engine_t* mrcp_engine_create( apr_pool_t *pool) { mrcp_engine_t *engine = apr_palloc(pool,sizeof(mrcp_engine_t)); + engine->id = NULL; engine->resource_id = resource_id; engine->obj = obj; engine->method_vtable =vtable; + engine->event_vtable = NULL; + engine->event_obj = NULL; engine->config = NULL; engine->codec_manager = NULL; engine->dir_layout = NULL; @@ -217,7 +222,7 @@ mrcp_engine_channel_t* mrcp_engine_sink_channel_create( } /** Get codec descriptor of the audio source stream */ -const mpf_codec_descriptor_t* mrcp_engine_source_stream_codec_get(mrcp_engine_channel_t *channel) +const mpf_codec_descriptor_t* mrcp_engine_source_stream_codec_get(const mrcp_engine_channel_t *channel) { if(channel && channel->termination) { mpf_audio_stream_t *audio_stream = mpf_termination_audio_stream_get(channel->termination); @@ -229,7 +234,7 @@ const mpf_codec_descriptor_t* mrcp_engine_source_stream_codec_get(mrcp_engine_ch } /** Get codec descriptor of the audio sink stream */ -const mpf_codec_descriptor_t* mrcp_engine_sink_stream_codec_get(mrcp_engine_channel_t *channel) +const mpf_codec_descriptor_t* mrcp_engine_sink_stream_codec_get(const mrcp_engine_channel_t *channel) { if(channel && channel->termination) { mpf_audio_stream_t *audio_stream = mpf_termination_audio_stream_get(channel->termination); diff --git a/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_loader.c b/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_loader.c index dfa5bd617a..da29170d65 100644 --- a/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_loader.c +++ b/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_loader.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_engine_loader.c 1700 2010-05-21 18:56:06Z achaloyan $ */ #include @@ -121,17 +123,17 @@ static apt_bool_t plugin_logger_load(apr_dso_handle_t *plugin) /** Load engine plugin */ -MRCP_DECLARE(mrcp_engine_t*) mrcp_engine_loader_plugin_load(mrcp_engine_loader_t *loader, const char *path, const char *name) +MRCP_DECLARE(mrcp_engine_t*) mrcp_engine_loader_plugin_load(mrcp_engine_loader_t *loader, const char *id, const char *path, mrcp_engine_config_t *config) { apr_dso_handle_t *plugin = NULL; mrcp_plugin_creator_f plugin_creator = NULL; mrcp_engine_t *engine = NULL; - if(!path || !name) { + if(!path || !id) { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Load Plugin: invalid params"); return NULL; } - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Load Plugin [%s] [%s]",path,name); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Load Plugin [%s] [%s]",id,path); if(apr_dso_load(&plugin,path,loader->pool) != APR_SUCCESS) { char derr[512] = ""; apr_dso_error(plugin,derr,sizeof(derr)); @@ -153,12 +155,14 @@ MRCP_DECLARE(mrcp_engine_t*) mrcp_engine_loader_plugin_load(mrcp_engine_loader_t plugin_logger_load(plugin); - apr_hash_set(loader->plugins,name,APR_HASH_KEY_STRING,plugin); + apr_hash_set(loader->plugins,id,APR_HASH_KEY_STRING,plugin); engine = plugin_creator(loader->pool); if(!engine) { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create MRCP Engine"); } - + + engine->id = id; + engine->config = config; return engine; } diff --git a/libs/unimrcp/libs/mrcp-engine/src/mrcp_recog_state_machine.c b/libs/unimrcp/libs/mrcp-engine/src/mrcp_recog_state_machine.c index 1965192d96..50ddb972cb 100644 --- a/libs/unimrcp/libs/mrcp-engine/src/mrcp_recog_state_machine.c +++ b/libs/unimrcp/libs/mrcp-engine/src/mrcp_recog_state_machine.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_recog_state_machine.c 1782 2010-09-06 17:52:41Z achaloyan $ */ #include "apt_obj_list.h" @@ -41,19 +43,19 @@ static const char * state_names[RECOGNIZER_STATE_COUNT] = { 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; + mrcp_state_machine_t base; /** recognizer state */ - mrcp_recog_state_e state; + mrcp_recog_state_e state; /** indicate whether active_request was processed from pending request queue */ - apt_bool_t is_pending; + apt_bool_t is_pending; /** request sent to recognition engine and waiting for the response to be received */ - mrcp_message_t *active_request; + mrcp_message_t *active_request; /** in-progress recognize request */ - mrcp_message_t *recog; + mrcp_message_t *recog; /** queue of pending recognition requests */ - apt_obj_list_t *queue; + apt_obj_list_t *queue; /** properties used in set/get params */ - mrcp_message_header_t properties; + mrcp_message_header_t *properties; }; typedef apt_bool_t (*recog_method_f)(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message); @@ -83,9 +85,12 @@ static APR_INLINE apt_bool_t recog_event_dispatch(mrcp_recog_state_machine_t *st return state_machine->base.on_dispatch(&state_machine->base,message); } -static APR_INLINE void recog_state_change(mrcp_recog_state_machine_t *state_machine, mrcp_recog_state_e state) +static APR_INLINE void recog_state_change(mrcp_recog_state_machine_t *state_machine, mrcp_recog_state_e state, mrcp_message_t *message) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"State Transition %s -> %s",state_names[state_machine->state],state_names[state]); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"State Transition %s -> %s "APT_SIDRES_FMT, + state_names[state_machine->state], + state_names[state], + MRCP_MESSAGE_SIDRES(message)); state_machine->state = state; if(state == RECOGNIZER_STATE_IDLE) { state_machine->recog = NULL; @@ -95,32 +100,24 @@ static APR_INLINE void recog_state_change(mrcp_recog_state_machine_t *state_mach 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 [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); - mrcp_message_header_set(&state_machine->properties,&message->header,message->pool); + mrcp_header_fields_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 [%"MRCP_REQUEST_ID_FMT"]", - 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 [%"MRCP_REQUEST_ID_FMT"]", - 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 [%"MRCP_REQUEST_ID_FMT"]", - 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); + mrcp_header_fields_set(&message->header,&state_machine->active_request->header,message->pool); + mrcp_header_fields_get(&message->header,state_machine->properties,message->pool); return recog_response_dispatch(state_machine,message); } @@ -132,18 +129,14 @@ static apt_bool_t recog_request_define_grammar(mrcp_recog_state_machine_t *state return recog_response_dispatch(state_machine,response_message); } else if(state_machine->state == RECOGNIZER_STATE_RECOGNIZED) { - recog_state_change(state_machine,RECOGNIZER_STATE_IDLE); + recog_state_change(state_machine,RECOGNIZER_STATE_IDLE,message); } - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process DEFINE-GRAMMAR Request [%"MRCP_REQUEST_ID_FMT"]", - 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 [%"MRCP_REQUEST_ID_FMT"]", - 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; @@ -154,10 +147,11 @@ static apt_bool_t recog_response_define_grammar(mrcp_recog_state_machine_t *stat 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); + mrcp_header_fields_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 [%"MRCP_REQUEST_ID_FMT"]", + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Queue Up RECOGNIZE Request "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(message), message->start_line.request_id); message->start_line.request_state = MRCP_REQUEST_STATE_PENDING; apt_list_push_back(state_machine->queue,message,message->pool); @@ -167,18 +161,14 @@ static apt_bool_t recog_request_recognize(mrcp_recog_state_machine_t *state_mach return recog_response_dispatch(state_machine,response); } - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process RECOGNIZE Request [%"MRCP_REQUEST_ID_FMT"]", - 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 [%"MRCP_REQUEST_ID_FMT"]", - 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); + recog_state_change(state_machine,RECOGNIZER_STATE_RECOGNIZING,message); } if(state_machine->is_pending == TRUE) { state_machine->is_pending = FALSE; @@ -188,13 +178,22 @@ static apt_bool_t recog_response_recognize(mrcp_recog_state_machine_t *state_mac return recog_response_dispatch(state_machine,message); } +static apt_bool_t recog_request_interpret(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message) +{ + mrcp_header_fields_inherit(&message->header,state_machine->properties,message->pool); + return recog_request_dispatch(state_machine,message); +} + +static apt_bool_t recog_response_interpret(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message) +{ + 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 [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); return recog_request_dispatch(state_machine,message); } @@ -206,8 +205,6 @@ static apt_bool_t recog_request_get_result(mrcp_recog_state_machine_t *state_mac 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 [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); return recog_response_dispatch(state_machine,message); } @@ -216,8 +213,6 @@ static apt_bool_t recog_request_recognition_start_timers(mrcp_recog_state_machin 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 [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); return recog_request_dispatch(state_machine,message); } @@ -229,8 +224,6 @@ static apt_bool_t recog_request_recognition_start_timers(mrcp_recog_state_machin 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 [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); return recog_response_dispatch(state_machine,message); } @@ -252,7 +245,9 @@ static apt_bool_t recog_pending_requests_remove(mrcp_recog_state_machine_t *stat 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); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remove Pending RECOGNIZE Request "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(pending_message), + 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); @@ -283,13 +278,14 @@ static apt_bool_t recog_request_stop(mrcp_recog_state_machine_t *state_machine, 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 [%"MRCP_REQUEST_ID_FMT"]", + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Found IN-PROGRESS RECOGNIZE Request "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(message), 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); + recog_state_change(state_machine,RECOGNIZER_STATE_IDLE,message); } /* found no in-progress RECOGNIZE request, sending immediate response */ @@ -302,19 +298,19 @@ static apt_bool_t recog_response_stop(mrcp_recog_state_machine_t *state_machine, { 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 [%"MRCP_REQUEST_ID_FMT"]", - 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_state_change(state_machine,RECOGNIZER_STATE_IDLE,message); pending_request = apt_list_pop_front(state_machine->queue); recog_response_dispatch(state_machine,message); /* process pending RECOGNIZE requests / if any */ if(pending_request) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process Pending RECOGNIZE Request [%d]",pending_request->start_line.request_id); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process Pending RECOGNIZE Request "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(pending_request), + pending_request->start_line.request_id); state_machine->is_pending = TRUE; recog_request_dispatch(state_machine,pending_request); } @@ -333,8 +329,6 @@ static apt_bool_t recog_event_start_of_input(mrcp_recog_state_machine_t *state_m return FALSE; } - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process START-OF-INPUT Event [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); message->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS; return recog_event_dispatch(state_machine,message); } @@ -343,47 +337,62 @@ static apt_bool_t recog_event_recognition_complete(mrcp_recog_state_machine_t *s { mrcp_message_t *pending_request; if(!state_machine->recog) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected RECOGNITION-COMPLETE Event [%"MRCP_REQUEST_ID_FMT"]", + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected RECOGNITION-COMPLETE Event "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(message), 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 [%"MRCP_REQUEST_ID_FMT"]", + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected RECOGNITION-COMPLETE Event "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(message), 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); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Ignore RECOGNITION-COMPLETE Event "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]: waiting for STOP response", + MRCP_MESSAGE_SIDRES(message), + message->start_line.request_id); return FALSE; } - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process RECOGNITION-COMPLETE Event [%"MRCP_REQUEST_ID_FMT"]", - 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_state_change(state_machine,RECOGNIZER_STATE_RECOGNIZED,message); 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); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process Pending RECOGNIZE Request "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(pending_request), + 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_interpretation_complete(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message) +{ + 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_event_dispatch(state_machine,message); +} + 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_interpret, recog_request_get_result, recog_request_recognition_start_timers, recog_request_stop @@ -394,6 +403,7 @@ static recog_method_f recog_response_method_array[RECOGNIZER_METHOD_COUNT] = { recog_response_get_params, recog_response_define_grammar, recog_response_recognize, + recog_response_interpret, recog_response_get_result, recog_response_recognition_start_timers, recog_response_stop @@ -401,7 +411,8 @@ static recog_method_f recog_response_method_array[RECOGNIZER_METHOD_COUNT] = { static recog_method_f recog_event_method_array[RECOGNIZER_EVENT_COUNT] = { recog_event_start_of_input, - recog_event_recognition_complete + recog_event_recognition_complete, + recog_event_interpretation_complete }; /** Update state according to received incoming request from MRCP client */ @@ -412,6 +423,10 @@ static apt_bool_t recog_request_state_update(mrcp_recog_state_machine_t *state_m return FALSE; } + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process %s Request "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + message->start_line.method_name.buf, + MRCP_MESSAGE_SIDRES(message), + message->start_line.request_id); method = recog_request_method_array[message->start_line.method_id]; if(method) { return method(state_machine,message); @@ -436,6 +451,10 @@ static apt_bool_t recog_response_state_update(mrcp_recog_state_machine_t *state_ return FALSE; } + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process %s Response "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + message->start_line.method_name.buf, + MRCP_MESSAGE_SIDRES(message), + message->start_line.request_id); method = recog_response_method_array[message->start_line.method_id]; if(method) { return method(state_machine,message); @@ -451,6 +470,10 @@ static apt_bool_t recog_event_state_update(mrcp_recog_state_machine_t *state_mac return FALSE; } + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process %s Event "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + message->start_line.method_name.buf, + MRCP_MESSAGE_SIDRES(message), + message->start_line.request_id); method = recog_event_method_array[message->start_line.method_id]; if(method) { return method(state_machine,message); @@ -505,7 +528,8 @@ static apt_bool_t recog_state_deactivate(mrcp_state_machine_t *base) message->start_line.request_id = source->start_line.request_id + 1; apt_string_set(&message->start_line.method_name,"DEACTIVATE"); /* informative only */ message->header = source->header; - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create and Process STOP Request [%"MRCP_REQUEST_ID_FMT"]", + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create and Process STOP Request "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(message), message->start_line.request_id); return recog_request_dispatch(state_machine,message); } @@ -513,7 +537,6 @@ static apt_bool_t recog_state_deactivate(mrcp_state_machine_t *base) /** Create MRCP recognizer state machine */ mrcp_state_machine_t* mrcp_recog_state_machine_create(void *obj, 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); state_machine->base.update = recog_state_update; @@ -523,9 +546,9 @@ mrcp_state_machine_t* mrcp_recog_state_machine_create(void *obj, mrcp_version_e 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); + state_machine->properties = mrcp_message_header_create( + mrcp_generic_header_vtable_get(version), + mrcp_recog_header_vtable_get(version), + pool); return &state_machine->base; } diff --git a/libs/unimrcp/libs/mrcp-engine/src/mrcp_recorder_state_machine.c b/libs/unimrcp/libs/mrcp-engine/src/mrcp_recorder_state_machine.c index 9692d33244..312b4d57c3 100644 --- a/libs/unimrcp/libs/mrcp-engine/src/mrcp_recorder_state_machine.c +++ b/libs/unimrcp/libs/mrcp-engine/src/mrcp_recorder_state_machine.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_recorder_state_machine.c 1705 2010-05-23 14:04:20Z achaloyan $ */ #include "apt_obj_list.h" @@ -39,15 +41,15 @@ typedef struct mrcp_recorder_state_machine_t mrcp_recorder_state_machine_t; struct mrcp_recorder_state_machine_t { /** state machine base */ - mrcp_state_machine_t base; + mrcp_state_machine_t base; /** recorder state */ - mrcp_recorder_state_e state; + mrcp_recorder_state_e state; /** request sent to recorder engine and waiting for the response to be received */ - mrcp_message_t *active_request; + mrcp_message_t *active_request; /** in-progress record request */ - mrcp_message_t *record; + mrcp_message_t *record; /** properties used in set/get params */ - mrcp_message_header_t properties; + mrcp_message_header_t *properties; }; typedef apt_bool_t (*recorder_method_f)(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message); @@ -77,9 +79,12 @@ static APR_INLINE apt_bool_t recorder_event_dispatch(mrcp_recorder_state_machine return state_machine->base.on_dispatch(&state_machine->base,message); } -static APR_INLINE void recorder_state_change(mrcp_recorder_state_machine_t *state_machine, mrcp_recorder_state_e state) +static APR_INLINE void recorder_state_change(mrcp_recorder_state_machine_t *state_machine, mrcp_recorder_state_e state, mrcp_message_t *message) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"State Transition %s -> %s",state_names[state_machine->state],state_names[state]); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"State Transition %s -> %s "APT_SIDRES_FMT, + state_names[state_machine->state], + state_names[state], + MRCP_MESSAGE_SIDRES(message)); state_machine->state = state; if(state == RECORDER_STATE_IDLE) { state_machine->record = NULL; @@ -89,41 +94,34 @@ static APR_INLINE void recorder_state_change(mrcp_recorder_state_machine_t *stat static apt_bool_t recorder_request_set_params(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SET-PARAMS Request [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); - mrcp_message_header_set(&state_machine->properties,&message->header,message->pool); + mrcp_header_fields_set(state_machine->properties,&message->header,message->pool); return recorder_request_dispatch(state_machine,message); } static apt_bool_t recorder_response_set_params(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SET-PARAMS Response [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); return recorder_response_dispatch(state_machine,message); } static apt_bool_t recorder_request_get_params(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process GET-PARAMS Request [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); return recorder_request_dispatch(state_machine,message); } static apt_bool_t recorder_response_get_params(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process GET-PARAMS Response [%"MRCP_REQUEST_ID_FMT"]", - 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); + mrcp_header_fields_set(&message->header,&state_machine->active_request->header,message->pool); + mrcp_header_fields_get(&message->header,state_machine->properties,message->pool); return recorder_response_dispatch(state_machine,message); } static apt_bool_t recorder_request_record(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message) { - mrcp_message_header_inherit(&message->header,&state_machine->properties,message->pool); + mrcp_header_fields_inherit(&message->header,state_machine->properties,message->pool); if(state_machine->state == RECORDER_STATE_RECORDING) { mrcp_message_t *response; - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Reject RECORD Request [%"MRCP_REQUEST_ID_FMT"]", + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Reject RECORD Request "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(message), message->start_line.request_id); /* there is in-progress request, reject this one */ @@ -132,18 +130,14 @@ static apt_bool_t recorder_request_record(mrcp_recorder_state_machine_t *state_m return recorder_response_dispatch(state_machine,response); } - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process RECORD Request [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); return recorder_request_dispatch(state_machine,message); } static apt_bool_t recorder_response_record(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process RECORD Response [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); if(message->start_line.request_state == MRCP_REQUEST_STATE_INPROGRESS) { state_machine->record = state_machine->active_request; - recorder_state_change(state_machine,RECORDER_STATE_RECORDING); + recorder_state_change(state_machine,RECORDER_STATE_RECORDING,message); } return recorder_response_dispatch(state_machine,message); } @@ -153,8 +147,6 @@ static apt_bool_t recorder_request_stop(mrcp_recorder_state_machine_t *state_mac mrcp_message_t *response; if(state_machine->state == RECORDER_STATE_RECORDING) { /* found in-progress RECORDER request, stop it */ - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process STOP Request [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); return recorder_request_dispatch(state_machine,message); } @@ -166,12 +158,10 @@ static apt_bool_t recorder_request_stop(mrcp_recorder_state_machine_t *state_mac static apt_bool_t recorder_response_stop(mrcp_recorder_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 STOP Response [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); /* append active id list */ active_request_id_list_append(generic_header,state_machine->record->start_line.request_id); mrcp_generic_header_property_add(message,GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST); - recorder_state_change(state_machine,RECORDER_STATE_IDLE); + recorder_state_change(state_machine,RECORDER_STATE_IDLE,message); return recorder_response_dispatch(state_machine,message); } @@ -180,8 +170,6 @@ static apt_bool_t recorder_request_start_timers(mrcp_recorder_state_machine_t *s mrcp_message_t *response; if(state_machine->state == RECORDER_STATE_RECORDING) { /* found in-progress request */ - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process START-INPUT-TIMERS Request [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); return recorder_request_dispatch(state_machine,message); } @@ -193,8 +181,6 @@ static apt_bool_t recorder_request_start_timers(mrcp_recorder_state_machine_t *s static apt_bool_t recorder_response_start_timers(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process START-INPUT-TIMERS Response [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); return recorder_response_dispatch(state_machine,message); } @@ -210,8 +196,6 @@ static apt_bool_t recorder_event_start_of_input(mrcp_recorder_state_machine_t *s return FALSE; } - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process START-OF-INPUT Event [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); message->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS; return recorder_event_dispatch(state_machine,message); } @@ -219,30 +203,32 @@ static apt_bool_t recorder_event_start_of_input(mrcp_recorder_state_machine_t *s static apt_bool_t recorder_event_record_complete(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message) { if(!state_machine->record) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected RECORD-COMPLETE Event [%"MRCP_REQUEST_ID_FMT"]", + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected RECORD-COMPLETE Event "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(message), message->start_line.request_id); return FALSE; } if(state_machine->record->start_line.request_id != message->start_line.request_id) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected RECORD-COMPLETE Event [%"MRCP_REQUEST_ID_FMT"]", + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected RECORD-COMPLETE Event "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(message), message->start_line.request_id); return FALSE; } if(state_machine->active_request && state_machine->active_request->start_line.method_id == RECORDER_STOP) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Ignore RECORD-COMPLETE Event [%d]: waiting for STOP response",message->start_line.request_id); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Ignore RECORD-COMPLETE Event "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]: waiting for STOP response", + MRCP_MESSAGE_SIDRES(message), + message->start_line.request_id); return FALSE; } - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process RECORD-COMPLETE Event [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); if(mrcp_resource_header_property_check(message,RECORDER_HEADER_COMPLETION_CAUSE) != TRUE) { mrcp_recorder_header_t *recorder_header = mrcp_resource_header_prepare(message); recorder_header->completion_cause = RECORDER_COMPLETION_CAUSE_SUCCESS_SILENCE; mrcp_resource_header_property_add(message,RECORDER_HEADER_COMPLETION_CAUSE); } - recorder_state_change(state_machine,RECORDER_STATE_IDLE); + recorder_state_change(state_machine,RECORDER_STATE_IDLE,message); return recorder_event_dispatch(state_machine,message); } @@ -275,6 +261,10 @@ static apt_bool_t recorder_request_state_update(mrcp_recorder_state_machine_t *s return FALSE; } + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process %s Request "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + message->start_line.method_name.buf, + MRCP_MESSAGE_SIDRES(message), + message->start_line.request_id); method = recorder_request_method_array[message->start_line.method_id]; if(method) { return method(state_machine,message); @@ -299,6 +289,10 @@ static apt_bool_t recorder_response_state_update(mrcp_recorder_state_machine_t * return FALSE; } + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process %s Response "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + message->start_line.method_name.buf, + MRCP_MESSAGE_SIDRES(message), + message->start_line.request_id); method = recorder_response_method_array[message->start_line.method_id]; if(method) { return method(state_machine,message); @@ -314,6 +308,10 @@ static apt_bool_t recorder_event_state_update(mrcp_recorder_state_machine_t *sta return FALSE; } + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process %s Event "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + message->start_line.method_name.buf, + MRCP_MESSAGE_SIDRES(message), + message->start_line.request_id); method = recorder_event_method_array[message->start_line.method_id]; if(method) { return method(state_machine,message); @@ -368,7 +366,8 @@ static apt_bool_t recorder_state_deactivate(mrcp_state_machine_t *base) message->start_line.request_id = source->start_line.request_id + 1; apt_string_set(&message->start_line.method_name,"DEACTIVATE"); /* informative only */ message->header = source->header; - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create and Process STOP Request [%"MRCP_REQUEST_ID_FMT"]", + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create and Process STOP Request "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(message), message->start_line.request_id); return recorder_request_dispatch(state_machine,message); } @@ -376,7 +375,6 @@ static apt_bool_t recorder_state_deactivate(mrcp_state_machine_t *base) /** Create MRCP recorder state machine */ mrcp_state_machine_t* mrcp_recorder_state_machine_create(void *obj, mrcp_version_e version, apr_pool_t *pool) { - mrcp_message_header_t *properties; mrcp_recorder_state_machine_t *state_machine = apr_palloc(pool,sizeof(mrcp_recorder_state_machine_t)); mrcp_state_machine_init(&state_machine->base,obj); state_machine->base.update = recorder_state_update; @@ -384,9 +382,9 @@ mrcp_state_machine_t* mrcp_recorder_state_machine_create(void *obj, mrcp_version state_machine->state = RECORDER_STATE_IDLE; state_machine->active_request = NULL; state_machine->record = NULL; - 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_recorder_header_vtable_get(version); + state_machine->properties = mrcp_message_header_create( + mrcp_generic_header_vtable_get(version), + mrcp_recorder_header_vtable_get(version), + pool); return &state_machine->base; } diff --git a/libs/unimrcp/libs/mrcp-engine/src/mrcp_synth_state_machine.c b/libs/unimrcp/libs/mrcp-engine/src/mrcp_synth_state_machine.c index 01ff0af30f..523fbd3fbc 100644 --- a/libs/unimrcp/libs/mrcp-engine/src/mrcp_synth_state_machine.c +++ b/libs/unimrcp/libs/mrcp-engine/src/mrcp_synth_state_machine.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_synth_state_machine.c 1705 2010-05-23 14:04:20Z achaloyan $ */ #include "apt_obj_list.h" @@ -41,19 +43,19 @@ static const char * state_names[SYNTHESIZER_STATE_COUNT] = { 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; + mrcp_state_machine_t base; /** synthesizer state */ - mrcp_synth_state_e state; + mrcp_synth_state_e state; /** indicate whether active_request was processed from pending request queue */ - apt_bool_t is_pending; + apt_bool_t is_pending; /** request sent to synthesizer engine and waiting for the response to be received */ - mrcp_message_t *active_request; + mrcp_message_t *active_request; /** in-progress speak request */ - mrcp_message_t *speaker; + mrcp_message_t *speaker; /** queue of pending speak requests */ - apt_obj_list_t *queue; + apt_obj_list_t *queue; /** properties used in set/get params */ - mrcp_message_header_t properties; + mrcp_message_header_t *properties; }; typedef apt_bool_t (*synth_method_f)(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message); @@ -83,9 +85,12 @@ static APR_INLINE apt_bool_t synth_event_dispatch(mrcp_synth_state_machine_t *st return state_machine->base.on_dispatch(&state_machine->base,message); } -static APR_INLINE void synth_state_change(mrcp_synth_state_machine_t *state_machine, mrcp_synth_state_e state) +static APR_INLINE void synth_state_change(mrcp_synth_state_machine_t *state_machine, mrcp_synth_state_e state, mrcp_message_t *message) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"State Transition %s -> %s",state_names[state_machine->state],state_names[state]); + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"State Transition %s -> %s "APT_SIDRES_FMT, + state_names[state_machine->state], + state_names[state], + MRCP_MESSAGE_SIDRES(message)); state_machine->state = state; if(state == SYNTHESIZER_STATE_IDLE) { state_machine->speaker = NULL; @@ -95,41 +100,34 @@ static APR_INLINE void synth_state_change(mrcp_synth_state_machine_t *state_mach 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 [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); - mrcp_message_header_set(&state_machine->properties,&message->header,message->pool); + mrcp_header_fields_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 [%"MRCP_REQUEST_ID_FMT"]", - 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 [%"MRCP_REQUEST_ID_FMT"]", - 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 [%"MRCP_REQUEST_ID_FMT"]", - 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); + mrcp_header_fields_set(&message->header,&state_machine->active_request->header,message->pool); + mrcp_header_fields_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); + mrcp_header_fields_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 [%"MRCP_REQUEST_ID_FMT"]", + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Queue Up SPEAK Request "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(message), message->start_line.request_id); message->start_line.request_state = MRCP_REQUEST_STATE_PENDING; apt_list_push_back(state_machine->queue,message,message->pool); @@ -139,18 +137,14 @@ static apt_bool_t synth_request_speak(mrcp_synth_state_machine_t *state_machine, return synth_response_dispatch(state_machine,response); } - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SPEAK Request [%"MRCP_REQUEST_ID_FMT"]", - 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 [%"MRCP_REQUEST_ID_FMT"]", - 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); + synth_state_change(state_machine,SYNTHESIZER_STATE_SPEAKING,message); } if(state_machine->is_pending == TRUE) { mrcp_message_t *event_message = mrcp_event_create( @@ -183,7 +177,9 @@ static apt_bool_t synth_pending_requests_remove(mrcp_synth_state_machine_t *stat 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); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remove Pending SPEAK Request "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(pending_message), + 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); @@ -214,7 +210,8 @@ static apt_bool_t synth_request_stop(mrcp_synth_state_machine_t *state_machine, 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 [%"MRCP_REQUEST_ID_FMT"]", + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Found IN-PROGRESS SPEAK Request "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(message), message->start_line.request_id); return synth_request_dispatch(state_machine,message); } @@ -230,19 +227,19 @@ static apt_bool_t synth_response_stop(mrcp_synth_state_machine_t *state_machine, { 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 [%"MRCP_REQUEST_ID_FMT"]", - 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_state_change(state_machine,SYNTHESIZER_STATE_IDLE,message); pending_request = apt_list_pop_front(state_machine->queue); synth_response_dispatch(state_machine,message); /* process pending SPEAK requests / if any */ if(pending_request) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process Pending SPEAK Request [%d]",pending_request->start_line.request_id); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process Pending SPEAK Request "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(message), + pending_request->start_line.request_id); state_machine->is_pending = TRUE; synth_request_dispatch(state_machine,pending_request); } @@ -254,7 +251,6 @@ static apt_bool_t synth_request_pause(mrcp_synth_state_machine_t *state_machine, 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 { @@ -274,14 +270,12 @@ static apt_bool_t synth_request_pause(mrcp_synth_state_machine_t *state_machine, 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 [%"MRCP_REQUEST_ID_FMT"]", - 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_state_change(state_machine,SYNTHESIZER_STATE_PAUSED,message); } synth_response_dispatch(state_machine,message); return TRUE; @@ -292,7 +286,6 @@ static apt_bool_t synth_request_resume(mrcp_synth_state_machine_t *state_machine 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 { @@ -312,14 +305,12 @@ static apt_bool_t synth_request_resume(mrcp_synth_state_machine_t *state_machine 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 [%"MRCP_REQUEST_ID_FMT"]", - 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_state_change(state_machine,SYNTHESIZER_STATE_SPEAKING,message); } synth_response_dispatch(state_machine,message); return TRUE; @@ -338,8 +329,6 @@ static apt_bool_t synth_request_barge_in_occurred(mrcp_synth_state_machine_t *st } if(kill_on_barge_in == TRUE) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process BARGE-IN Request [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); return synth_request_dispatch(state_machine,message); } } @@ -352,13 +341,11 @@ static apt_bool_t synth_request_barge_in_occurred(mrcp_synth_state_machine_t *st 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 [%"MRCP_REQUEST_ID_FMT"]", - 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_state_change(state_machine,SYNTHESIZER_STATE_IDLE,message); return synth_response_dispatch(state_machine,message); } @@ -366,8 +353,6 @@ static apt_bool_t synth_request_control(mrcp_synth_state_machine_t *state_machin { mrcp_message_t *response_message; if(state_machine->state == SYNTHESIZER_STATE_SPEAKING) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process CONTROL Request [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); return synth_request_dispatch(state_machine,message); } @@ -379,8 +364,6 @@ static apt_bool_t synth_request_control(mrcp_synth_state_machine_t *state_machin 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 [%"MRCP_REQUEST_ID_FMT"]", - 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); @@ -391,8 +374,6 @@ static apt_bool_t synth_request_define_lexicon(mrcp_synth_state_machine_t *state { mrcp_message_t *response_message; if(state_machine->state == SYNTHESIZER_STATE_IDLE) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process DEFINE-LEXICON Request [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); return synth_request_dispatch(state_machine,message); } @@ -404,8 +385,6 @@ static apt_bool_t synth_request_define_lexicon(mrcp_synth_state_machine_t *state 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 [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); return synth_response_dispatch(state_machine,message); } @@ -421,8 +400,6 @@ static apt_bool_t synth_event_speech_marker(mrcp_synth_state_machine_t *state_ma return FALSE; } - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SPEECH-MARKER Event [%"MRCP_REQUEST_ID_FMT"]", - message->start_line.request_id); message->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS; return synth_event_dispatch(state_machine,message); } @@ -431,36 +408,40 @@ static apt_bool_t synth_event_speak_complete(mrcp_synth_state_machine_t *state_m { mrcp_message_t *pending_request; if(!state_machine->speaker) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected SPEAK-COMPLETE Event [%"MRCP_REQUEST_ID_FMT"]", + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected SPEAK-COMPLETE Event "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(message), 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 [%"MRCP_REQUEST_ID_FMT"]", + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected SPEAK-COMPLETE Event "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(message), 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); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Ignore SPEAK-COMPLETE Event "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]: waiting for STOP response", + MRCP_MESSAGE_SIDRES(message), + message->start_line.request_id); return FALSE; } - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SPEAK-COMPLETE Event [%"MRCP_REQUEST_ID_FMT"]", - 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_state_change(state_machine,SYNTHESIZER_STATE_IDLE,message); 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); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process Pending SPEAK Request "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(pending_request), + pending_request->start_line.request_id); state_machine->is_pending = TRUE; synth_request_dispatch(state_machine,pending_request); } @@ -504,6 +485,10 @@ static apt_bool_t synth_request_state_update(mrcp_synth_state_machine_t *state_m return FALSE; } + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process %s Request "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + message->start_line.method_name.buf, + MRCP_MESSAGE_SIDRES(message), + message->start_line.request_id); method = synth_request_method_array[message->start_line.method_id]; if(method) { return method(state_machine,message); @@ -528,6 +513,10 @@ static apt_bool_t synth_response_state_update(mrcp_synth_state_machine_t *state_ return FALSE; } + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process %s Response "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + message->start_line.method_name.buf, + MRCP_MESSAGE_SIDRES(message), + message->start_line.request_id); method = synth_response_method_array[message->start_line.method_id]; if(method) { return method(state_machine,message); @@ -543,6 +532,10 @@ static apt_bool_t synth_event_state_update(mrcp_synth_state_machine_t *state_mac return FALSE; } + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process %s Event "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + message->start_line.method_name.buf, + MRCP_MESSAGE_SIDRES(message), + message->start_line.request_id); method = synth_event_method_array[message->start_line.method_id]; if(method) { return method(state_machine,message); @@ -594,7 +587,8 @@ static apt_bool_t synth_state_deactivate(mrcp_state_machine_t *base) message->start_line.request_id = source->start_line.request_id + 1; apt_string_set(&message->start_line.method_name,"DEACTIVATE"); /* informative only */ message->header = source->header; - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create and Process STOP Request [%"MRCP_REQUEST_ID_FMT"]", + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create and Process STOP Request "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(message), message->start_line.request_id); return synth_request_dispatch(state_machine,message); } @@ -602,7 +596,6 @@ static apt_bool_t synth_state_deactivate(mrcp_state_machine_t *base) /** Create MRCP synthesizer state machine */ mrcp_state_machine_t* mrcp_synth_state_machine_create(void *obj, 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); state_machine->base.update = synth_state_update; @@ -612,9 +605,9 @@ mrcp_state_machine_t* mrcp_synth_state_machine_create(void *obj, mrcp_version_e 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); + state_machine->properties = mrcp_message_header_create( + mrcp_generic_header_vtable_get(version), + mrcp_synth_header_vtable_get(version), + pool); return &state_machine->base; } diff --git a/libs/unimrcp/libs/mrcp-engine/src/mrcp_verifier_state_machine.c b/libs/unimrcp/libs/mrcp-engine/src/mrcp_verifier_state_machine.c new file mode 100644 index 0000000000..335fdc9758 --- /dev/null +++ b/libs/unimrcp/libs/mrcp-engine/src/mrcp_verifier_state_machine.c @@ -0,0 +1,525 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: mrcp_verifier_state_machine.c 1756 2010-08-19 19:02:39Z achaloyan $ + */ + +#include "apt_obj_list.h" +#include "apt_log.h" +#include "mrcp_verifier_state_machine.h" +#include "mrcp_generic_header.h" +#include "mrcp_verifier_header.h" +#include "mrcp_verifier_resource.h" +#include "mrcp_message.h" + +/** MRCP verifier states */ +typedef enum { + VERIFIER_STATE_IDLE, + VERIFIER_STATE_OPENED, + VERIFIER_STATE_VERIFYING, + + VERIFIER_STATE_COUNT +} mrcp_verifier_state_e; + +static const char * state_names[VERIFIER_STATE_COUNT] = { + "IDLE", + "OPENED", + "VERIFYING" +}; + +typedef struct mrcp_verifier_state_machine_t mrcp_verifier_state_machine_t; + +struct mrcp_verifier_state_machine_t { + /** state machine base */ + mrcp_state_machine_t base; + /** verifier state */ + mrcp_verifier_state_e state; + /** request sent to verification engine and waiting for the response to be received */ + mrcp_message_t *active_request; + /** in-progress verify request */ + mrcp_message_t *verify; + /** properties used in set/get params */ + mrcp_message_header_t *properties; +}; + +typedef apt_bool_t (*verifier_method_f)(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message); + +static APR_INLINE apt_bool_t verifier_request_dispatch(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + state_machine->active_request = message; + return state_machine->base.on_dispatch(&state_machine->base,message); +} + +static APR_INLINE apt_bool_t verifier_response_dispatch(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + state_machine->active_request = NULL; + if(state_machine->base.active == FALSE) { + /* this is the response to deactivation (STOP) request */ + return state_machine->base.on_deactivate(&state_machine->base); + } + return state_machine->base.on_dispatch(&state_machine->base,message); +} + +static APR_INLINE apt_bool_t verifier_event_dispatch(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + if(state_machine->base.active == FALSE) { + /* do nothing, state machine has already been deactivated */ + return FALSE; + } + return state_machine->base.on_dispatch(&state_machine->base,message); +} + +static APR_INLINE void verifier_state_change(mrcp_verifier_state_machine_t *state_machine, mrcp_verifier_state_e state, mrcp_message_t *message) +{ + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"State Transition %s -> %s "APT_SIDRES_FMT, + state_names[state_machine->state], + state_names[state], + MRCP_MESSAGE_SIDRES(message)); + state_machine->state = state; + if(state == VERIFIER_STATE_IDLE) { + state_machine->verify = NULL; + } +} + + +static apt_bool_t verifier_request_set_params(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + mrcp_header_fields_set(state_machine->properties,&message->header,message->pool); + return verifier_request_dispatch(state_machine,message); +} + +static apt_bool_t verifier_response_set_params(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + return verifier_response_dispatch(state_machine,message); +} + +static apt_bool_t verifier_request_get_params(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + return verifier_request_dispatch(state_machine,message); +} + +static apt_bool_t verifier_response_get_params(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + mrcp_header_fields_set(&message->header,&state_machine->active_request->header,message->pool); + mrcp_header_fields_get(&message->header,state_machine->properties,message->pool); + return verifier_response_dispatch(state_machine,message); +} + +static apt_bool_t verifier_request_start_session(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + if(state_machine->state == VERIFIER_STATE_VERIFYING) { + mrcp_message_t *response_message = mrcp_response_create(message,message->pool); + response_message->start_line.status_code = MRCP_STATUS_CODE_METHOD_NOT_VALID; + return verifier_response_dispatch(state_machine,response_message); + } + + return verifier_request_dispatch(state_machine,message); +} + +static apt_bool_t verifier_response_start_session(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + verifier_state_change(state_machine,VERIFIER_STATE_OPENED,message); + + return verifier_response_dispatch(state_machine,message); +} + +static apt_bool_t verifier_request_end_session(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + if(state_machine->state == VERIFIER_STATE_IDLE) { + mrcp_message_t *response_message = mrcp_response_create(message,message->pool); + response_message->start_line.status_code = MRCP_STATUS_CODE_METHOD_NOT_VALID; + return verifier_response_dispatch(state_machine,response_message); + } + + return verifier_request_dispatch(state_machine,message); +} + +static apt_bool_t verifier_response_end_session(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + verifier_state_change(state_machine,VERIFIER_STATE_IDLE,message); + + return verifier_response_dispatch(state_machine,message); +} + +static apt_bool_t verifier_request_query_voiceprint(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + if(state_machine->state == VERIFIER_STATE_IDLE) { + mrcp_message_t *response_message = mrcp_response_create(message,message->pool); + response_message->start_line.status_code = MRCP_STATUS_CODE_METHOD_NOT_VALID; + return verifier_response_dispatch(state_machine,response_message); + } + + return verifier_request_dispatch(state_machine,message); +} + +static apt_bool_t verifier_response_query_voiceprint(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + + return verifier_response_dispatch(state_machine,message); +} + +static apt_bool_t verifier_request_delete_voiceprint(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + if(state_machine->state == VERIFIER_STATE_IDLE) { + mrcp_message_t *response_message = mrcp_response_create(message,message->pool); + response_message->start_line.status_code = MRCP_STATUS_CODE_METHOD_NOT_VALID; + return verifier_response_dispatch(state_machine,response_message); + } + + return verifier_request_dispatch(state_machine,message); +} + +static apt_bool_t verifier_response_delete_voiceprint(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + return verifier_response_dispatch(state_machine,message); +} + +static apt_bool_t verifier_request_verify(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + if(state_machine->state == VERIFIER_STATE_IDLE || state_machine->state == VERIFIER_STATE_VERIFYING) { + mrcp_message_t *response_message = mrcp_response_create(message,message->pool); + response_message->start_line.status_code = MRCP_STATUS_CODE_METHOD_NOT_VALID; + return verifier_response_dispatch(state_machine,response_message); + } + + state_machine->verify = message; + return verifier_request_dispatch(state_machine,message); +} + +static apt_bool_t verifier_response_verify(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + verifier_state_change(state_machine,VERIFIER_STATE_VERIFYING,message); + + return verifier_response_dispatch(state_machine,message); +} + +static apt_bool_t verifier_request_verify_from_buffer(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + if(state_machine->state == VERIFIER_STATE_IDLE || state_machine->state == VERIFIER_STATE_VERIFYING) { + mrcp_message_t *response_message = mrcp_response_create(message,message->pool); + response_message->start_line.status_code = MRCP_STATUS_CODE_METHOD_NOT_VALID; + return verifier_response_dispatch(state_machine,response_message); + } + + state_machine->verify = message; + return verifier_request_dispatch(state_machine,message); +} + +static apt_bool_t verifier_response_verify_from_buffer(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + verifier_state_change(state_machine,VERIFIER_STATE_VERIFYING,message); + + return verifier_response_dispatch(state_machine,message); +} + +static apt_bool_t verifier_request_verify_rollback(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + return verifier_request_dispatch(state_machine,message); +} + +static apt_bool_t verifier_response_verify_rollback(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + return verifier_response_dispatch(state_machine,message); +} + +static apt_bool_t verifier_request_stop(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + if(state_machine->state == VERIFIER_STATE_IDLE) { + mrcp_message_t *response_message = mrcp_response_create(message,message->pool); + response_message->start_line.status_code = MRCP_STATUS_CODE_METHOD_NOT_VALID; + return verifier_response_dispatch(state_machine,response_message); + } + + if(state_machine->state == VERIFIER_STATE_OPENED) { + /* no in-progress VERIFY request, sending immediate response */ + mrcp_message_t *response_message = mrcp_response_create(message,message->pool); + return verifier_response_dispatch(state_machine,response_message); + } + + return verifier_request_dispatch(state_machine,message); +} + +static apt_bool_t verifier_response_stop(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + mrcp_generic_header_t *generic_header = mrcp_generic_header_prepare(message); + /* append active id list */ + active_request_id_list_append(generic_header,state_machine->verify->start_line.request_id); + mrcp_generic_header_property_add(message,GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST); + verifier_state_change(state_machine,VERIFIER_STATE_OPENED,message); + return verifier_response_dispatch(state_machine,message); +} + +static apt_bool_t verifier_request_clear_buffer(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + return verifier_request_dispatch(state_machine,message); +} + +static apt_bool_t verifier_response_clear_buffer(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + return verifier_response_dispatch(state_machine,message); +} + +static apt_bool_t verifier_request_start_input_timers(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + if(state_machine->state == VERIFIER_STATE_IDLE || state_machine->state == VERIFIER_STATE_VERIFYING) { + mrcp_message_t *response_message = mrcp_response_create(message,message->pool); + response_message->start_line.status_code = MRCP_STATUS_CODE_METHOD_NOT_VALID; + return verifier_response_dispatch(state_machine,response_message); + } + + return verifier_request_dispatch(state_machine,message); +} + +static apt_bool_t verifier_response_start_input_timers(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + return verifier_response_dispatch(state_machine,message); +} + +static apt_bool_t verifier_request_get_intermidiate_result(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + if(state_machine->state != VERIFIER_STATE_VERIFYING) { + mrcp_message_t *response_message = mrcp_response_create(message,message->pool); + response_message->start_line.status_code = MRCP_STATUS_CODE_METHOD_NOT_VALID; + return verifier_response_dispatch(state_machine,response_message); + } + return verifier_request_dispatch(state_machine,message); +} + +static apt_bool_t verifier_response_get_intermidiate_result(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + return verifier_response_dispatch(state_machine,message); +} + + +static apt_bool_t verifier_event_start_of_input(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + if(!state_machine->verify) { + /* unexpected event, no in-progress verify request */ + return FALSE; + } + + if(state_machine->verify->start_line.request_id != message->start_line.request_id) { + /* unexpected event */ + return FALSE; + } + + message->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS; + return verifier_event_dispatch(state_machine,message); +} + +static apt_bool_t verifier_event_verification_complete(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + if(!state_machine->verify) { + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected VERIFICATION-COMPLETE Event "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(message), + message->start_line.request_id); + return FALSE; + } + + if(state_machine->verify->start_line.request_id != message->start_line.request_id) { + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected VERIFICATION-COMPLETE Event "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(message), + message->start_line.request_id); + return FALSE; + } + + if(state_machine->active_request && state_machine->active_request->start_line.method_id == VERIFIER_STOP) { + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Ignore VERIFICATION-COMPLETE Event "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]: waiting for STOP response", + MRCP_MESSAGE_SIDRES(message), + message->start_line.request_id); + return FALSE; + } + + if(mrcp_resource_header_property_check(message,VERIFIER_HEADER_COMPLETION_CAUSE) != TRUE) { + mrcp_verifier_header_t *verifier_header = mrcp_resource_header_prepare(message); + verifier_header->completion_cause = VERIFIER_COMPLETION_CAUSE_SUCCESS; + mrcp_resource_header_property_add(message,VERIFIER_HEADER_COMPLETION_CAUSE); + } + verifier_state_change(state_machine,VERIFIER_STATE_OPENED,message); + return verifier_event_dispatch(state_machine,message); +} + +static verifier_method_f verifier_request_method_array[VERIFIER_METHOD_COUNT] = { + verifier_request_set_params, + verifier_request_get_params, + verifier_request_start_session, + verifier_request_end_session, + verifier_request_query_voiceprint, + verifier_request_delete_voiceprint, + verifier_request_verify, + verifier_request_verify_from_buffer, + verifier_request_verify_rollback, + verifier_request_stop, + verifier_request_clear_buffer, + verifier_request_start_input_timers, + verifier_request_get_intermidiate_result +}; + +static verifier_method_f verifier_response_method_array[VERIFIER_METHOD_COUNT] = { + verifier_response_set_params, + verifier_response_get_params, + verifier_response_start_session, + verifier_response_end_session, + verifier_response_query_voiceprint, + verifier_response_delete_voiceprint, + verifier_response_verify, + verifier_response_verify_from_buffer, + verifier_response_verify_rollback, + verifier_response_stop, + verifier_response_clear_buffer, + verifier_response_start_input_timers, + verifier_response_get_intermidiate_result +}; + +static verifier_method_f verifier_event_method_array[VERIFIER_EVENT_COUNT] = { + verifier_event_start_of_input, + verifier_event_verification_complete +}; + +/** Update state according to received incoming request from MRCP client */ +static apt_bool_t verifier_request_state_update(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + verifier_method_f method; + if(message->start_line.method_id >= VERIFIER_METHOD_COUNT) { + return FALSE; + } + + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process %s Request "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + message->start_line.method_name.buf, + MRCP_MESSAGE_SIDRES(message), + message->start_line.request_id); + method = verifier_request_method_array[message->start_line.method_id]; + if(method) { + return method(state_machine,message); + } + return verifier_request_dispatch(state_machine,message); +} + +/** Update state according to received outgoing response from verification engine */ +static apt_bool_t verifier_response_state_update(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + verifier_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 >= VERIFIER_METHOD_COUNT) { + return FALSE; + } + + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process %s Response "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + message->start_line.method_name.buf, + MRCP_MESSAGE_SIDRES(message), + message->start_line.request_id); + method = verifier_response_method_array[message->start_line.method_id]; + if(method) { + return method(state_machine,message); + } + return verifier_response_dispatch(state_machine,message); +} + +/** Update state according to received outgoing event from verification engine */ +static apt_bool_t verifier_event_state_update(mrcp_verifier_state_machine_t *state_machine, mrcp_message_t *message) +{ + verifier_method_f method; + if(message->start_line.method_id >= VERIFIER_EVENT_COUNT) { + return FALSE; + } + + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process %s Event "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + message->start_line.method_name.buf, + MRCP_MESSAGE_SIDRES(message), + message->start_line.request_id); + method = verifier_event_method_array[message->start_line.method_id]; + if(method) { + return method(state_machine,message); + } + return verifier_event_dispatch(state_machine,message); +} + +/** Update state according to request received from MRCP client or response/event received from verification engine */ +static apt_bool_t verifier_state_update(mrcp_state_machine_t *base, mrcp_message_t *message) +{ + mrcp_verifier_state_machine_t *state_machine = (mrcp_verifier_state_machine_t*)base; + apt_bool_t status = TRUE; + switch(message->start_line.message_type) { + case MRCP_MESSAGE_TYPE_REQUEST: + status = verifier_request_state_update(state_machine,message); + break; + case MRCP_MESSAGE_TYPE_RESPONSE: + status = verifier_response_state_update(state_machine,message); + break; + case MRCP_MESSAGE_TYPE_EVENT: + status = verifier_event_state_update(state_machine,message); + break; + default: + status = FALSE; + break; + } + return status; +} + +/** Deactivate state machine */ +static apt_bool_t verifier_state_deactivate(mrcp_state_machine_t *base) +{ + mrcp_verifier_state_machine_t *state_machine = (mrcp_verifier_state_machine_t*)base; + mrcp_message_t *message; + mrcp_message_t *source; + if(state_machine->state != VERIFIER_STATE_VERIFYING) { + /* no in-progress VERIFY request to deactivate */ + return FALSE; + } + source = state_machine->verify; + if(!source) { + return FALSE; + } + + /* create internal STOP request */ + message = mrcp_request_create( + source->resource, + source->start_line.version, + VERIFIER_STOP, + source->pool); + message->channel_id = source->channel_id; + message->start_line.request_id = source->start_line.request_id + 1; + apt_string_set(&message->start_line.method_name,"DEACTIVATE"); /* informative only */ + message->header = source->header; + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create and Process STOP Request "APT_SIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]", + MRCP_MESSAGE_SIDRES(message), + message->start_line.request_id); + return verifier_request_dispatch(state_machine,message); +} + +/** Create MRCP verification state machine */ +mrcp_state_machine_t* mrcp_verifier_state_machine_create(void *obj, mrcp_version_e version, apr_pool_t *pool) +{ + mrcp_verifier_state_machine_t *state_machine = apr_palloc(pool,sizeof(mrcp_verifier_state_machine_t)); + mrcp_state_machine_init(&state_machine->base,obj); + state_machine->base.update = verifier_state_update; + state_machine->base.deactivate = verifier_state_deactivate; + state_machine->state = VERIFIER_STATE_IDLE; + state_machine->active_request = NULL; + state_machine->verify = NULL; + state_machine->properties = mrcp_message_header_create( + mrcp_generic_header_vtable_get(version), + mrcp_verifier_header_vtable_get(version), + pool); + return &state_machine->base; +} diff --git a/libs/unimrcp/libs/mrcp-server/include/mrcp_server.h b/libs/unimrcp/libs/mrcp-server/include/mrcp_server.h index 59a33db059..f2bf49fe37 100644 --- a/libs/unimrcp/libs/mrcp-server/include/mrcp_server.h +++ b/libs/unimrcp/libs/mrcp-server/include/mrcp_server.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_server.h 1721 2010-06-01 05:45:46Z achaloyan $ */ -#ifndef __MRCP_SERVER_H__ -#define __MRCP_SERVER_H__ +#ifndef MRCP_SERVER_H +#define MRCP_SERVER_H /** * @file mrcp_server.h @@ -24,6 +26,7 @@ #include "mrcp_server_types.h" #include "mrcp_engine_iface.h" +#include "mpf_rtp_descriptor.h" #include "apt_task.h" APT_BEGIN_EXTERN_C @@ -59,15 +62,18 @@ MRCP_DECLARE(apt_bool_t) mrcp_server_destroy(mrcp_server_t *server); * @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); +MRCP_DECLARE(apt_bool_t) mrcp_server_resource_factory_register( + mrcp_server_t *server, + mrcp_resource_factory_t *resource_factory); /** * Register MRCP engine. * @param server the MRCP server to set engine for * @param engine the engine to set - * @param config the config of the engine */ -MRCP_DECLARE(apt_bool_t) mrcp_server_engine_register(mrcp_server_t *server, mrcp_engine_t *engine, mrcp_engine_config_t *config); +MRCP_DECLARE(apt_bool_t) mrcp_server_engine_register( + mrcp_server_t *server, + mrcp_engine_t *engine); /** * Register codec manager. @@ -80,15 +86,16 @@ MRCP_DECLARE(apt_bool_t) mrcp_server_codec_manager_register(mrcp_server_t *serve * 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); +MRCP_DECLARE(const mpf_codec_manager_t*) mrcp_server_codec_manager_get(const 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); +MRCP_DECLARE(apt_bool_t) mrcp_server_media_engine_register( + mrcp_server_t *server, + mpf_engine_t *media_engine); /** * Register RTP termination factory. @@ -96,95 +103,123 @@ MRCP_DECLARE(apt_bool_t) mrcp_server_media_engine_register(mrcp_server_t *server * @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); +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 RTP settings. + * @param server the MRCP server to set RTP settings for + * @param rtp_settings the settings to set + * @param name the name of the settings + */ +MRCP_DECLARE(apt_bool_t) mrcp_server_rtp_settings_register( + mrcp_server_t *server, + mpf_rtp_settings_t *rtp_settings, + 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); +MRCP_DECLARE(apt_bool_t) mrcp_server_signaling_agent_register( + mrcp_server_t *server, + mrcp_sig_agent_t *signaling_agent); /** * 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); +MRCP_DECLARE(apt_bool_t) mrcp_server_connection_agent_register( + mrcp_server_t *server, + mrcp_connection_agent_t *connection_agent); /** 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); + const char *id, + 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, + mpf_rtp_settings_t *rtp_settings, + 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 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); + apr_table_t *plugin_map); /** - * Register MRCP engine plugin. - * @param server the MRCP server to set engine for - * @param path the path to plugin - * @param config the config of the plugin + * Load MRCP engine as a plugin. + * @param server the MRCP server to use + * @param id the identifier of the plugin + * @param path the path to the plugin to load + * @param config the config of the engine */ -MRCP_DECLARE(apt_bool_t) mrcp_server_plugin_register(mrcp_server_t *server, const char *path, mrcp_engine_config_t *config); +MRCP_DECLARE(mrcp_engine_t*) mrcp_server_engine_load( + mrcp_server_t *server, + const char *id, + const char *path, + mrcp_engine_config_t *config); /** * 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); +MRCP_DECLARE(apr_pool_t*) mrcp_server_memory_pool_get(const mrcp_server_t *server); /** * 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); +MRCP_DECLARE(mpf_engine_t*) mrcp_server_media_engine_get(const 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); +MRCP_DECLARE(mpf_termination_factory_t*) mrcp_server_rtp_factory_get(const mrcp_server_t *server, const char *name); + +/** + * Get RTP settings by name + * @param server the MRCP server to get from + * @param name the name to lookup + */ +MRCP_DECLARE(mpf_rtp_settings_t*) mrcp_server_rtp_settings_get(const 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); +MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_server_signaling_agent_get(const 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); +MRCP_DECLARE(mrcp_connection_agent_t*) mrcp_server_connection_agent_get(const 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); +MRCP_DECLARE(mrcp_profile_t*) mrcp_server_profile_get(const mrcp_server_t *server, const char *name); APT_END_EXTERN_C -#endif /*__MRCP_SERVER_H__*/ +#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 index 4cd88f6b3e..07258f0298 100644 --- a/libs/unimrcp/libs/mrcp-server/include/mrcp_server_session.h +++ b/libs/unimrcp/libs/mrcp-server/include/mrcp_server_session.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_server_session.h 1700 2010-05-21 18:56:06Z achaloyan $ */ -#ifndef __MRCP_SERVER_SESSION_H__ -#define __MRCP_SERVER_SESSION_H__ +#ifndef MRCP_SERVER_SESSION_H +#define MRCP_SERVER_SESSION_H /** * @file mrcp_server_session.h @@ -109,6 +111,8 @@ struct mrcp_server_session_t { /** MRCP profile */ struct mrcp_profile_t { + /** Identifier of the profile */ + const char *id; /** Table of engines (mrcp_engine_t*) */ apr_hash_t *engine_table; /** MRCP resource factory */ @@ -117,6 +121,8 @@ struct mrcp_profile_t { mpf_engine_t *media_engine; /** RTP termination factory */ mpf_termination_factory_t *rtp_termination_factory; + /** RTP settings */ + mpf_rtp_settings_t *rtp_settings; /** Signaling agent */ mrcp_sig_agent_t *signaling_agent; /** Connection agent */ @@ -152,4 +158,4 @@ mrcp_session_t* mrcp_server_channel_session_get(mrcp_channel_t *channel); APT_END_EXTERN_C -#endif /*__MRCP_SERVER_SESSION_H__*/ +#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 index ac640fc750..2c9f3f0be8 100644 --- a/libs/unimrcp/libs/mrcp-server/include/mrcp_server_types.h +++ b/libs/unimrcp/libs/mrcp-server/include/mrcp_server_types.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_server_types.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MRCP_SERVER_TYPES_H__ -#define __MRCP_SERVER_TYPES_H__ +#ifndef MRCP_SERVER_TYPES_H +#define MRCP_SERVER_TYPES_H /** * @file mrcp_server_types.h @@ -37,4 +39,4 @@ typedef struct mrcp_profile_t mrcp_profile_t; APT_END_EXTERN_C -#endif /*__MRCP_SERVER_TYPES_H__*/ +#endif /* MRCP_SERVER_TYPES_H */ diff --git a/libs/unimrcp/libs/mrcp-server/mrcpserver.2008.vcproj b/libs/unimrcp/libs/mrcp-server/mrcpserver.2008.vcproj deleted file mode 100644 index fe124d4a8a..0000000000 --- a/libs/unimrcp/libs/mrcp-server/mrcpserver.2008.vcproj +++ /dev/null @@ -1,162 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/unimrcp/libs/mrcp-server/src/mrcp_server.c b/libs/unimrcp/libs/mrcp-server/src/mrcp_server.c index 0c8d2a8a07..bd1b6aa848 100644 --- a/libs/unimrcp/libs/mrcp-server/src/mrcp_server.c +++ b/libs/unimrcp/libs/mrcp-server/src/mrcp_server.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_server.c 1721 2010-06-01 05:45:46Z achaloyan $ */ #include "mrcp_server.h" @@ -53,6 +55,8 @@ struct mrcp_server_t { apr_hash_t *sig_agent_table; /** Table of connection agents (mrcp_connection_agent_t*) */ apr_hash_t *cnt_agent_table; + /** Table of RTP settings (mpf_rtp_settings_t*) */ + apr_hash_t *rtp_settings_table; /** Table of profiles (mrcp_profile_t*) */ apr_hash_t *profile_table; @@ -126,6 +130,8 @@ static const mrcp_connection_event_vtable_t connection_method_vtable = { /* MRCP engine interface */ typedef enum { + ENGINE_TASK_MSG_OPEN_ENGINE, + ENGINE_TASK_MSG_CLOSE_ENGINE, ENGINE_TASK_MSG_OPEN_CHANNEL, ENGINE_TASK_MSG_CLOSE_CHANNEL, ENGINE_TASK_MSG_MESSAGE @@ -133,11 +139,20 @@ typedef enum { typedef struct engine_task_msg_data_t engine_task_msg_data_t; struct engine_task_msg_data_t { + mrcp_engine_t *engine; mrcp_channel_t *channel; apt_bool_t status; mrcp_message_t *mrcp_message; }; +static apt_bool_t mrcp_server_engine_open_signal(mrcp_engine_t *engine, apt_bool_t status); +static apt_bool_t mrcp_server_engine_close_signal(mrcp_engine_t *engine); + +const mrcp_engine_event_vtable_t engine_vtable = { + mrcp_server_engine_open_signal, + mrcp_server_engine_close_signal, +}; + 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); @@ -149,6 +164,8 @@ const mrcp_engine_channel_event_vtable_t engine_channel_vtable = { }; /* Task interface */ +static void mrcp_server_on_start_request(apt_task_t *task); +static void mrcp_server_on_terminate_request(apt_task_t *task); 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); @@ -181,6 +198,7 @@ MRCP_DECLARE(mrcp_server_t*) mrcp_server_create(apt_dir_layout_t *dir_layout) server->rtp_factory_table = NULL; server->sig_agent_table = NULL; server->cnt_agent_table = NULL; + server->rtp_settings_table = NULL; server->profile_table = NULL; server->session_table = NULL; server->connection_msg_pool = NULL; @@ -198,6 +216,8 @@ MRCP_DECLARE(mrcp_server_t*) mrcp_server_create(apt_dir_layout_t *dir_layout) vtable = apt_task_vtable_get(task); if(vtable) { vtable->process_msg = mrcp_server_msg_process; + vtable->on_start_request = mrcp_server_on_start_request; + vtable->on_terminate_request = mrcp_server_on_terminate_request; vtable->on_start_complete = mrcp_server_on_start_complete; vtable->on_terminate_complete = mrcp_server_on_terminate_complete; } @@ -207,6 +227,7 @@ MRCP_DECLARE(mrcp_server_t*) mrcp_server_create(apt_dir_layout_t *dir_layout) server->media_engine_table = apr_hash_make(server->pool); server->rtp_factory_table = apr_hash_make(server->pool); + server->rtp_settings_table = apr_hash_make(server->pool); server->sig_agent_table = apr_hash_make(server->pool); server->cnt_agent_table = apr_hash_make(server->pool); @@ -249,7 +270,7 @@ MRCP_DECLARE(apt_bool_t) mrcp_server_shutdown(mrcp_server_t *server) } 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)); + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Server Uptime [%"APR_TIME_T_FMT" sec]", apr_time_sec(uptime)); return TRUE; } @@ -284,19 +305,21 @@ MRCP_DECLARE(apt_bool_t) mrcp_server_resource_factory_register(mrcp_server_t *se } /** Register MRCP engine */ -MRCP_DECLARE(apt_bool_t) mrcp_server_engine_register(mrcp_server_t *server, mrcp_engine_t *engine, mrcp_engine_config_t *config) +MRCP_DECLARE(apt_bool_t) mrcp_server_engine_register(mrcp_server_t *server, mrcp_engine_t *engine) { - if(!engine || !config || !config->name) { + if(!engine || !engine->id) { return FALSE; } + if(!server->engine_msg_pool) { server->engine_msg_pool = apt_task_msg_pool_create_dynamic(sizeof(engine_task_msg_data_t),server->pool); } - engine->config = config; engine->codec_manager = server->codec_manager; engine->dir_layout = server->dir_layout; - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register MRCP Engine [%s]",config->name); - return mrcp_engine_factory_engine_register(server->engine_factory,engine,config->name); + engine->event_vtable = &engine_vtable; + engine->event_obj = server; + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register MRCP Engine [%s]",engine->id); + return mrcp_engine_factory_engine_register(server->engine_factory,engine); } /** Register codec manager */ @@ -310,20 +333,26 @@ MRCP_DECLARE(apt_bool_t) mrcp_server_codec_manager_register(mrcp_server_t *serve } /** Get registered codec manager */ -MRCP_DECLARE(const mpf_codec_manager_t*) mrcp_server_codec_manager_get(mrcp_server_t *server) +MRCP_DECLARE(const mpf_codec_manager_t*) mrcp_server_codec_manager_get(const 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) +MRCP_DECLARE(apt_bool_t) mrcp_server_media_engine_register(mrcp_server_t *server, mpf_engine_t *media_engine) { - if(!media_engine || !name) { + const char *id; + if(!media_engine) { + return FALSE; + } + id = mpf_engine_id_get(media_engine); + if(!id) { return FALSE; } - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Media Engine [%s]",name); + + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Media Engine [%s]",id); mpf_engine_codec_manager_register(media_engine,server->codec_manager); - apr_hash_set(server->media_engine_table,name,APR_HASH_KEY_STRING,media_engine); + apr_hash_set(server->media_engine_table,id,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); @@ -334,7 +363,7 @@ MRCP_DECLARE(apt_bool_t) mrcp_server_media_engine_register(mrcp_server_t *server } /** Get media engine by name */ -MRCP_DECLARE(mpf_engine_t*) mrcp_server_media_engine_get(mrcp_server_t *server, const char *name) +MRCP_DECLARE(mpf_engine_t*) mrcp_server_media_engine_get(const mrcp_server_t *server, const char *name) { return apr_hash_get(server->media_engine_table,name,APR_HASH_KEY_STRING); } @@ -351,23 +380,40 @@ MRCP_DECLARE(apt_bool_t) mrcp_server_rtp_factory_register(mrcp_server_t *server, } /** Get RTP termination factory by name */ -MRCP_DECLARE(mpf_termination_factory_t*) mrcp_server_rtp_factory_get(mrcp_server_t *server, const char *name) +MRCP_DECLARE(mpf_termination_factory_t*) mrcp_server_rtp_factory_get(const mrcp_server_t *server, const char *name) { return apr_hash_get(server->rtp_factory_table,name,APR_HASH_KEY_STRING); } +/** Register RTP settings */ +MRCP_DECLARE(apt_bool_t) mrcp_server_rtp_settings_register(mrcp_server_t *server, mpf_rtp_settings_t *rtp_settings, const char *name) +{ + if(!rtp_settings || !name) { + return FALSE; + } + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register RTP Settings [%s]",name); + apr_hash_set(server->rtp_settings_table,name,APR_HASH_KEY_STRING,rtp_settings); + return TRUE; +} + +/** Get RTP settings by name */ +MRCP_DECLARE(mpf_rtp_settings_t*) mrcp_server_rtp_settings_get(const mrcp_server_t *server, const char *name) +{ + return apr_hash_get(server->rtp_settings_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) +MRCP_DECLARE(apt_bool_t) mrcp_server_signaling_agent_register(mrcp_server_t *server, mrcp_sig_agent_t *signaling_agent) { - if(!signaling_agent || !name) { + if(!signaling_agent || !signaling_agent->id) { return FALSE; } - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Signaling Agent [%s]",name); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Signaling Agent [%s]",signaling_agent->id); 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); + apr_hash_set(server->sig_agent_table,signaling_agent->id,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); @@ -376,22 +422,27 @@ MRCP_DECLARE(apt_bool_t) mrcp_server_signaling_agent_register(mrcp_server_t *ser } /** Get signaling agent by name */ -MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_server_signaling_agent_get(mrcp_server_t *server, const char *name) +MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_server_signaling_agent_get(const 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) +MRCP_DECLARE(apt_bool_t) mrcp_server_connection_agent_register(mrcp_server_t *server, mrcp_connection_agent_t *connection_agent) { - if(!connection_agent || !name) { + const char *id; + if(!connection_agent) { return FALSE; } - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Connection Agent [%s]",name); + id = mrcp_server_connection_agent_id_get(connection_agent); + if(!id) { + return FALSE; + } + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Connection Agent [%s]",id); 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); + apr_hash_set(server->cnt_agent_table,id,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); @@ -401,25 +452,29 @@ MRCP_DECLARE(apt_bool_t) mrcp_server_connection_agent_register(mrcp_server_t *se } /** Get connection agent by name */ -MRCP_DECLARE(mrcp_connection_agent_t*) mrcp_server_connection_agent_get(mrcp_server_t *server, const char *name) +MRCP_DECLARE(mrcp_connection_agent_t*) mrcp_server_connection_agent_get(const 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( + const char *id, 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, + mpf_rtp_settings_t *rtp_settings, apr_pool_t *pool) { mrcp_profile_t *profile = apr_palloc(pool,sizeof(mrcp_profile_t)); + profile->id = id; profile->resource_factory = resource_factory; profile->engine_table = NULL; profile->media_engine = media_engine; profile->rtp_termination_factory = rtp_factory; + profile->rtp_settings = rtp_settings; profile->signaling_agent = signaling_agent; profile->connection_agent = connection_agent; return profile; @@ -452,8 +507,8 @@ static apt_bool_t mrcp_server_engine_table_make(mrcp_server_t *server, mrcp_prof } if(engine) { - if(engine->config->name) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Assign MRCP Engine [%s] [%s]",resource->name.buf,engine->config->name); + if(engine->id) { + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Assign MRCP Engine [%s] [%s]",resource->name.buf,engine->id); } apr_hash_set(profile->engine_table,resource->name.buf,resource->name.length,engine); } @@ -467,18 +522,17 @@ static apt_bool_t mrcp_server_engine_table_make(mrcp_server_t *server, mrcp_prof /** 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) + mrcp_server_t *server, + mrcp_profile_t *profile, + apr_table_t *plugin_map) { - if(!profile || !name) { + if(!profile || !profile->id) { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Register Profile: no name"); return FALSE; } if(!profile->resource_factory) { if(!server->resource_factory) { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Register Profile: no resources"); + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Register Profile [%s]: missing resource factory",profile->id); return FALSE; } profile->resource_factory = server->resource_factory; @@ -486,58 +540,55 @@ MRCP_DECLARE(apt_bool_t) mrcp_server_profile_register( 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); + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Register Profile [%s]: missing signaling agent",profile->id); 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); + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Register Profile [%s]: missing connection agent",profile->id); return FALSE; } if(!profile->media_engine) { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Register Profile [%s]: missing media engine",name); + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Register Profile [%s]: missing media engine",profile->id); return FALSE; } if(!profile->rtp_termination_factory) { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Register Profile [%s]: missing RTP factory",name); + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Register Profile [%s]: missing RTP factory",profile->id); 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); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Profile [%s]",profile->id); + apr_hash_set(server->profile_table,profile->id,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) +MRCP_DECLARE(mrcp_profile_t*) mrcp_server_profile_get(const mrcp_server_t *server, const char *name) { return apr_hash_get(server->profile_table,name,APR_HASH_KEY_STRING); } -/** Register MRCP engine plugin */ -MRCP_DECLARE(apt_bool_t) mrcp_server_plugin_register(mrcp_server_t *server, const char *path, mrcp_engine_config_t *config) +/** Load MRCP engine */ +MRCP_DECLARE(mrcp_engine_t*) mrcp_server_engine_load( + mrcp_server_t *server, + const char *id, + const char *path, + mrcp_engine_config_t *config) { mrcp_engine_t *engine; - if(!config) { + if(!id || !path || !config) { return FALSE; } - - engine = mrcp_engine_loader_plugin_load(server->engine_loader,path,config->name); + + engine = mrcp_engine_loader_plugin_load(server->engine_loader,id,path,config); if(!engine) { return FALSE; } - if(!server->engine_msg_pool) { - server->engine_msg_pool = apt_task_msg_pool_create_dynamic(sizeof(engine_task_msg_data_t),server->pool); - } - engine->config = config; - engine->codec_manager = server->codec_manager; - engine->dir_layout = server->dir_layout; - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register MRCP Engine [%s]",config->name); - return mrcp_engine_factory_engine_register(server->engine_factory,engine,config->name); + return engine; } -MRCP_DECLARE(apr_pool_t*) mrcp_server_memory_pool_get(mrcp_server_t *server) +MRCP_DECLARE(apr_pool_t*) mrcp_server_memory_pool_get(const mrcp_server_t *server) { return server->pool; } @@ -563,22 +614,53 @@ static APR_INLINE mrcp_server_session_t* mrcp_server_session_find(mrcp_server_t return apr_hash_get(server->session_table,session_id->buf,session_id->length); } - -static void mrcp_server_on_start_complete(apt_task_t *task) +static void mrcp_server_on_start_request(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_engine_factory_open(server->engine_factory); - apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,SERVER_TASK_NAME" Started"); + mrcp_engine_t *engine; + apr_hash_index_t *it; + void *val; + it = mrcp_engine_factory_engine_first(server->engine_factory); + for(; it; it = apr_hash_next(it)) { + apr_hash_this(it,NULL,NULL,&val); + engine = val; + if(engine) { + if(mrcp_engine_virtual_open(engine) == TRUE) { + apt_task_start_request_add(task); + } + } + } } -static void mrcp_server_on_terminate_complete(apt_task_t *task) +static void mrcp_server_on_terminate_request(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_engine_factory_close(server->engine_factory); + mrcp_engine_t *engine; + apr_hash_index_t *it; + void *val; + it = mrcp_engine_factory_engine_first(server->engine_factory); + for(; it; it = apr_hash_next(it)) { + apr_hash_this(it,NULL,NULL,&val); + engine = val; + if(engine) { + if(mrcp_engine_virtual_close(engine) == TRUE) { + apt_task_terminate_request_add(task); + } + } + } +} + +static void mrcp_server_on_start_complete(apt_task_t *task) +{ + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,SERVER_TASK_NAME" Started"); +} + +static void mrcp_server_on_terminate_complete(apt_task_t *task) +{ apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,SERVER_TASK_NAME" Terminated"); } @@ -588,14 +670,12 @@ static apt_bool_t mrcp_server_msg_process(apt_task_t *task, apt_task_msg_t *msg) 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: { @@ -630,8 +710,15 @@ static apt_bool_t mrcp_server_msg_process(apt_task_t *task, apt_task_msg_t *msg) case MRCP_SERVER_ENGINE_TASK_MSG: { engine_task_msg_data_t *data = (engine_task_msg_data_t*)msg->data; - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Receive Engine Task Message [%d]", msg->sub_type); switch(msg->sub_type) { + case ENGINE_TASK_MSG_OPEN_ENGINE: + mrcp_engine_on_open(data->engine,data->status); + apt_task_start_request_remove(task); + break; + case ENGINE_TASK_MSG_CLOSE_ENGINE: + mrcp_engine_on_close(data->engine); + apt_task_terminate_request_remove(task); + break; case ENGINE_TASK_MSG_OPEN_CHANNEL: mrcp_server_on_engine_channel_open(data->channel,data->status); break; @@ -649,13 +736,12 @@ static apt_bool_t mrcp_server_msg_process(apt_task_t *task, apt_task_msg_t *msg) case MRCP_SERVER_MEDIA_TASK_MSG: { mpf_message_container_t *mpf_message_container = (mpf_message_container_t*) msg->data; - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Receive Media Task Message"); mrcp_server_mpf_message_process(mpf_message_container); break; } default: { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Receive Unknown Task Message [%d]", msg->type); + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Task Message Received [%d;%d]", msg->type,msg->sub_type); break; } } @@ -678,7 +764,6 @@ static apt_bool_t mrcp_server_signaling_task_msg_signal(mrcp_signaling_message_t 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); } @@ -702,15 +787,34 @@ static apt_bool_t mrcp_server_connection_task_msg_signal( 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( engine_task_msg_type_e type, - mrcp_engine_channel_t *engine_channel, - apt_bool_t status, - mrcp_message_t *message) + mrcp_engine_t *engine, + apt_bool_t status) +{ + mrcp_server_t *server = engine->event_obj; + apt_task_t *task = apt_consumer_task_base_get(server->task); + engine_task_msg_data_t *data; + apt_task_msg_t *task_msg = apt_task_msg_acquire(server->engine_msg_pool); + task_msg->type = MRCP_SERVER_ENGINE_TASK_MSG; + task_msg->sub_type = type; + data = (engine_task_msg_data_t*) task_msg->data; + data->engine = engine; + data->channel = NULL; + data->status = status; + data->mrcp_message = NULL; + + return apt_task_msg_signal(task,task_msg); +} + +static apt_bool_t mrcp_server_channel_task_msg_signal( + 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); @@ -721,11 +825,11 @@ static apt_bool_t mrcp_server_engine_task_msg_signal( task_msg->type = MRCP_SERVER_ENGINE_TASK_MSG; task_msg->sub_type = type; data = (engine_task_msg_data_t*) task_msg->data; + data->engine = engine_channel->engine; data->channel = channel; data->status = status; data->mrcp_message = message; - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Signal Engine Task Message"); return apt_task_msg_signal(task,task_msg); } @@ -734,19 +838,14 @@ static mrcp_profile_t* mrcp_server_profile_get_by_agent(mrcp_server_t *server, m 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); + apr_hash_this(it,NULL,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); + if(profile && profile->signaling_agent == signaling_agent) { return profile; } } - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot Find Profile by Agent "APT_SID_FMT,MRCP_SESSION_SID(&session->base)); return NULL; } @@ -757,9 +856,16 @@ static mrcp_session_t* mrcp_server_sig_agent_session_create(mrcp_sig_agent_t *si session->server = server; session->profile = mrcp_server_profile_get_by_agent(server,session,signaling_agent); if(!session->profile) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot Find Profile by Agent "APT_NAMESID_FMT, + session->base.name, + MRCP_SESSION_SID(&session->base)); mrcp_session_destroy(&session->base); return NULL; } + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create Session "APT_NAMESID_FMT" [%s]", + session->base.name, + MRCP_SESSION_SID(&session->base), + session->profile->id); session->base.signaling_agent = signaling_agent; session->base.request_vtable = &session_request_vtable; return &session->base; @@ -840,9 +946,25 @@ static apt_bool_t mrcp_server_disconnect_signal(mrcp_control_channel_t *channel) TRUE); } -static apt_bool_t mrcp_server_channel_open_signal(mrcp_engine_channel_t *channel, apt_bool_t status) +static apt_bool_t mrcp_server_engine_open_signal(mrcp_engine_t *engine, apt_bool_t status) +{ + return mrcp_server_engine_task_msg_signal( + ENGINE_TASK_MSG_OPEN_ENGINE, + engine, + status); +} + +static apt_bool_t mrcp_server_engine_close_signal(mrcp_engine_t *engine) { return mrcp_server_engine_task_msg_signal( + ENGINE_TASK_MSG_CLOSE_ENGINE, + engine, + TRUE); +} + +static apt_bool_t mrcp_server_channel_open_signal(mrcp_engine_channel_t *channel, apt_bool_t status) +{ + return mrcp_server_channel_task_msg_signal( ENGINE_TASK_MSG_OPEN_CHANNEL, channel, status, @@ -851,7 +973,7 @@ static apt_bool_t mrcp_server_channel_open_signal(mrcp_engine_channel_t *channel static apt_bool_t mrcp_server_channel_close_signal(mrcp_engine_channel_t *channel) { - return mrcp_server_engine_task_msg_signal( + return mrcp_server_channel_task_msg_signal( ENGINE_TASK_MSG_CLOSE_CHANNEL, channel, TRUE, @@ -860,7 +982,7 @@ static apt_bool_t mrcp_server_channel_close_signal(mrcp_engine_channel_t *channe 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( + return mrcp_server_channel_task_msg_signal( ENGINE_TASK_MSG_MESSAGE, channel, TRUE, diff --git a/libs/unimrcp/libs/mrcp-server/src/mrcp_server_session.c b/libs/unimrcp/libs/mrcp-server/src/mrcp_server_session.c index b254300921..9a18b9ae14 100644 --- a/libs/unimrcp/libs/mrcp-server/src/mrcp_server_session.c +++ b/libs/unimrcp/libs/mrcp-server/src/mrcp_server_session.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_server_session.c 1794 2011-01-20 18:59:01Z achaloyan $ */ #include "mrcp_server.h" @@ -30,6 +32,10 @@ #include "apt_consumer_task.h" #include "apt_log.h" +/** Macro to log session name and identifier */ +#define MRCP_SESSION_NAMESID(session) \ + session->base.name, MRCP_SESSION_SID(&session->base) + #define MRCP_SESSION_ID_HEX_STRING_LENGTH 16 struct mrcp_channel_t { @@ -106,6 +112,7 @@ mrcp_server_session_t* mrcp_server_session_create() session->mpf_task_msg = NULL; session->subrequest_count = 0; session->state = SESSION_STATE_NONE; + session->base.name = apr_psprintf(session->base.pool,"0x%pp",session); return session; } @@ -124,7 +131,9 @@ static mrcp_engine_channel_t* mrcp_server_engine_channel_create( resource_name->buf, resource_name->length); if(!engine) { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Find MRCP Engine [%s]",resource_name->buf); + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Find MRCP Engine "APT_NAMESID_FMT" [%s]", + MRCP_SESSION_NAMESID(session), + resource_name->buf); return NULL; } @@ -177,17 +186,22 @@ static mrcp_channel_t* mrcp_server_channel_create(mrcp_server_session_t *session channel->engine_channel = engine_channel; } else { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Engine Channel [%s]",resource_name->buf); + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Engine Channel "APT_NAMESID_FMT" [%s]", + MRCP_SESSION_NAMESID(session), + 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); + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Such Resource "APT_NAMESID_FMT" [%s]", + MRCP_SESSION_NAMESID(session), + resource_name->buf); session->answer->status = MRCP_SESSION_STATUS_NO_SUCH_RESOURCE; } } else { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Invalid Resource Identifier"); + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Invalid Resource Identifier "APT_NAMESID_FMT, + MRCP_SESSION_NAMESID(session)); session->answer->status = MRCP_SESSION_STATUS_NO_SUCH_RESOURCE; } @@ -245,7 +259,8 @@ apt_bool_t mrcp_server_signaling_message_process(mrcp_signaling_message_t *signa { 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_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Push Request to Queue "APT_NAMESID_FMT, + MRCP_SESSION_NAMESID(session)); apt_list_push_back(session->request_queue,signaling_message,session->base.pool); } else { @@ -258,7 +273,9 @@ apt_bool_t mrcp_server_signaling_message_process(mrcp_signaling_message_t *signa 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"); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Control Channel Modified "APT_NAMESIDRES_FMT, + MRCP_SESSION_NAMESID(session), + channel->resource->name.buf); if(!answer) { return FALSE; } @@ -275,7 +292,9 @@ apt_bool_t mrcp_server_on_channel_modify(mrcp_channel_t *channel, mrcp_control_d 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"); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Control Channel Removed "APT_NAMESIDRES_FMT, + MRCP_SESSION_NAMESID(session), + channel->resource->name.buf); if(!channel->waiting_for_channel) { return FALSE; } @@ -306,7 +325,10 @@ apt_bool_t mrcp_server_on_disconnect(mrcp_channel_t *channel) 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"); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Engine Channel Opened "APT_NAMESIDRES_FMT" [%s]", + MRCP_SESSION_NAMESID(session), + channel->resource->name.buf, + status == TRUE ? "OK" : "Failed"); if(status == FALSE) { session->answer->status = MRCP_SESSION_STATUS_UNAVAILABLE_RESOURCE; } @@ -317,7 +339,9 @@ apt_bool_t mrcp_server_on_engine_channel_open(mrcp_channel_t *channel, apt_bool_ 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"); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Engine Channel Closed "APT_NAMESIDRES_FMT, + MRCP_SESSION_NAMESID(session), + channel->resource->name.buf); mrcp_server_session_subrequest_remove(session); return TRUE; } @@ -366,10 +390,13 @@ static apt_bool_t mrcp_server_session_offer_process(mrcp_server_session_t *sessi } mrcp_server_session_add(session); - session->context = mpf_engine_context_create(session->profile->media_engine,session,5,session->base.pool); + session->context = mpf_engine_context_create( + session->profile->media_engine, + session->base.name, + session,5,session->base.pool); } - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive Offer "APT_SID_FMT" [c:%d a:%d v:%d]", - MRCP_SESSION_SID(&session->base), + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive Offer "APT_NAMESID_FMT" [c:%d a:%d v:%d]", + MRCP_SESSION_NAMESID(session), descriptor->control_media_arr->nelts, descriptor->audio_media_arr->nelts, descriptor->video_media_arr->nelts); @@ -422,7 +449,7 @@ static apt_bool_t mrcp_server_session_terminate_process(mrcp_server_session_t *s 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,MRCP_SESSION_SID(&session->base)); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Terminate Session "APT_NAMESID_FMT,MRCP_SESSION_NAMESID(session)); mrcp_server_session_state_set(session,SESSION_STATE_TERMINATING); @@ -441,7 +468,10 @@ static apt_bool_t mrcp_server_session_terminate_process(mrcp_server_session_t *s if(!channel) continue; /* send remove channel request */ - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Remove Control Channel [%d]",i); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Remove Control Channel "APT_NAMESIDRES_FMT" [%d]", + MRCP_SESSION_NAMESID(session), + channel->resource->name.buf, + i); if(channel->control_channel) { if(mrcp_server_control_channel_remove(channel->control_channel) == TRUE) { channel->waiting_for_channel = TRUE; @@ -453,7 +483,9 @@ static apt_bool_t mrcp_server_session_terminate_process(mrcp_server_session_t *s 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"); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Subtract Media Termination "APT_NAMESIDRES_FMT, + MRCP_SESSION_NAMESID(session), + mpf_termination_name_get(termination)); if(mpf_engine_termination_message_add( session->profile->media_engine, MPF_SUBTRACT_TERMINATION,session->context,termination,NULL, @@ -475,7 +507,9 @@ static apt_bool_t mrcp_server_session_terminate_process(mrcp_server_session_t *s if(!slot || !slot->termination) continue; /* send subtract termination request */ - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Subtract RTP Termination [%d]",i); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Subtract Media Termination "APT_NAMESIDRES_FMT, + MRCP_SESSION_NAMESID(session), + mpf_termination_name_get(slot->termination)); if(mpf_engine_termination_message_add( session->profile->media_engine, MPF_SUBTRACT_TERMINATION,session->context,slot->termination,NULL, @@ -502,7 +536,7 @@ static apt_bool_t mrcp_server_session_deactivate(mrcp_server_session_t *session) { mrcp_channel_t *channel; int i; - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Deactivate Session "APT_SID_FMT,MRCP_SESSION_SID(&session->base)); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Deactivate Session "APT_NAMESID_FMT,MRCP_SESSION_NAMESID(session)); mrcp_server_session_state_set(session,SESSION_STATE_DEACTIVATING); for(i=0; ichannels->nelts; i++) { channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*); @@ -525,12 +559,16 @@ static apt_bool_t mrcp_server_on_message_receive(mrcp_server_session_t *session, 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"); + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Such Channel "APT_NAMESIDRES_FMT, + MRCP_SESSION_NAMESID(session), + message->channel_id.resource_name.buf); return FALSE; } } if(!channel->resource || !channel->state_machine) { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Resource"); + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Missing Resource "APT_NAMESIDRES_FMT, + MRCP_SESSION_NAMESID(session), + channel->resource->name.buf); return FALSE; } @@ -626,7 +664,10 @@ static apt_bool_t mrcp_server_resource_offer_process(mrcp_server_session_t *sess return FALSE; } /* add to channel array */ - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add Control Channel [%d]",count); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add Control Channel "APT_NAMESIDRES_FMT" [%d]", + MRCP_SESSION_NAMESID(session), + channel->resource->name.buf, + count); APR_ARRAY_PUSH(session->channels,mrcp_channel_t*) = channel; if(channel->engine_channel && channel->engine_channel->termination) { mpf_termination_t *termination = channel->engine_channel->termination; @@ -668,7 +709,10 @@ static apt_bool_t mrcp_server_control_media_offer_process(mrcp_server_session_t 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); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Modify Control Channel "APT_NAMESIDRES_FMT" [%d]", + MRCP_SESSION_NAMESID(session), + channel->resource->name.buf, + i); if(channel->control_channel) { /* send offer */ if(mrcp_server_control_channel_modify(channel->control_channel,control_descriptor) == TRUE) { @@ -696,7 +740,10 @@ static apt_bool_t mrcp_server_control_media_offer_process(mrcp_server_session_t if(!channel) continue; control_descriptor->session_id = session->base.id; - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add Control Channel [%d]",i); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add Control Channel "APT_NAMESIDRES_FMT" [%d]", + MRCP_SESSION_NAMESID(session), + channel->resource->name.buf, + i); APR_ARRAY_PUSH(session->channels,mrcp_channel_t*) = channel; if(channel->control_channel) { @@ -746,6 +793,7 @@ static mpf_rtp_termination_descriptor_t* mrcp_server_associations_build(mrcp_ser mpf_rtp_termination_descriptor_init(rtp_descriptor); rtp_descriptor->audio.local = NULL; rtp_descriptor->audio.remote = media_descriptor; + rtp_descriptor->audio.settings = session->profile->rtp_settings; slot->mid = media_descriptor->mid; slot->channels = apr_array_make(session->base.pool,1,sizeof(mrcp_channel_t*)); @@ -753,7 +801,7 @@ static mpf_rtp_termination_descriptor_t* mrcp_server_associations_build(mrcp_ser channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*); if(!channel) continue; - if(!channel->cmid_arr || mrcp_cmid_find(channel->cmid_arr,slot->mid) == TRUE) { + if(session->terminations->nelts == 1 || (!channel->cmid_arr || mrcp_cmid_find(channel->cmid_arr,slot->mid) == TRUE)) { APR_ARRAY_PUSH(slot->channels, mrcp_channel_t*) = channel; audio_stream = NULL; @@ -840,7 +888,10 @@ static apt_bool_t mrcp_server_av_media_offer_process(mrcp_server_session_t *sess if(!rtp_descriptor) continue; /* send modify termination request */ - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Modify RTP Termination [%d]",i); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Modify Media Termination "APT_NAMESIDRES_FMT" [%d]", + MRCP_SESSION_NAMESID(session), + mpf_termination_name_get(slot->termination), + i); if(mpf_engine_termination_message_add( session->profile->media_engine, MPF_MODIFY_TERMINATION,session->context,slot->termination,rtp_descriptor, @@ -859,7 +910,10 @@ static apt_bool_t mrcp_server_av_media_offer_process(mrcp_server_session_t *sess /* 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); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add Media Termination "APT_NAMESIDRES_FMT" [%d]", + MRCP_SESSION_NAMESID(session), + mpf_termination_name_get(termination), + i); slot = apr_array_push(session->terminations); slot->id = i; slot->mid = 0; @@ -890,8 +944,8 @@ 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", - MRCP_SESSION_SID(&session->base), + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Send Answer "APT_NAMESID_FMT" [c:%d a:%d v:%d] Status %s", + MRCP_SESSION_NAMESID(session), descriptor->control_media_arr->nelts, descriptor->audio_media_arr->nelts, descriptor->video_media_arr->nelts, @@ -924,7 +978,7 @@ static apt_bool_t mrcp_server_session_terminate_send(mrcp_server_session_t *sess channel->engine_channel = NULL; } } - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Send Terminate Response "APT_SID_FMT,MRCP_SESSION_SID(&session->base)); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Session Terminated "APT_NAMESID_FMT,MRCP_SESSION_NAMESID(session)); mrcp_session_terminate_response(&session->base); return TRUE; } @@ -979,6 +1033,9 @@ static apt_bool_t mrcp_server_on_termination_modify(mrcp_server_session_t *sessi if(!session) { return FALSE; } + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Media Termination Modified "APT_NAMESIDRES_FMT, + MRCP_SESSION_NAMESID(session), + mpf_termination_name_get(mpf_message->termination)); termination_slot = mrcp_server_rtp_termination_find(session,mpf_message->termination); if(termination_slot) { /* rtp termination */ @@ -1012,6 +1069,9 @@ static apt_bool_t mrcp_server_on_termination_subtract(mrcp_server_session_t *ses if(!session) { return FALSE; } + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Media Termination Subtracted "APT_NAMESIDRES_FMT, + MRCP_SESSION_NAMESID(session), + mpf_termination_name_get(mpf_message->termination)); termination_slot = mrcp_server_rtp_termination_find(session,mpf_message->termination); if(termination_slot) { /* rtp termination */ @@ -1049,15 +1109,12 @@ apt_bool_t mrcp_server_mpf_message_process(mpf_message_container_t *mpf_message_ if(mpf_message->message_type == MPF_MESSAGE_TYPE_RESPONSE) { switch(mpf_message->command_id) { case MPF_ADD_TERMINATION: - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Termination Add"); mrcp_server_on_termination_modify(session,mpf_message); break; case MPF_MODIFY_TERMINATION: - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Termination Modify"); mrcp_server_on_termination_modify(session,mpf_message); break; case MPF_SUBTRACT_TERMINATION: - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Termination Subtract"); mrcp_server_on_termination_subtract(session,mpf_message); break; case MPF_ADD_ASSOCIATION: diff --git a/libs/unimrcp/libs/mrcp-signaling/include/mrcp_session.h b/libs/unimrcp/libs/mrcp-signaling/include/mrcp_session.h index 173d1c39b2..b1f2ead512 100644 --- a/libs/unimrcp/libs/mrcp-signaling/include/mrcp_session.h +++ b/libs/unimrcp/libs/mrcp-signaling/include/mrcp_session.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_session.h 1792 2011-01-10 21:08:52Z achaloyan $ */ -#ifndef __MRCP_SESSION_H__ -#define __MRCP_SESSION_H__ +#ifndef MRCP_SESSION_H +#define MRCP_SESSION_H /** * @file mrcp_session.h @@ -51,6 +53,10 @@ struct mrcp_session_t { apr_pool_t *pool; /** External object associated with session */ void *obj; + /** External logger object associated with session */ + void *log_obj; + /** Informative name of the session used for debugging */ + const char *name; /** Back pointer to signaling agent */ mrcp_sig_agent_t *signaling_agent; @@ -189,4 +195,4 @@ static APR_INLINE apt_bool_t mrcp_session_discover_response(mrcp_session_t *sess APT_END_EXTERN_C -#endif /*__MRCP_SESSION_H__*/ +#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 index 7a94a42496..9cdbbc9dfe 100644 --- a/libs/unimrcp/libs/mrcp-signaling/include/mrcp_session_descriptor.h +++ b/libs/unimrcp/libs/mrcp-signaling/include/mrcp_session_descriptor.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_session_descriptor.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MRCP_SESSION_DESCRIPTOR_H__ -#define __MRCP_SESSION_DESCRIPTOR_H__ +#ifndef MRCP_SESSION_DESCRIPTOR_H +#define MRCP_SESSION_DESCRIPTOR_H /** * @file mrcp_session_descriptor.h @@ -143,4 +145,4 @@ MRCP_DECLARE(const char*) mrcp_session_status_phrase_get(mrcp_session_status_e s APT_END_EXTERN_C -#endif /*__MRCP_SESSION_DESCRIPTOR_H__*/ +#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 index d17986c445..a0ef308470 100644 --- a/libs/unimrcp/libs/mrcp-signaling/include/mrcp_sig_agent.h +++ b/libs/unimrcp/libs/mrcp-signaling/include/mrcp_sig_agent.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,48 +12,78 @@ * 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. + * + * $Id: mrcp_sig_agent.h 1750 2010-07-23 19:33:34Z achaloyan $ */ -#ifndef __MRCP_SIG_AGENT_H__ -#define __MRCP_SIG_AGENT_H__ +#ifndef MRCP_SIG_AGENT_H +#define MRCP_SIG_AGENT_H /** * @file mrcp_sig_agent.h * @brief Abstract MRCP Signaling Agent */ +#include +#include #include "mrcp_sig_types.h" #include "apt_task.h" APT_BEGIN_EXTERN_C +/** Signaling settings */ +struct mrcp_sig_settings_t { + /** Server IP address */ + char *server_ip; + /** Server port */ + apr_port_t server_port; + /** Server SIP user name (v2 only) */ + char *user_name; + /** Resource location (v1 only) */ + char *resource_location; + /** Map of the MRCP resource names (v1 only) */ + apr_table_t *resource_map; + /** 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; + /** Optional feature tags */ + char *feature_tags; +}; + + /** MRCP signaling agent */ struct mrcp_sig_agent_t { + /** Agent identifier */ + const char *id; /** Memory pool to allocate memory from */ - apr_pool_t *pool; + apr_pool_t *pool; /** External object associated with agent */ - void *obj; + void *obj; /** Parent object (client/server) */ - void *parent; + void *parent; /** MRCP version */ - mrcp_version_e mrcp_version; + mrcp_version_e mrcp_version; /** MRCP resource factory */ mrcp_resource_factory_t *resource_factory; /** Task interface */ - apt_task_t *task; + apt_task_t *task; /** Task message pool used to allocate signaling agent messages */ - apt_task_msg_pool_t *msg_pool; + 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); + apt_bool_t (*create_client_session)(mrcp_session_t *session, mrcp_sig_settings_t *settings); }; /** Create signaling agent. */ -MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_signaling_agent_create(void *obj, mrcp_version_e mrcp_version, apr_pool_t *pool); +MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_signaling_agent_create(const char *id, void *obj, mrcp_version_e mrcp_version, apr_pool_t *pool); + +/** Allocate MRCP signaling settings. */ +MRCP_DECLARE(mrcp_sig_settings_t*) mrcp_signaling_settings_alloc(apr_pool_t *pool); + APT_END_EXTERN_C -#endif /*__MRCP_SIG_AGENT_H__*/ +#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 index 41de32b861..c45b4be6e6 100644 --- a/libs/unimrcp/libs/mrcp-signaling/include/mrcp_sig_types.h +++ b/libs/unimrcp/libs/mrcp-signaling/include/mrcp_sig_types.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_sig_types.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MRCP_SIG_TYPES_H__ -#define __MRCP_SIG_TYPES_H__ +#ifndef MRCP_SIG_TYPES_H +#define MRCP_SIG_TYPES_H /** * @file mrcp_sig_types.h @@ -26,6 +28,9 @@ APT_BEGIN_EXTERN_C +/** Opaque MRCP signaling settings declaration */ +typedef struct mrcp_sig_settings_t mrcp_sig_settings_t; + /** Opaque MRCP signaling agent declaration */ typedef struct mrcp_sig_agent_t mrcp_sig_agent_t; @@ -37,4 +42,4 @@ typedef struct mrcp_session_descriptor_t mrcp_session_descriptor_t; APT_END_EXTERN_C -#endif /*__MRCP_SIG_TYPES_H__*/ +#endif /* MRCP_SIG_TYPES_H */ diff --git a/libs/unimrcp/libs/mrcp-signaling/mrcpsignaling.2008.vcproj b/libs/unimrcp/libs/mrcp-signaling/mrcpsignaling.2008.vcproj deleted file mode 100644 index 25e0f23d9c..0000000000 --- a/libs/unimrcp/libs/mrcp-signaling/mrcpsignaling.2008.vcproj +++ /dev/null @@ -1,289 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/unimrcp/libs/mrcp-signaling/mrcpsignaling.2010.vcxproj b/libs/unimrcp/libs/mrcp-signaling/mrcpsignaling.2010.vcxproj deleted file mode 100644 index f11e3bd765..0000000000 --- a/libs/unimrcp/libs/mrcp-signaling/mrcpsignaling.2010.vcxproj +++ /dev/null @@ -1,121 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - mrcpsignaling - {12A49562-BAB9-43A3-A21D-15B60BBB4C31} - mrcpsignaling - Win32Proj - - - - StaticLibrary - Unicode - true - - - StaticLibrary - Unicode - - - StaticLibrary - Unicode - true - - - StaticLibrary - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - - - - APT_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;%(PreprocessorDefinitions) - - - - - X64 - - - APT_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;%(PreprocessorDefinitions) - ProgramDatabase - - - - - APT_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;%(PreprocessorDefinitions) - - - - - X64 - - - APT_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/libs/unimrcp/libs/mrcp-signaling/mrcpsignaling.2010.vcxproj.filters b/libs/unimrcp/libs/mrcp-signaling/mrcpsignaling.2010.vcxproj.filters deleted file mode 100644 index 4e5d30c3da..0000000000 --- a/libs/unimrcp/libs/mrcp-signaling/mrcpsignaling.2010.vcxproj.filters +++ /dev/null @@ -1,35 +0,0 @@ - - - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {f3dc550f-1a0f-4b9e-b077-3b6940dc5531} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - - - include - - - include - - - include - - - include - - - - - src - - - src - - - \ No newline at end of file diff --git a/libs/unimrcp/libs/mrcp-signaling/src/mrcp_session_descriptor.c b/libs/unimrcp/libs/mrcp-signaling/src/mrcp_session_descriptor.c index 5b0162725f..54d89ff258 100644 --- a/libs/unimrcp/libs/mrcp-signaling/src/mrcp_session_descriptor.c +++ b/libs/unimrcp/libs/mrcp-signaling/src/mrcp_session_descriptor.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_session_descriptor.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include "mrcp_session_descriptor.h" diff --git a/libs/unimrcp/libs/mrcp-signaling/src/mrcp_sig_agent.c b/libs/unimrcp/libs/mrcp-signaling/src/mrcp_sig_agent.c index 90773c345b..ba8570a606 100644 --- a/libs/unimrcp/libs/mrcp-signaling/src/mrcp_sig_agent.c +++ b/libs/unimrcp/libs/mrcp-signaling/src/mrcp_sig_agent.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,15 +12,18 @@ * 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. + * + * $Id: mrcp_sig_agent.c 1792 2011-01-10 21:08:52Z achaloyan $ */ #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_DECLARE(mrcp_sig_agent_t*) mrcp_signaling_agent_create(const char *id, 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->id = id; sig_agent->pool = pool; sig_agent->obj = obj; sig_agent->mrcp_version = mrcp_version; @@ -33,6 +36,21 @@ MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_signaling_agent_create(void *obj, mrcp_vers return sig_agent; } +/** Allocate MRCP signaling settings */ +MRCP_DECLARE(mrcp_sig_settings_t*) mrcp_signaling_settings_alloc(apr_pool_t *pool) +{ + mrcp_sig_settings_t *settings = apr_palloc(pool,sizeof(mrcp_sig_settings_t)); + settings->server_ip = NULL; + settings->server_port = 0; + settings->user_name = NULL; + settings->resource_location = NULL; + settings->resource_map = apr_table_make(pool,2); + settings->force_destination = FALSE; + settings->feature_tags = NULL; + return settings; +} + + MRCP_DECLARE(mrcp_session_t*) mrcp_session_create(apr_size_t padding) { mrcp_session_t *session; @@ -43,6 +61,8 @@ MRCP_DECLARE(mrcp_session_t*) mrcp_session_create(apr_size_t padding) session = apr_palloc(pool,sizeof(mrcp_session_t)+padding); session->pool = pool; session->obj = NULL; + session->log_obj = NULL; + session->name = NULL; session->signaling_agent = NULL; session->request_vtable = NULL; session->response_vtable = NULL; diff --git a/libs/unimrcp/libs/mrcp/Makefile.am b/libs/unimrcp/libs/mrcp/Makefile.am index 014261f81d..7528d04928 100644 --- a/libs/unimrcp/libs/mrcp/Makefile.am +++ b/libs/unimrcp/libs/mrcp/Makefile.am @@ -14,6 +14,7 @@ include_HEADERS = include/mrcp.h \ message/include/mrcp_start_line.h \ message/include/mrcp_header_accessor.h \ message/include/mrcp_generic_header.h \ + message/include/mrcp_header.h \ message/include/mrcp_message.h \ control/include/mrcp_resource.h \ control/include/mrcp_resource_factory.h \ @@ -24,11 +25,14 @@ include_HEADERS = include/mrcp.h \ resources/include/mrcp_recog_header.h \ resources/include/mrcp_recog_resource.h \ resources/include/mrcp_recorder_header.h \ - resources/include/mrcp_recorder_resource.h + resources/include/mrcp_recorder_resource.h \ + resources/include/mrcp_verifier_header.h \ + resources/include/mrcp_verifier_resource.h -libmrcp_la_SOURCES = message/src/mrcp_header_accessor.c \ +libmrcp_la_SOURCES = message/src/mrcp_start_line.c \ + message/src/mrcp_header_accessor.c \ message/src/mrcp_generic_header.c \ - message/src/mrcp_start_line.c \ + message/src/mrcp_header.c \ message/src/mrcp_message.c \ control/src/mrcp_resource_factory.c \ control/src/mrcp_resource_loader.c \ @@ -38,4 +42,6 @@ libmrcp_la_SOURCES = message/src/mrcp_header_accessor.c \ resources/src/mrcp_recog_header.c \ resources/src/mrcp_recog_resource.c \ resources/src/mrcp_recorder_header.c \ - resources/src/mrcp_recorder_resource.c + resources/src/mrcp_recorder_resource.c \ + resources/src/mrcp_verifier_header.c \ + resources/src/mrcp_verifier_resource.c diff --git a/libs/unimrcp/libs/mrcp/control/include/mrcp_resource.h b/libs/unimrcp/libs/mrcp/control/include/mrcp_resource.h index dd7a7f8abd..0f45fe54cc 100644 --- a/libs/unimrcp/libs/mrcp/control/include/mrcp_resource.h +++ b/libs/unimrcp/libs/mrcp/control/include/mrcp_resource.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_resource.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MRCP_RESOURCE_H__ -#define __MRCP_RESOURCE_H__ +#ifndef MRCP_RESOURCE_H +#define MRCP_RESOURCE_H /** * @file mrcp_resource.h @@ -77,4 +79,4 @@ static APR_INLINE apt_bool_t mrcp_resource_validate(mrcp_resource_t *resource) APT_END_EXTERN_C -#endif /*__MRCP_RESOURCE_H__*/ +#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 index f0349a7e2e..84631b13d7 100644 --- a/libs/unimrcp/libs/mrcp/control/include/mrcp_resource_factory.h +++ b/libs/unimrcp/libs/mrcp/control/include/mrcp_resource_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_resource_factory.h 1632 2010-03-30 20:46:25Z achaloyan $ */ -#ifndef __MRCP_RESOURCE_FACTORY_H__ -#define __MRCP_RESOURCE_FACTORY_H__ +#ifndef MRCP_RESOURCE_FACTORY_H +#define MRCP_RESOURCE_FACTORY_H /** * @file mrcp_resource_factory.h @@ -37,12 +39,12 @@ MRCP_DECLARE(apt_bool_t) mrcp_resource_factory_destroy(mrcp_resource_factory_t * MRCP_DECLARE(apt_bool_t) mrcp_resource_register(mrcp_resource_factory_t *resource_factory, mrcp_resource_t *resource); /** 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); +MRCP_DECLARE(mrcp_resource_t*) mrcp_resource_get(const mrcp_resource_factory_t *resource_factory, mrcp_resource_id resource_id); /** Find MRCP resource by resource name */ -MRCP_DECLARE(mrcp_resource_t*) mrcp_resource_find(mrcp_resource_factory_t *resource_factory, const apt_str_t *name); +MRCP_DECLARE(mrcp_resource_t*) mrcp_resource_find(const mrcp_resource_factory_t *resource_factory, const apt_str_t *name); APT_END_EXTERN_C -#endif /*__MRCP_RESOURCE_FACTORY_H__*/ +#endif /* MRCP_RESOURCE_FACTORY_H */ diff --git a/libs/unimrcp/libs/mrcp/control/include/mrcp_resource_loader.h b/libs/unimrcp/libs/mrcp/control/include/mrcp_resource_loader.h index e88cca4305..a6608aba3b 100644 --- a/libs/unimrcp/libs/mrcp/control/include/mrcp_resource_loader.h +++ b/libs/unimrcp/libs/mrcp/control/include/mrcp_resource_loader.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_resource_loader.h 1710 2010-05-24 17:36:19Z achaloyan $ */ -#ifndef __MRCP_RESOURCE_LOADER_H__ -#define __MRCP_RESOURCE_LOADER_H__ +#ifndef MRCP_RESOURCE_LOADER_H +#define MRCP_RESOURCE_LOADER_H /** * @file mrcp_resource_loader.h @@ -44,8 +46,8 @@ MRCP_DECLARE(apt_bool_t) mrcp_resource_load(mrcp_resource_loader_t *loader, cons MRCP_DECLARE(apt_bool_t) mrcp_resource_load_by_id(mrcp_resource_loader_t *loader, mrcp_resource_id id); /** Get MRCP resource factory */ -MRCP_DECLARE(mrcp_resource_factory_t*) mrcp_resource_factory_get(mrcp_resource_loader_t *loader); +MRCP_DECLARE(mrcp_resource_factory_t*) mrcp_resource_factory_get(const mrcp_resource_loader_t *loader); APT_END_EXTERN_C -#endif /*__MRCP_RESOURCE_LOADER_H__*/ +#endif /* MRCP_RESOURCE_LOADER_H */ diff --git a/libs/unimrcp/libs/mrcp/control/include/mrcp_stream.h b/libs/unimrcp/libs/mrcp/control/include/mrcp_stream.h index 3cc9d38511..ab5c4c6fa5 100644 --- a/libs/unimrcp/libs/mrcp/control/include/mrcp_stream.h +++ b/libs/unimrcp/libs/mrcp/control/include/mrcp_stream.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,68 +12,58 @@ * 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. + * + * $Id: mrcp_stream.h 1660 2010-04-19 18:29:06Z achaloyan $ */ -#ifndef __MRCP_STREAM_H__ -#define __MRCP_STREAM_H__ +#ifndef MRCP_STREAM_H +#define MRCP_STREAM_H /** * @file mrcp_stream.h * @brief MRCP Stream Parser and Generator */ -#include "apt_text_stream.h" +#include "apt_text_message.h" #include "mrcp_types.h" APT_BEGIN_EXTERN_C -/** Status of MRCP stream processing (parse/generate) */ -typedef enum { - MRCP_STREAM_STATUS_COMPLETE, - MRCP_STREAM_STATUS_INCOMPLETE, - MRCP_STREAM_STATUS_INVALID -} mrcp_stream_status_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_status_e status); - -/** 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); +MRCP_DECLARE(mrcp_parser_t*) mrcp_parser_create(const 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); +/** Set resource by name to be used for parsing of MRCPv1 messages */ +MRCP_DECLARE(void) mrcp_parser_resource_set(mrcp_parser_t *parser, const apt_str_t *resource_name); + +/** Set verbose mode for the parser */ +MRCP_DECLARE(void) mrcp_parser_verbose_set(mrcp_parser_t *parser, apt_bool_t verbose); /** Parse MRCP stream */ -MRCP_DECLARE(mrcp_stream_status_e) mrcp_parser_run(mrcp_parser_t *parser, apt_text_stream_t *stream); +MRCP_DECLARE(apt_message_status_e) mrcp_parser_run(mrcp_parser_t *parser, apt_text_stream_t *stream, mrcp_message_t **message); -/** 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); +MRCP_DECLARE(mrcp_generator_t*) mrcp_generator_create(const 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); +/** Set verbose mode for the generator */ +MRCP_DECLARE(void) mrcp_generator_verbose_set(mrcp_generator_t *generator, apt_bool_t verbose); /** Generate MRCP stream */ -MRCP_DECLARE(mrcp_stream_status_e) mrcp_generator_run(mrcp_generator_t *generator, apt_text_stream_t *stream); +MRCP_DECLARE(apt_message_status_e) mrcp_generator_run(mrcp_generator_t *generator, mrcp_message_t *message, apt_text_stream_t *stream); + + +/** Generate MRCP message (excluding message body) */ +MRCP_DECLARE(apt_bool_t) mrcp_message_generate(const mrcp_resource_factory_t *resource_factory, mrcp_message_t *message, 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__*/ +#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 index 894f89f158..21c6d341e6 100644 --- a/libs/unimrcp/libs/mrcp/control/src/mrcp_resource_factory.c +++ b/libs/unimrcp/libs/mrcp/control/src/mrcp_resource_factory.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_resource_factory.c 1632 2010-03-30 20:46:25Z achaloyan $ */ #include @@ -80,7 +82,7 @@ MRCP_DECLARE(apt_bool_t) mrcp_resource_register(mrcp_resource_factory_t *resourc } /** 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) +MRCP_DECLARE(mrcp_resource_t*) mrcp_resource_get(const mrcp_resource_factory_t *resource_factory, mrcp_resource_id resource_id) { if(resource_id >= resource_factory->resource_count) { return NULL; @@ -89,7 +91,7 @@ MRCP_DECLARE(mrcp_resource_t*) mrcp_resource_get(mrcp_resource_factory_t *resour } /** Find MRCP resource by resource name */ -MRCP_DECLARE(mrcp_resource_t*) mrcp_resource_find(mrcp_resource_factory_t *resource_factory, const apt_str_t *name) +MRCP_DECLARE(mrcp_resource_t*) mrcp_resource_find(const mrcp_resource_factory_t *resource_factory, const apt_str_t *name) { if(!name->buf || !name->length) { return NULL; diff --git a/libs/unimrcp/libs/mrcp/control/src/mrcp_resource_loader.c b/libs/unimrcp/libs/mrcp/control/src/mrcp_resource_loader.c index c670b8ba79..2160b2a614 100644 --- a/libs/unimrcp/libs/mrcp/control/src/mrcp_resource_loader.c +++ b/libs/unimrcp/libs/mrcp/control/src/mrcp_resource_loader.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_resource_loader.c 1764 2010-08-23 18:02:18Z achaloyan $ */ #include "mrcp_resource_loader.h" @@ -20,6 +22,7 @@ #include "mrcp_synth_resource.h" #include "mrcp_recog_resource.h" #include "mrcp_recorder_resource.h" +#include "mrcp_verifier_resource.h" #include "apt_log.h" /** Resource loader */ @@ -28,11 +31,12 @@ struct mrcp_resource_loader_t { apr_pool_t *pool; }; -/** String table of MRCPv2 resources (mrcp_resource_types_e) */ +/** String table of MRCPv2 resources (mrcp_resource_type_e) */ static const apt_str_table_item_t mrcp_resource_string_table[] = { {{"speechsynth",11},6}, {{"speechrecog",11},6}, - {{"recorder", 8},0} + {{"recorder", 8},0}, + {{"speakverify",11},3} }; static mrcp_resource_t* mrcp_resource_create_by_id(mrcp_resource_id id, apr_pool_t *pool); @@ -106,7 +110,7 @@ MRCP_DECLARE(apt_bool_t) mrcp_resource_load_by_id(mrcp_resource_loader_t *loader } /** Get MRCP resource factory */ -MRCP_DECLARE(mrcp_resource_factory_t*) mrcp_resource_factory_get(mrcp_resource_loader_t *loader) +MRCP_DECLARE(mrcp_resource_factory_t*) mrcp_resource_factory_get(const mrcp_resource_loader_t *loader) { return loader->factory; } @@ -124,6 +128,9 @@ static mrcp_resource_t* mrcp_resource_create_by_id(mrcp_resource_id id, apr_pool case MRCP_RECORDER_RESOURCE: resource = mrcp_recorder_resource_create(pool); break; + case MRCP_VERIFIER_RESOURCE: + resource = mrcp_verifier_resource_create(pool); + break; } if(resource) { diff --git a/libs/unimrcp/libs/mrcp/control/src/mrcp_stream.c b/libs/unimrcp/libs/mrcp/control/src/mrcp_stream.c index daef44c219..94f067240c 100644 --- a/libs/unimrcp/libs/mrcp/control/src/mrcp_stream.c +++ b/libs/unimrcp/libs/mrcp/control/src/mrcp_stream.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,399 +12,234 @@ * 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. + * + * $Id: mrcp_stream.c 1671 2010-04-28 19:50:29Z achaloyan $ */ #include "mrcp_stream.h" #include "mrcp_message.h" -#include "mrcp_generic_header.h" #include "mrcp_resource_factory.h" +#include "mrcp_resource.h" #include "apt_log.h" -/** Stage of MRCP stream processing (parse/generate) */ -typedef enum { - MRCP_STREAM_STAGE_NONE, - MRCP_STREAM_STAGE_START_LINE, - MRCP_STREAM_STAGE_RESOURCE, - MRCP_STREAM_STAGE_HEADER, - MRCP_STREAM_STAGE_BODY -} mrcp_stream_stage_e; /** MRCP parser */ struct mrcp_parser_t { - mrcp_resource_factory_t *resource_factory; - apt_str_t resource_name; - mrcp_stream_stage_e stage; - apt_bool_t skip_lf; - mrcp_message_t *message; - apr_pool_t *pool; + apt_message_parser_t *base; + const mrcp_resource_factory_t *resource_factory; + mrcp_resource_t *resource; }; /** MRCP generator */ struct mrcp_generator_t { - mrcp_resource_factory_t *resource_factory; - mrcp_stream_stage_e stage; - mrcp_message_t *message; - apr_pool_t *pool; + apt_message_generator_t *base; + const mrcp_resource_factory_t *resource_factory; }; +/** Create message and read start line */ +static apt_bool_t mrcp_parser_on_start(apt_message_parser_t *parser, apt_message_context_t *context, apt_text_stream_t *stream, apr_pool_t *pool); +/** Header section handler */ +static apt_bool_t mrcp_parser_on_header_complete(apt_message_parser_t *parser, apt_message_context_t *context); -/** Read MRCP message-body */ -static apt_bool_t mrcp_message_body_read(mrcp_message_t *message, apt_text_stream_t *stream) -{ - apt_bool_t status = TRUE; - 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 */ - status = FALSE; - } - 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 status; -} - -/** Write MRCP message-body */ -static apt_bool_t mrcp_message_body_write(mrcp_message_t *message, apt_text_stream_t *stream) -{ - apt_bool_t status = TRUE; - 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 */ - status = FALSE; - } - - memcpy(stream->pos,message->body.buf+message->body.length,required_length); - message->body.length += required_length; - stream->pos += required_length; - } - - return status; -} - -/** 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) -{ - mrcp_resource_t *resource; - - /* 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); - } - - /* find resource */ - resource = mrcp_resource_find(resource_factory,&message->channel_id.resource_name); - if(!resource) { - return FALSE; - } - - if(mrcp_message_resource_set(message,resource) == 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) -{ - /* 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); - } +static const apt_message_parser_vtable_t parser_vtable = { + mrcp_parser_on_start, + mrcp_parser_on_header_complete, + NULL +}; - /* generate header */ - if(mrcp_message_header_generate(&message->header,stream) == FALSE) { - return FALSE; - } +/** Start message generation */ +apt_bool_t mrcp_generator_on_start(apt_message_generator_t *generator, apt_message_context_t *context, apt_text_stream_t *stream); +/** Finalize by setting overall message length in start line */ +apt_bool_t mrcp_generator_on_header_complete(apt_message_generator_t *generator, apt_message_context_t *context, apt_text_stream_t *stream); - /* finalize start-line generation */ - if(mrcp_start_line_finalize(&message->start_line,message->body.length,stream) == FALSE) { - return FALSE; - } - - return TRUE; -} +static const apt_message_generator_vtable_t generator_vtable = { + mrcp_generator_on_start, + mrcp_generator_on_header_complete, + NULL +}; /** Create MRCP stream parser */ -MRCP_DECLARE(mrcp_parser_t*) mrcp_parser_create(mrcp_resource_factory_t *resource_factory, apr_pool_t *pool) +MRCP_DECLARE(mrcp_parser_t*) mrcp_parser_create(const mrcp_resource_factory_t *resource_factory, apr_pool_t *pool) { mrcp_parser_t *parser = apr_palloc(pool,sizeof(mrcp_parser_t)); + parser->base = apt_message_parser_create(parser,&parser_vtable,pool); parser->resource_factory = resource_factory; - apt_string_reset(&parser->resource_name); - parser->stage = MRCP_STREAM_STAGE_NONE; - parser->skip_lf = FALSE; - parser->message = NULL; - parser->pool = pool; + parser->resource = NULL; 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) +/** Set resource by name to be used for parsing of MRCPv1 messages */ +MRCP_DECLARE(void) mrcp_parser_resource_set(mrcp_parser_t *parser, const apt_str_t *resource_name) { if(resource_name) { - apt_string_copy(&parser->resource_name,resource_name,parser->pool); + parser->resource = mrcp_resource_find(parser->resource_factory,resource_name); } } -static mrcp_stream_status_e mrcp_parser_break(mrcp_parser_t *parser, apt_text_stream_t *stream) +/** Set verbose mode for the parser */ +MRCP_DECLARE(void) mrcp_parser_verbose_set(mrcp_parser_t *parser, apt_bool_t verbose) { - /* failed to parse message */ - if(apt_text_is_eos(stream) == TRUE) { - /* end of stream reached */ - return MRCP_STREAM_STATUS_INCOMPLETE; - } - - /* error case */ - parser->stage = MRCP_STREAM_STAGE_NONE; - return MRCP_STREAM_STATUS_INVALID; + apt_message_parser_verbose_set(parser->base,verbose); } /** Parse MRCP stream */ -MRCP_DECLARE(mrcp_stream_status_e) mrcp_parser_run(mrcp_parser_t *parser, apt_text_stream_t *stream) +MRCP_DECLARE(apt_message_status_e) mrcp_parser_run(mrcp_parser_t *parser, apt_text_stream_t *stream, mrcp_message_t **message) +{ + return apt_message_parser_run(parser->base,stream,(void**)message); +} + +/** Create message and read start line */ +static apt_bool_t mrcp_parser_on_start(apt_message_parser_t *parser, apt_message_context_t *context, apt_text_stream_t *stream, apr_pool_t *pool) { - mrcp_message_t *message = parser->message; - if(parser->stage == MRCP_STREAM_STAGE_NONE || !message) { - /* create new MRCP message */ - message = mrcp_message_create(parser->pool); - message->channel_id.resource_name = parser->resource_name; - parser->message = message; - parser->stage = MRCP_STREAM_STAGE_START_LINE; + mrcp_message_t *mrcp_message; + apt_str_t start_line; + /* read start line */ + if(apt_text_line_read(stream,&start_line) == FALSE) { + return FALSE; + } + + /* create new MRCP message */ + mrcp_message = mrcp_message_create(pool); + /* parse start-line */ + if(mrcp_start_line_parse(&mrcp_message->start_line,&start_line,mrcp_message->pool) == FALSE) { + return FALSE; } - if(parser->stage == MRCP_STREAM_STAGE_START_LINE) { - /* parse start-line */ - if(mrcp_start_line_parse(&message->start_line,stream,message->pool) == FALSE) { - return mrcp_parser_break(parser,stream); + if(mrcp_message->start_line.version == MRCP_VERSION_1) { + mrcp_parser_t *mrcp_parser = apt_message_parser_object_get(parser); + if(!mrcp_parser->resource) { + return FALSE; + } + apt_string_copy( + &mrcp_message->channel_id.resource_name, + &mrcp_parser->resource->name, + pool); + + if(mrcp_message_resource_set(mrcp_message,mrcp_parser->resource) == FALSE) { + return FALSE; } - parser->stage = MRCP_STREAM_STAGE_RESOURCE; } - if(parser->stage == MRCP_STREAM_STAGE_RESOURCE) { + context->message = mrcp_message; + context->header = &mrcp_message->header.header_section; + context->body = &mrcp_message->body; + return TRUE; +} + +/** Header section handler */ +static apt_bool_t mrcp_parser_on_header_complete(apt_message_parser_t *parser, apt_message_context_t *context) +{ + mrcp_message_t *mrcp_message = context->message; + if(mrcp_message->start_line.version == MRCP_VERSION_2) { mrcp_resource_t *resource; - - if(message->start_line.version == MRCP_VERSION_2) { - mrcp_channel_id_parse(&message->channel_id,stream,message->pool); + mrcp_parser_t *mrcp_parser; + if(mrcp_channel_id_parse(&mrcp_message->channel_id,&mrcp_message->header,mrcp_message->pool) == FALSE) { + return FALSE; } - + mrcp_parser = apt_message_parser_object_get(parser); /* find resource */ - resource = mrcp_resource_find(parser->resource_factory,&message->channel_id.resource_name); + resource = mrcp_resource_find(mrcp_parser->resource_factory,&mrcp_message->channel_id.resource_name); if(!resource) { - return mrcp_parser_break(parser,stream); + return FALSE; } - if(mrcp_message_resource_set(message,resource) == FALSE) { - return mrcp_parser_break(parser,stream); + if(mrcp_message_resource_set(mrcp_message,resource) == FALSE) { + return FALSE; } - parser->stage = MRCP_STREAM_STAGE_HEADER; } - if(parser->stage == MRCP_STREAM_STAGE_HEADER) { - /* parse header */ - if(mrcp_message_header_parse(&message->header,stream,message->pool) == FALSE) { - return mrcp_parser_break(parser,stream); - } - - parser->stage = MRCP_STREAM_STAGE_NONE; - 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(message->pool,generic_header->content_length+1); - body->length = 0; - parser->stage = MRCP_STREAM_STAGE_BODY; - } - } + if(mrcp_header_fields_parse(&mrcp_message->header,mrcp_message->pool) == FALSE) { + return FALSE; } - if(parser->stage == MRCP_STREAM_STAGE_BODY) { - if(mrcp_message_body_read(message,stream) == FALSE) { - return mrcp_parser_break(parser,stream); + if(context->body && mrcp_generic_header_property_check(mrcp_message,GENERIC_HEADER_CONTENT_LENGTH) == TRUE) { + mrcp_generic_header_t *generic_header = mrcp_generic_header_get(mrcp_message); + if(generic_header && generic_header->content_length) { + context->body->length = generic_header->content_length; } - parser->stage = MRCP_STREAM_STAGE_NONE; - } - - /* in the worst case message segmentation may occur between and - of the final empty header */ - if(!message->body.length && *(stream->pos-1)== APT_TOKEN_CR) { - /* if this is the case be prepared to skip */ - parser->skip_lf = TRUE; } - return MRCP_STREAM_STATUS_COMPLETE; -} - -/** Get parsed MRCP message */ -MRCP_DECLARE(mrcp_message_t*) mrcp_parser_message_get(const mrcp_parser_t *parser) -{ - return parser->message; + return TRUE; } /** Create MRCP stream generator */ -MRCP_DECLARE(mrcp_generator_t*) mrcp_generator_create(mrcp_resource_factory_t *resource_factory, apr_pool_t *pool) +MRCP_DECLARE(mrcp_generator_t*) mrcp_generator_create(const mrcp_resource_factory_t *resource_factory, apr_pool_t *pool) { mrcp_generator_t *generator = apr_palloc(pool,sizeof(mrcp_generator_t)); + generator->base = apt_message_generator_create(generator,&generator_vtable,pool); generator->resource_factory = resource_factory; - generator->stage = MRCP_STREAM_STAGE_NONE; - 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) +/** Set verbose mode for the generator */ +MRCP_DECLARE(void) mrcp_generator_verbose_set(mrcp_generator_t *generator, apt_bool_t verbose) { - if(!message) { - return FALSE; - } - generator->message = message; - return TRUE; + apt_message_generator_verbose_set(generator->base,verbose); } -static mrcp_stream_status_e mrcp_generator_break(mrcp_generator_t *generator, apt_text_stream_t *stream) +/** Generate MRCP stream */ +MRCP_DECLARE(apt_message_status_e) mrcp_generator_run(mrcp_generator_t *generator, mrcp_message_t *message, apt_text_stream_t *stream) { - /* failed to generate message */ - if(apt_text_is_eos(stream) == TRUE) { - /* end of stream reached */ - return MRCP_STREAM_STATUS_INCOMPLETE; - } - - /* error case */ - generator->stage = MRCP_STREAM_STAGE_NONE; - return MRCP_STREAM_STATUS_INVALID; + return apt_message_generator_run(generator->base,message,stream); } -/** Generate MRCP stream */ -MRCP_DECLARE(mrcp_stream_status_e) mrcp_generator_run(mrcp_generator_t *generator, apt_text_stream_t *stream) +/** Initialize by generating message start line and return header section and body */ +apt_bool_t mrcp_generator_on_start(apt_message_generator_t *generator, apt_message_context_t *context, apt_text_stream_t *stream) { - mrcp_message_t *message = generator->message; - if(!message) { - return MRCP_STREAM_STATUS_INVALID; - } - - if(generator->stage == MRCP_STREAM_STAGE_NONE) { - /* validate message */ - if(mrcp_message_validate(message) == FALSE) { - return MRCP_STREAM_STATUS_INVALID; - } - generator->stage = MRCP_STREAM_STAGE_START_LINE; + mrcp_message_t *mrcp_message = context->message; + /* validate message */ + if(mrcp_message_validate(mrcp_message) == FALSE) { + return FALSE; } - - if(generator->stage == MRCP_STREAM_STAGE_START_LINE) { - /* generate start-line */ - if(mrcp_start_line_generate(&message->start_line,stream) == FALSE) { - return mrcp_generator_break(generator,stream); - } - - 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 mrcp_generator_break(generator,stream); - } - - /* finalize start-line generation */ - if(mrcp_start_line_finalize(&message->start_line,message->body.length,stream) == FALSE) { - return mrcp_generator_break(generator,stream); - } - - generator->stage = MRCP_STREAM_STAGE_NONE; - 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; - generator->stage = MRCP_STREAM_STAGE_BODY; - } - } + /* generate start-line */ + if(mrcp_start_line_generate(&mrcp_message->start_line,stream) == FALSE) { + return FALSE; } - - if(generator->stage == MRCP_STREAM_STAGE_BODY) { - if(mrcp_message_body_write(message,stream) == FALSE) { - return mrcp_generator_break(generator,stream); - } - generator->stage = MRCP_STREAM_STAGE_NONE; + if(mrcp_message->start_line.version == MRCP_VERSION_2) { + mrcp_channel_id_generate(&mrcp_message->channel_id,stream); } - return MRCP_STREAM_STATUS_COMPLETE; + context->header = &mrcp_message->header.header_section; + context->body = &mrcp_message->body; + return TRUE; } +/** Finalize by setting overall message length in start line */ +apt_bool_t mrcp_generator_on_header_complete(apt_message_generator_t *generator, apt_message_context_t *context, apt_text_stream_t *stream) +{ + mrcp_message_t *mrcp_message = context->message; + /* finalize start-line generation */ + return mrcp_start_line_finalize(&mrcp_message->start_line,mrcp_message->body.length,stream); +} -/** 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) +/** Generate MRCP message (excluding message body) */ +MRCP_DECLARE(apt_bool_t) mrcp_message_generate(const mrcp_resource_factory_t *resource_factory, mrcp_message_t *message, apt_text_stream_t *stream) { - mrcp_stream_status_e status; - if(parser->skip_lf == TRUE) { - /* skip occurred as a result of message segmentation between and */ - apt_text_char_skip(stream,APT_TOKEN_LF); - parser->skip_lf = FALSE; + /* validate message */ + if(mrcp_message_validate(message) == FALSE) { + return FALSE; } - do { - status = mrcp_parser_run(parser,stream); - if(status == MRCP_STREAM_STATUS_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,status); - } - else if(status == MRCP_STREAM_STATUS_INCOMPLETE) { - /* 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(status == MRCP_STREAM_STATUS_INVALID){ - /* error case */ - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse MRCP Message"); - /* invoke message handler */ - handler(obj,parser->message,status); - /* reset stream pos */ - stream->pos = stream->text.buf; - 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 section */ + if(apt_header_section_generate(&message->header.header_section,stream) == FALSE) { + return FALSE; + } + + /* finalize start-line generation */ + if(mrcp_start_line_finalize(&message->start_line,message->body.length,stream) == FALSE) { + return FALSE; } - while(apt_text_is_eos(stream) == FALSE); - /* reset stream pos */ - apt_text_stream_reset(stream); return TRUE; } diff --git a/libs/unimrcp/libs/mrcp/include/mrcp.h b/libs/unimrcp/libs/mrcp/include/mrcp.h index 0140a1bfe8..9425954a78 100644 --- a/libs/unimrcp/libs/mrcp/include/mrcp.h +++ b/libs/unimrcp/libs/mrcp/include/mrcp.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MRCP_H__ -#define __MRCP_H__ +#ifndef MRCP_H +#define MRCP_H /** * @file mrcp.h @@ -40,4 +42,4 @@ #define MRCP_DECLARE(type) type #endif -#endif /*__MRCP_H__*/ +#endif /* MRCP_H */ diff --git a/libs/unimrcp/libs/mrcp/include/mrcp_types.h b/libs/unimrcp/libs/mrcp/include/mrcp_types.h index 3177077b39..7509f01888 100644 --- a/libs/unimrcp/libs/mrcp/include/mrcp_types.h +++ b/libs/unimrcp/libs/mrcp/include/mrcp_types.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_types.h 1753 2010-08-16 20:46:45Z achaloyan $ */ -#ifndef __MRCP_TYPES_H__ -#define __MRCP_TYPES_H__ +#ifndef MRCP_TYPES_H +#define MRCP_TYPES_H /** * @file mrcp_types.h @@ -39,6 +41,7 @@ typedef enum { MRCP_SYNTHESIZER_RESOURCE, /**< Synthesizer resource */ MRCP_RECOGNIZER_RESOURCE, /**< Recognizer resource */ MRCP_RECORDER_RESOURCE, /**< Recorder resource */ + MRCP_VERIFIER_RESOURCE, /**< Verifier resource */ MRCP_RESOURCE_TYPE_COUNT /**< Number of resources */ } mrcp_resource_type_e; @@ -77,4 +80,4 @@ typedef struct mrcp_resource_factory_t mrcp_resource_factory_t; APT_END_EXTERN_C -#endif /*__MRCP_TYPES_H__*/ +#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 index fb8ebf852f..10b3d98917 100644 --- a/libs/unimrcp/libs/mrcp/message/include/mrcp_generic_header.h +++ b/libs/unimrcp/libs/mrcp/message/include/mrcp_generic_header.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_generic_header.h 1710 2010-05-24 17:36:19Z achaloyan $ */ -#ifndef __MRCP_GENERIC_HEADER_H__ -#define __MRCP_GENERIC_HEADER_H__ +#ifndef MRCP_GENERIC_HEADER_H +#define MRCP_GENERIC_HEADER_H /** * @file mrcp_generic_header.h @@ -27,7 +29,7 @@ APT_BEGIN_EXTERN_C -/** Enumeration of MRCP generic headers */ +/** Enumeration of MRCP generic header fields */ typedef enum { GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST, GENERIC_HEADER_PROXY_SYNC_ID, @@ -42,7 +44,7 @@ typedef enum { GENERIC_HEADER_LOGGING_TAG, GENERIC_HEADER_VENDOR_SPECIFIC_PARAMS, - /** Additional headers for MRCP v2 */ + /** Additional header fields for MRCP v2 */ GENERIC_HEADER_ACCEPT, GENERIC_HEADER_FETCH_TIMEOUT, GENERIC_HEADER_SET_COOKIE, @@ -65,7 +67,7 @@ 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; + apr_size_t count; }; @@ -97,7 +99,7 @@ struct mrcp_generic_header_t { /** Specifies the vendor specific parameters used by the media server */ apt_pair_arr_t *vendor_specific_params; - /** Additional headers for MRCP v2 */ + /** Additional header fields 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 */ @@ -115,9 +117,9 @@ MRCP_DECLARE(const mrcp_header_vtable_t*) mrcp_generic_header_vtable_get(mrcp_ve /** 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); +MRCP_DECLARE(apt_bool_t) active_request_id_list_find(const mrcp_generic_header_t *generic_header, mrcp_request_id request_id); APT_END_EXTERN_C -#endif /*__MRCP_GENERIC_HEADER_H__*/ +#endif /* MRCP_GENERIC_HEADER_H */ diff --git a/libs/unimrcp/libs/mrcp/message/include/mrcp_header.h b/libs/unimrcp/libs/mrcp/message/include/mrcp_header.h new file mode 100644 index 0000000000..91655864c9 --- /dev/null +++ b/libs/unimrcp/libs/mrcp/message/include/mrcp_header.h @@ -0,0 +1,121 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: mrcp_header.h 1648 2010-04-12 20:03:59Z achaloyan $ + */ + +#ifndef MRCP_HEADER_H +#define MRCP_HEADER_H + +/** + * @file mrcp_header.h + * @brief MRCP Message Header Definition + */ + +#include "mrcp_header_accessor.h" + +APT_BEGIN_EXTERN_C + +/** + * Allows external applications to trigger whether + * transaprent header fields are supported or not + */ +#define TRANSPARENT_HEADER_FIELDS_SUPPORT + +/** MRCP message header declaration */ +typedef struct mrcp_message_header_t mrcp_message_header_t; +/** MRCP channel-id declaration */ +typedef struct mrcp_channel_id mrcp_channel_id; + + +/** 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; + + /** Header section (collection of header fields)*/ + apt_header_section_t header_section; +}; + +/** 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; +}; + + +/** Initialize MRCP message-header */ +static APR_INLINE void mrcp_message_header_init(mrcp_message_header_t *header) +{ + mrcp_header_accessor_init(&header->generic_header_accessor); + mrcp_header_accessor_init(&header->resource_header_accessor); + apt_header_section_init(&header->header_section); +} + +/** Allocate MRCP message-header data */ +MRCP_DECLARE(apt_bool_t) mrcp_message_header_data_alloc( + mrcp_message_header_t *header, + const mrcp_header_vtable_t *generic_header_vtable, + const mrcp_header_vtable_t *resource_header_vtable, + apr_pool_t *pool); + +/** Create MRCP message-header */ +MRCP_DECLARE(mrcp_message_header_t*) mrcp_message_header_create( + const mrcp_header_vtable_t *generic_header_vtable, + const mrcp_header_vtable_t *resource_header_vtable, + apr_pool_t *pool); + +/** Destroy MRCP message-header */ +static APR_INLINE void mrcp_message_header_destroy(mrcp_message_header_t *header) +{ + mrcp_header_destroy(&header->generic_header_accessor); + mrcp_header_destroy(&header->resource_header_accessor); +} + +/** Add MRCP header field */ +MRCP_DECLARE(apt_bool_t) mrcp_header_field_add(mrcp_message_header_t *header, apt_header_field_t *header_field, apr_pool_t *pool); + + +/** Set (copy) MRCP header fields */ +MRCP_DECLARE(apt_bool_t) mrcp_header_fields_set(mrcp_message_header_t *header, const mrcp_message_header_t *src_header, apr_pool_t *pool); + +/** Get (copy) MRCP header fields */ +MRCP_DECLARE(apt_bool_t) mrcp_header_fields_get(mrcp_message_header_t *header, const mrcp_message_header_t *src_header, apr_pool_t *pool); + +/** Inherit (copy) MRCP header fields */ +MRCP_DECLARE(apt_bool_t) mrcp_header_fields_inherit(mrcp_message_header_t *header, const mrcp_message_header_t *src_header, apr_pool_t *pool); + +/** Parse MRCP header fields */ +MRCP_DECLARE(apt_bool_t) mrcp_header_fields_parse(mrcp_message_header_t *header, apr_pool_t *pool); + + +/** 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, mrcp_message_header_t *header, 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); + + + +APT_END_EXTERN_C + +#endif /* MRCP_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 index dbd52d2d47..e2c7590f0d 100644 --- a/libs/unimrcp/libs/mrcp/message/include/mrcp_header_accessor.h +++ b/libs/unimrcp/libs/mrcp/message/include/mrcp_header_accessor.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,18 +12,20 @@ * 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. + * + * $Id: mrcp_header_accessor.h 1632 2010-03-30 20:46:25Z achaloyan $ */ -#ifndef __MRCP_HEADER_ACCESSOR_H__ -#define __MRCP_HEADER_ACCESSOR_H__ +#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 "apt_header_field.h" #include "mrcp.h" APT_BEGIN_EXTERN_C @@ -40,12 +42,12 @@ struct mrcp_header_vtable_t { /** Destroy header data */ void (*destroy)(mrcp_header_accessor_t *accessor); - /** Parse header field */ + /** Parse header field value */ 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); + /** Generate header field value */ + apt_bool_t (*generate_field)(const mrcp_header_accessor_t *accessor, apr_size_t id, apt_str_t *value, apr_pool_t *pool); + /** Duplicate header field value */ + apt_bool_t (*duplicate_field)(mrcp_header_accessor_t *accessor, const mrcp_header_accessor_t *src, apr_size_t id, const apt_str_t *value, apr_pool_t *pool); /** Table of fields */ const apt_str_table_item_t *field_table; @@ -53,6 +55,15 @@ struct mrcp_header_vtable_t { apr_size_t field_count; }; +/** MRCP header accessor */ +struct mrcp_header_accessor_t { + /** Actual header data allocated by accessor */ + void *data; + /** Header accessor interface */ + const mrcp_header_vtable_t *vtable; +}; + + /** Initialize header vtable */ static APR_INLINE void mrcp_header_vtable_init(mrcp_header_vtable_t *vtable) @@ -76,30 +87,13 @@ static APR_INLINE apt_bool_t mrcp_header_vtable_validate(const mrcp_header_vtabl } -/** 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) { @@ -109,8 +103,6 @@ static APR_INLINE void* mrcp_header_allocate(mrcp_header_accessor_t *accessor, a 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); } @@ -124,35 +116,16 @@ static APR_INLINE void mrcp_header_destroy(mrcp_header_accessor_t *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); +/** Parse header field value */ +MRCP_DECLARE(apt_bool_t) mrcp_header_field_value_parse(mrcp_header_accessor_t *accessor, apt_header_field_t *header_field, apr_pool_t *pool); -/** Add name only property */ -MRCP_DECLARE(void) mrcp_header_name_property_add(mrcp_header_accessor_t *accessor, apr_size_t id); +/** Generate header field value */ +MRCP_DECLARE(apt_header_field_t*) mrcp_header_field_value_generate(const mrcp_header_accessor_t *accessor, apr_size_t id, apt_bool_t empty_value, apr_pool_t *pool); +/** Duplicate header field value */ +MRCP_DECLARE(apt_bool_t) mrcp_header_field_value_duplicate(mrcp_header_accessor_t *accessor, const mrcp_header_accessor_t *src_accessor, apr_size_t id, const apt_str_t *value, apr_pool_t *pool); -/** Generate completion-cause */ -MRCP_DECLARE(apt_bool_t) mrcp_completion_cause_generate(const apt_str_table_item_t table[], apr_size_t size, apr_size_t cause, apt_text_stream_t *stream); APT_END_EXTERN_C -#endif /*__MRCP_HEADER_ACCESSOR_H__*/ +#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 index 497a14d7c3..3bfe453882 100644 --- a/libs/unimrcp/libs/mrcp/message/include/mrcp_message.h +++ b/libs/unimrcp/libs/mrcp/message/include/mrcp_message.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_message.h 1721 2010-06-01 05:45:46Z achaloyan $ */ -#ifndef __MRCP_MESSAGE_H__ -#define __MRCP_MESSAGE_H__ +#ifndef MRCP_MESSAGE_H +#define MRCP_MESSAGE_H /** * @file mrcp_message.h @@ -24,176 +26,228 @@ #include "mrcp_types.h" #include "mrcp_start_line.h" -#include "mrcp_header_accessor.h" +#include "mrcp_header.h" +#include "mrcp_generic_header.h" APT_BEGIN_EXTERN_C -/** 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; - -/** 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; -}; - -/** 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); - - +/** Macro to log channel identifier of the message */ +#define MRCP_MESSAGE_SIDRES(message) \ + (message)->channel_id.session_id.buf, (message)->channel_id.resource_name.buf /** MRCP message */ struct mrcp_message_t { /** Start-line of MRCP message */ - mrcp_start_line_t start_line; + mrcp_start_line_t start_line; /** Channel-identifier of MRCP message */ - mrcp_channel_id channel_id; + mrcp_channel_id channel_id; /** Header of MRCP message */ - mrcp_message_header_t header; + mrcp_message_header_t header; /** Body of MRCP message */ - apt_str_t body; + apt_str_t body; /** Associated MRCP resource */ - mrcp_resource_t *resource; - /** Memory pool MRCP message is allocated from */ - apr_pool_t *pool; + const mrcp_resource_t *resource; + /** Memory pool to allocate memory from */ + apr_pool_t *pool; }; -/** Create MRCP message */ +/** + * Create an MRCP message. + * @param pool the pool to allocate memory from + */ MRCP_DECLARE(mrcp_message_t*) mrcp_message_create(apr_pool_t *pool); -/** Create MRCP request message */ -MRCP_DECLARE(mrcp_message_t*) mrcp_request_create(mrcp_resource_t *resource, mrcp_version_e version, mrcp_method_id method_id, apr_pool_t *pool); -/** Create MRCP response message */ +/** + * Create an MRCP request message. + * @param resource the MRCP resource to use + * @param version the MRCP version to use + * @param method_id the MRCP resource specific method identifier + * @param pool the pool to allocate memory from + */ +MRCP_DECLARE(mrcp_message_t*) mrcp_request_create( + const mrcp_resource_t *resource, + mrcp_version_e version, + mrcp_method_id method_id, + apr_pool_t *pool); + +/** + * Create an MRCP response message based on given request message. + * @param request_message the MRCP request message to create a response for + * @param pool the pool to allocate memory from + */ 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); -/** Associate MRCP resource specific data by resource name */ -MRCP_DECLARE(apt_bool_t) mrcp_message_resource_set(mrcp_message_t *message, mrcp_resource_t *resource); +/** + * Create an MRCP event message based on given requuest message. + * @param request_message the MRCP request message to create an event for + * @param event_id the MRCP resource specific event identifier + * @param pool the pool to allocate memory from + */ +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 */ +/** + * Associate MRCP resource with message. + * @param message the message to associate resource with + * @param resource the resource to associate + */ +MRCP_DECLARE(apt_bool_t) mrcp_message_resource_set(mrcp_message_t *message, const mrcp_resource_t *resource); + +/** + * Validate MRCP message. + * @param message the message to validate + */ MRCP_DECLARE(apt_bool_t) mrcp_message_validate(mrcp_message_t *message); -/** Destroy MRCP message */ +/** + * Destroy MRCP message. + * @param message the message to destroy + */ 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) +/** + * Get MRCP generic header. + * @param message the message to get generic header from + */ +static APR_INLINE mrcp_generic_header_t* mrcp_generic_header_get(const mrcp_message_t *message) { - return mrcp_message->header.generic_header_accessor.data; + return (mrcp_generic_header_t*) message->header.generic_header_accessor.data; } -/** Prepare MRCP generic-header */ -static APR_INLINE void* mrcp_generic_header_prepare(mrcp_message_t *mrcp_message) +/** + * Allocate (if not allocated) and get MRCP generic header. + * @param message the message to prepare generic header for + */ +static APR_INLINE mrcp_generic_header_t* mrcp_generic_header_prepare(mrcp_message_t *message) { - return mrcp_header_allocate(&mrcp_message->header.generic_header_accessor,mrcp_message->pool); + return (mrcp_generic_header_t*) mrcp_header_allocate(&message->header.generic_header_accessor,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 field by specified property (numeric identifier). + * @param message the message to add property for + * @param id the numeric identifier to add + */ +MRCP_DECLARE(apt_bool_t) mrcp_generic_header_property_add(mrcp_message_t *message, apr_size_t 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) +/** + * Add only the name of MRCP generic header field specified by property (numeric identifier). + * @param message the message to add property for + * @param id the numeric identifier to add + * @remark Should be used to construct empty header fiedls for GET-PARAMS requests + */ +MRCP_DECLARE(apt_bool_t) mrcp_generic_header_name_property_add(mrcp_message_t *message, apr_size_t id); + +/** + * Remove MRCP generic header field by specified property (numeric identifier). + * @param message the message to remove property from + * @param id the numeric identifier to remove + */ +static APR_INLINE apt_bool_t mrcp_generic_header_property_remove(mrcp_message_t *message, apr_size_t id) { - mrcp_header_name_property_add(&mrcp_message->header.generic_header_accessor,id); + apt_header_field_t *header_field = apt_header_section_field_get(&message->header.header_section,id); + if(header_field) { + return apt_header_section_field_remove(&message->header.header_section,header_field); + } + return FALSE; } -/** Check MRCP generic-header proprerty */ -static APR_INLINE apt_bool_t mrcp_generic_header_property_check(mrcp_message_t *mrcp_message, size_t id) +/** + * Check whether specified by property (numeric identifier) MRCP generic header field is set or not. + * @param message the message to use + * @param id the numeric identifier to check + */ +static APR_INLINE apt_bool_t mrcp_generic_header_property_check(const mrcp_message_t *message, apr_size_t id) { - return mrcp_header_property_check(&mrcp_message->header.generic_header_accessor,id); + return apt_header_section_field_check(&message->header.header_section,id); } -/** Get MRCP resource-header */ -static APR_INLINE void* mrcp_resource_header_get(const mrcp_message_t *mrcp_message) +/** + * Get MRCP resource header. + * @param message the message to get resource header from + */ +static APR_INLINE void* mrcp_resource_header_get(const mrcp_message_t *message) { - return mrcp_message->header.resource_header_accessor.data; + return message->header.resource_header_accessor.data; } -/** Prepare MRCP resource-header */ +/** + * Allocate (if not allocated) and get MRCP resource header. + * @param message the message to prepare resource header for + */ 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) +/** + * Add MRCP resource header field by specified property (numeric identifier). + * @param message the message to add property for + * @param id the numeric identifier to add + */ +MRCP_DECLARE(apt_bool_t) mrcp_resource_header_property_add(mrcp_message_t *message, apr_size_t id); + +/** + * Add only the name of MRCP resource header field specified by property (numeric identifier). + * @param message the message to add property for + * @param id the numeric identifier to add + * @remark Should be used to construct empty header fiedls for GET-PARAMS requests + */ +MRCP_DECLARE(apt_bool_t) mrcp_resource_header_name_property_add(mrcp_message_t *message, apr_size_t id); + +/** + * Remove MRCP resource header field by specified property (numeric identifier). + * @param message the message to remove property from + * @param id the numeric identifier to remove + */ +static APR_INLINE apt_bool_t mrcp_resource_header_property_remove(mrcp_message_t *message, apr_size_t id) { - mrcp_header_property_add(&mrcp_message->header.resource_header_accessor,id); + apt_header_field_t *header_field = apt_header_section_field_get(&message->header.header_section,id + GENERIC_HEADER_COUNT); + if(header_field) { + return apt_header_section_field_remove(&message->header.header_section,header_field); + } + return FALSE; } -/** 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) +/** + * Check whether specified by property (numeric identifier) MRCP resource header field is set or not. + * @param message the message to use + * @param id the numeric identifier to check + */ +static APR_INLINE apt_bool_t mrcp_resource_header_property_check(const mrcp_message_t *message, apr_size_t id) { - mrcp_header_name_property_add(&mrcp_message->header.resource_header_accessor,id); + return apt_header_section_field_check(&message->header.header_section,id + GENERIC_HEADER_COUNT); } -/** Check MRCP resource-header proprerty */ -static APR_INLINE apt_bool_t mrcp_resource_header_property_check(mrcp_message_t *mrcp_message, size_t id) +/** + * Add MRCP header field. + * @param message the message to add header field for + * @param header_field the header field to add + */ +static APR_INLINE apt_bool_t mrcp_message_header_field_add(mrcp_message_t *message, apt_header_field_t *header_field) { - return mrcp_header_property_check(&mrcp_message->header.resource_header_accessor,id); + return mrcp_header_field_add(&message->header,header_field,message->pool); } +/** + * Get the next MRCP header field. + * @param message the message to use + * @param header_field current header field + * @remark Should be used to iterate on header fields + * + * apt_header_field_t *header_field = NULL; + * while( (header_field = mrcp_message_next_header_field_get(message,header_field)) != NULL ) { + * } + */ +MRCP_DECLARE(apt_header_field_t*) mrcp_message_next_header_field_get( + const mrcp_message_t *message, + apt_header_field_t *header_field); + APT_END_EXTERN_C -#endif /*__MRCP_MESSAGE_H__*/ +#endif /* MRCP_MESSAGE_H */ diff --git a/libs/unimrcp/libs/mrcp/message/include/mrcp_start_line.h b/libs/unimrcp/libs/mrcp/message/include/mrcp_start_line.h index 1c6db22d40..0273229b75 100644 --- a/libs/unimrcp/libs/mrcp/message/include/mrcp_start_line.h +++ b/libs/unimrcp/libs/mrcp/message/include/mrcp_start_line.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_start_line.h 1632 2010-03-30 20:46:25Z achaloyan $ */ -#ifndef __MRCP_START_LINE_H__ -#define __MRCP_START_LINE_H__ +#ifndef MRCP_START_LINE_H +#define MRCP_START_LINE_H /** * @file mrcp_start_line.h @@ -59,6 +61,7 @@ typedef enum { MRCP_STATUS_CODE_METHOD_FAILED = 407, MRCP_STATUS_CODE_UNRECOGNIZED_MESSAGE = 408, MRCP_STATUS_CODE_UNSUPPORTED_PARAM_VALUE = 409, + MRCP_STATUS_CODE_OUT_OF_ORDER = 410, MRCP_STATUS_CODE_RESOURCE_SPECIFIC_FAILURE = 421 } mrcp_status_code_e; @@ -97,7 +100,7 @@ struct mrcp_start_line_t { /** 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); +MRCP_DECLARE(apt_bool_t) mrcp_start_line_parse(mrcp_start_line_t *start_line, apt_str_t *str, 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 */ @@ -111,4 +114,4 @@ MRCP_DECLARE(apt_bool_t) mrcp_request_id_generate(mrcp_request_id request_id, ap APT_END_EXTERN_C -#endif /*__MRCP_START_LINE_H__*/ +#endif /* MRCP_START_LINE_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 index 1b1d1a7d7f..dc8878b446 100644 --- a/libs/unimrcp/libs/mrcp/message/src/mrcp_generic_header.c +++ b/libs/unimrcp/libs/mrcp/message/src/mrcp_generic_header.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_generic_header.c 1710 2010-05-24 17:36:19Z achaloyan $ */ #include "mrcp_generic_header.h" @@ -56,15 +58,20 @@ static apt_bool_t mrcp_request_id_list_parse(mrcp_request_id_list_t *request_id_ } /** 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) +static apt_bool_t mrcp_request_id_list_generate(mrcp_request_id_list_t *request_id_list, apt_str_t *str, apr_pool_t *pool) { - size_t i; + apr_size_t i; + char buf[256]; + apt_text_stream_t stream; + apt_text_stream_init(&stream,buf,sizeof(buf)); for(i=0; icount; i++) { - mrcp_request_id_generate(request_id_list->ids[i],stream); + mrcp_request_id_generate(request_id_list->ids[i],&stream); if(i < request_id_list->count-1) { - *stream->pos++ = ','; + *stream.pos++ = ','; } } + + apt_string_assign_n(str,stream.text.buf, stream.pos - stream.text.buf, pool); return TRUE; } @@ -84,7 +91,7 @@ static void mrcp_generic_header_init(mrcp_generic_header_t *generic_header) 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 */ + /* initializes additionnal MRCP v2 generic header fields */ apt_string_reset(&generic_header->accept); generic_header->fetch_timeout = 0; apt_string_reset(&generic_header->set_cookie); @@ -111,34 +118,34 @@ static apt_bool_t mrcp_generic_header_parse(mrcp_header_accessor_t *accessor, si 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); + generic_header->proxy_sync_id = *value; break; case GENERIC_HEADER_ACCEPT_CHARSET: - apt_string_copy(&generic_header->accept_charset,value,pool); + generic_header->accept_charset = *value; break; case GENERIC_HEADER_CONTENT_TYPE: - apt_string_copy(&generic_header->content_type,value,pool); + generic_header->content_type = *value; break; case GENERIC_HEADER_CONTENT_ID: - apt_string_copy(&generic_header->content_id,value,pool); + generic_header->content_id = *value; break; case GENERIC_HEADER_CONTENT_BASE: - apt_string_copy(&generic_header->content_base,value,pool); + generic_header->content_base = *value; break; case GENERIC_HEADER_CONTENT_ENCODING: - apt_string_copy(&generic_header->content_encoding,value,pool); + generic_header->content_encoding = *value; break; case GENERIC_HEADER_CONTENT_LOCATION: - apt_string_copy(&generic_header->content_location,value,pool); + generic_header->content_location = *value; 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); + generic_header->cache_control = *value; break; case GENERIC_HEADER_LOGGING_TAG: - apt_string_copy(&generic_header->logging_tag,value,pool); + generic_header->logging_tag = *value; break; case GENERIC_HEADER_VENDOR_SPECIFIC_PARAMS: if(!generic_header->vendor_specific_params) { @@ -147,16 +154,16 @@ static apt_bool_t mrcp_generic_header_parse(mrcp_header_accessor_t *accessor, si apt_pair_array_parse(generic_header->vendor_specific_params,value,pool); break; case GENERIC_HEADER_ACCEPT: - apt_string_copy(&generic_header->accept,value,pool); + generic_header->accept = *value; 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); + generic_header->set_cookie = *value; break; case GENERIC_HEADER_SET_COOKIE2: - apt_string_copy(&generic_header->set_cookie2,value,pool); + generic_header->set_cookie2 = *value; break; default: status = FALSE; @@ -165,57 +172,57 @@ static apt_bool_t mrcp_generic_header_parse(mrcp_header_accessor_t *accessor, si } /** Generate generic-header */ -static apt_bool_t mrcp_generic_header_generate(mrcp_header_accessor_t *accessor, size_t id, apt_text_stream_t *value) +static apt_bool_t mrcp_generic_header_generate(const mrcp_header_accessor_t *accessor, apr_size_t id, apt_str_t *value, apr_pool_t *pool) { 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); + mrcp_request_id_list_generate(&generic_header->active_request_id_list,value,pool); break; case GENERIC_HEADER_PROXY_SYNC_ID: - apt_string_value_generate(&generic_header->proxy_sync_id,value); + *value = generic_header->proxy_sync_id; break; case GENERIC_HEADER_ACCEPT_CHARSET: - apt_string_value_generate(&generic_header->accept_charset,value); + *value = generic_header->accept_charset; break; case GENERIC_HEADER_CONTENT_TYPE: - apt_string_value_generate(&generic_header->content_type,value); + *value = generic_header->content_type; break; case GENERIC_HEADER_CONTENT_ID: - apt_string_value_generate(&generic_header->content_id,value); + *value = generic_header->content_id; break; case GENERIC_HEADER_CONTENT_BASE: - apt_string_value_generate(&generic_header->content_base,value); + *value = generic_header->content_base; break; case GENERIC_HEADER_CONTENT_ENCODING: - apt_string_value_generate(&generic_header->content_encoding,value); + *value = generic_header->content_encoding; break; case GENERIC_HEADER_CONTENT_LOCATION: - apt_string_value_generate(&generic_header->content_location,value); + *value = generic_header->content_location; break; case GENERIC_HEADER_CONTENT_LENGTH: - apt_size_value_generate(generic_header->content_length,value); + apt_size_value_generate(generic_header->content_length,value,pool); break; case GENERIC_HEADER_CACHE_CONTROL: - apt_string_value_generate(&generic_header->cache_control,value); + *value = generic_header->cache_control; break; case GENERIC_HEADER_LOGGING_TAG: - apt_string_value_generate(&generic_header->logging_tag,value); + *value = generic_header->logging_tag; break; case GENERIC_HEADER_VENDOR_SPECIFIC_PARAMS: - apt_pair_array_generate(generic_header->vendor_specific_params,value); + apt_pair_array_generate(generic_header->vendor_specific_params,value,pool); break; case GENERIC_HEADER_ACCEPT: - apt_string_value_generate(&generic_header->accept,value); + *value = generic_header->accept; break; case GENERIC_HEADER_FETCH_TIMEOUT: - apt_size_value_generate(generic_header->fetch_timeout,value); + apt_size_value_generate(generic_header->fetch_timeout,value,pool); break; case GENERIC_HEADER_SET_COOKIE: - apt_string_value_generate(&generic_header->set_cookie,value); + *value = generic_header->set_cookie; break; case GENERIC_HEADER_SET_COOKIE2: - apt_string_value_generate(&generic_header->set_cookie2,value); + *value = generic_header->set_cookie2; break; default: break; @@ -224,7 +231,7 @@ static apt_bool_t mrcp_generic_header_generate(mrcp_header_accessor_t *accessor, } /** 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) +static apt_bool_t mrcp_generic_header_duplicate(mrcp_header_accessor_t *accessor, const mrcp_header_accessor_t *src, apr_size_t id, const apt_str_t *value, apr_pool_t *pool) { mrcp_generic_header_t *generic_header = accessor->data; const mrcp_generic_header_t *src_generic_header = src->data; @@ -238,49 +245,49 @@ static apt_bool_t mrcp_generic_header_duplicate(mrcp_header_accessor_t *accessor 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); + generic_header->proxy_sync_id = *value; break; case GENERIC_HEADER_ACCEPT_CHARSET: - apt_string_copy(&generic_header->accept_charset,&src_generic_header->accept_charset,pool); + generic_header->accept_charset = *value; break; case GENERIC_HEADER_CONTENT_TYPE: - apt_string_copy(&generic_header->content_type,&src_generic_header->content_type,pool); + generic_header->content_type = *value; break; case GENERIC_HEADER_CONTENT_ID: - apt_string_copy(&generic_header->content_id,&src_generic_header->content_id,pool); + generic_header->content_id = *value; break; case GENERIC_HEADER_CONTENT_BASE: - apt_string_copy(&generic_header->content_base,&src_generic_header->content_base,pool); + generic_header->content_base = *value; break; case GENERIC_HEADER_CONTENT_ENCODING: - apt_string_copy(&generic_header->content_encoding,&src_generic_header->content_encoding,pool); + generic_header->content_encoding = *value; break; case GENERIC_HEADER_CONTENT_LOCATION: - apt_string_copy(&generic_header->content_location,&src_generic_header->content_location,pool); + generic_header->content_location = *value; 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); + generic_header->cache_control = *value; break; case GENERIC_HEADER_LOGGING_TAG: - apt_string_copy(&generic_header->logging_tag,&src_generic_header->logging_tag,pool); + generic_header->logging_tag = *value; 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); + generic_header->accept = *value; 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); + generic_header->set_cookie = *value; break; case GENERIC_HEADER_SET_COOKIE2: - apt_string_copy(&generic_header->set_cookie2,&src_generic_header->set_cookie2,pool); + generic_header->set_cookie2 = *value; break; default: status = FALSE; @@ -317,10 +324,10 @@ MRCP_DECLARE(apt_bool_t) active_request_id_list_append(mrcp_generic_header_t *ge } /** 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) +MRCP_DECLARE(apt_bool_t) active_request_id_list_find(const 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; + const mrcp_request_id_list_t *request_id_list = &generic_header->active_request_id_list; for(i=0; icount; i++) { if(request_id_list->ids[i] == request_id) { return TRUE; diff --git a/libs/unimrcp/libs/mrcp/message/src/mrcp_header.c b/libs/unimrcp/libs/mrcp/message/src/mrcp_header.c new file mode 100644 index 0000000000..864baedc42 --- /dev/null +++ b/libs/unimrcp/libs/mrcp/message/src/mrcp_header.c @@ -0,0 +1,267 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: mrcp_header.c 1737 2010-06-15 18:29:17Z achaloyan $ + */ + +#include "mrcp_header.h" +#include "mrcp_generic_header.h" +#include "apt_text_message.h" +#include "apt_log.h" + +#define MRCP_CHANNEL_ID "Channel-Identifier" +#define MRCP_CHANNEL_ID_LENGTH (sizeof(MRCP_CHANNEL_ID)-1) + + +/** Allocate MRCP message-header data */ +MRCP_DECLARE(apt_bool_t) mrcp_message_header_data_alloc( + mrcp_message_header_t *header, + const mrcp_header_vtable_t *generic_header_vtable, + const mrcp_header_vtable_t *resource_header_vtable, + apr_pool_t *pool) +{ + if(!generic_header_vtable || !resource_header_vtable) { + return FALSE; + } + + header->generic_header_accessor.data = NULL; + header->generic_header_accessor.vtable = generic_header_vtable; + + header->resource_header_accessor.data = NULL; + header->resource_header_accessor.vtable = resource_header_vtable; + + apt_header_section_array_alloc( + &header->header_section, + header->generic_header_accessor.vtable->field_count + + header->resource_header_accessor.vtable->field_count, + pool); + + mrcp_header_allocate(&header->generic_header_accessor,pool); + mrcp_header_allocate(&header->resource_header_accessor,pool); + return TRUE; +} + +MRCP_DECLARE(mrcp_message_header_t*) mrcp_message_header_create( + const mrcp_header_vtable_t *generic_header_vtable, + const mrcp_header_vtable_t *resource_header_vtable, + apr_pool_t *pool) +{ + mrcp_message_header_t *header = apr_palloc(pool,sizeof(mrcp_message_header_t)); + apt_header_section_init(&header->header_section); + mrcp_message_header_data_alloc(header,generic_header_vtable,resource_header_vtable,pool); + return header; +} + +/** Add MRCP header field */ +MRCP_DECLARE(apt_bool_t) mrcp_header_field_add(mrcp_message_header_t *header, apt_header_field_t *header_field, apr_pool_t *pool) +{ + apt_bool_t status = FALSE; + if(apt_string_is_empty(&header_field->name) == FALSE) { + /* normal header */ + if(mrcp_header_field_value_parse(&header->resource_header_accessor,header_field,pool) == TRUE) { + header_field->id += GENERIC_HEADER_COUNT; + } + else if(mrcp_header_field_value_parse(&header->generic_header_accessor,header_field,pool) == TRUE) { + status = apt_header_section_field_add(&header->header_section,header_field); + } + else { + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Unknown MRCP header field: %s",header_field->name.buf); + } + status = apt_header_section_field_add(&header->header_section,header_field); + } + return status; +} + +/** Parse MRCP header fields */ +MRCP_DECLARE(apt_bool_t) mrcp_header_fields_parse(mrcp_message_header_t *header, apr_pool_t *pool) +{ + apt_header_field_t *header_field; + for(header_field = APR_RING_FIRST(&header->header_section.ring); + header_field != APR_RING_SENTINEL(&header->header_section.ring, apt_header_field_t, link); + header_field = APR_RING_NEXT(header_field, link)) { + + if(mrcp_header_field_value_parse(&header->resource_header_accessor,header_field,pool) == TRUE) { + header_field->id += GENERIC_HEADER_COUNT; + apt_header_section_field_set(&header->header_section,header_field); + } + else if(mrcp_header_field_value_parse(&header->generic_header_accessor,header_field,pool) == TRUE) { + apt_header_section_field_set(&header->header_section,header_field); + } + else { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown MRCP header field: %s",header_field->name.buf); + } + } + + return TRUE; +} + +/** Set (copy) MRCP header fields */ +MRCP_DECLARE(apt_bool_t) mrcp_header_fields_set(mrcp_message_header_t *header, const mrcp_message_header_t *src_header, apr_pool_t *pool) +{ + apt_header_field_t *header_field; + const apt_header_field_t *src_header_field; + for(src_header_field = APR_RING_FIRST(&src_header->header_section.ring); + src_header_field != APR_RING_SENTINEL(&src_header->header_section.ring, apt_header_field_t, link); + src_header_field = APR_RING_NEXT(src_header_field, link)) { + + header_field = apt_header_field_copy(src_header_field,pool); + if(header_field->id < GENERIC_HEADER_COUNT) { + if(mrcp_header_field_value_duplicate( + &header->generic_header_accessor, + &src_header->generic_header_accessor, + header_field->id, + &header_field->value, + pool) == TRUE) { + apt_header_section_field_add(&header->header_section,header_field); + } + } + else { + if(mrcp_header_field_value_duplicate( + &header->resource_header_accessor, + &src_header->resource_header_accessor, + header_field->id - GENERIC_HEADER_COUNT, + &header_field->value, + pool) == TRUE) { + apt_header_section_field_add(&header->header_section,header_field); + } + } + } + + return TRUE; +} + +/** Get (copy) MRCP header fields */ +MRCP_DECLARE(apt_bool_t) mrcp_header_fields_get(mrcp_message_header_t *header, const mrcp_message_header_t *src_header, apr_pool_t *pool) +{ + apt_header_field_t *header_field; + const apt_header_field_t *src_header_field; + for(header_field = APR_RING_FIRST(&header->header_section.ring); + header_field != APR_RING_SENTINEL(&header->header_section.ring, apt_header_field_t, link); + header_field = APR_RING_NEXT(header_field, link)) { + + src_header_field = apt_header_section_field_get(&src_header->header_section,header_field->id); + if(src_header_field) { + if(header_field->id < GENERIC_HEADER_COUNT) { + apt_string_copy(&header_field->value,&src_header_field->value,pool); + mrcp_header_field_value_duplicate( + &header->generic_header_accessor, + &src_header->generic_header_accessor, + header_field->id, + &header_field->value, + pool); + } + else { + apt_string_copy(&header_field->value,&src_header_field->value,pool); + mrcp_header_field_value_duplicate( + &header->resource_header_accessor, + &src_header->resource_header_accessor, + header_field->id - GENERIC_HEADER_COUNT, + &header_field->value, + pool); + } + } + } + + return TRUE; +} + +/** Inherit (copy) MRCP header fields */ +MRCP_DECLARE(apt_bool_t) mrcp_header_fields_inherit(mrcp_message_header_t *header, const mrcp_message_header_t *src_header, apr_pool_t *pool) +{ + apt_header_field_t *header_field; + const apt_header_field_t *src_header_field; + for(src_header_field = APR_RING_FIRST(&src_header->header_section.ring); + src_header_field != APR_RING_SENTINEL(&src_header->header_section.ring, apt_header_field_t, link); + src_header_field = APR_RING_NEXT(src_header_field, link)) { + + header_field = apt_header_section_field_get(&header->header_section,src_header_field->id); + if(!header_field) { + header_field = apt_header_field_copy(src_header_field,pool); + if(header_field->id < GENERIC_HEADER_COUNT) { + if(mrcp_header_field_value_duplicate( + &header->generic_header_accessor, + &src_header->generic_header_accessor, + header_field->id, + &header_field->value, + pool) == TRUE) { + apt_header_section_field_add(&header->header_section,header_field); + } + } + else { + if(mrcp_header_field_value_duplicate( + &header->resource_header_accessor, + &src_header->resource_header_accessor, + header_field->id - GENERIC_HEADER_COUNT, + &header_field->value, + pool) == TRUE) { + apt_header_section_field_add(&header->header_section,header_field); + } + } + } + } + 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); +} + +/** Parse MRCP channel-identifier */ +MRCP_DECLARE(apt_bool_t) mrcp_channel_id_parse(mrcp_channel_id *channel_id, mrcp_message_header_t *header, apr_pool_t *pool) +{ + apt_header_field_t *header_field; + for(header_field = APR_RING_FIRST(&header->header_section.ring); + header_field != APR_RING_SENTINEL(&header->header_section.ring, apt_header_field_t, link); + header_field = APR_RING_NEXT(header_field, link)) { + + if(header_field->value.length && strncasecmp(header_field->name.buf,MRCP_CHANNEL_ID,MRCP_CHANNEL_ID_LENGTH) == 0) { + apt_id_resource_parse(&header_field->value,'@',&channel_id->session_id,&channel_id->resource_name,pool); + apt_header_section_field_remove(&header->header_section,header_field); + return TRUE; + } + } + return FALSE; +} + +/** Generate MRCP channel-identifier */ +MRCP_DECLARE(apt_bool_t) mrcp_channel_id_generate(mrcp_channel_id *channel_id, apt_text_stream_t *stream) +{ + apt_str_t *str; + char *pos = stream->pos; + if(pos + MRCP_CHANNEL_ID_LENGTH + 2 + channel_id->session_id.length + 1 + + channel_id->resource_name.length >= stream->end) { + return FALSE; + } + memcpy(pos,MRCP_CHANNEL_ID,MRCP_CHANNEL_ID_LENGTH); + pos += MRCP_CHANNEL_ID_LENGTH; + *pos++ = ':'; + *pos++ = APT_TOKEN_SP; + + 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; + + stream->pos = pos; + return apt_text_eol_insert(stream); +} diff --git a/libs/unimrcp/libs/mrcp/message/src/mrcp_header_accessor.c b/libs/unimrcp/libs/mrcp/message/src/mrcp_header_accessor.c index ae80b1aa50..c7148129cd 100644 --- a/libs/unimrcp/libs/mrcp/message/src/mrcp_header_accessor.c +++ b/libs/unimrcp/libs/mrcp/message/src/mrcp_header_accessor.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,202 +12,73 @@ * 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. + * + * $Id: mrcp_header_accessor.c 1737 2010-06-15 18:29:17Z achaloyan $ */ -#include #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) +/** Parse header field value */ +MRCP_DECLARE(apt_bool_t) mrcp_header_field_value_parse(mrcp_header_accessor_t *accessor, apt_header_field_t *header_field, apr_pool_t *pool) { - size_t id; + apr_size_t id; if(!accessor->vtable) { return FALSE; } - id = apt_string_table_id_find(accessor->vtable->field_table,accessor->vtable->field_count,&pair->name); + id = apt_string_table_id_find(accessor->vtable->field_table,accessor->vtable->field_count,&header_field->name); if(id >= accessor->vtable->field_count) { return FALSE; } + header_field->id = id; - 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; + if(header_field->value.length) { + if(accessor->vtable->parse_field(accessor,header_field->id,&header_field->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) +/** Generate header field value */ +MRCP_DECLARE(apt_header_field_t*) mrcp_header_field_value_generate(const mrcp_header_accessor_t *accessor, apr_size_t id, apt_bool_t empty_value, apr_pool_t *pool) { + apt_header_field_t *header_field; const apt_str_t *name; - apr_size_t i,j; - char prop; if(!accessor->vtable) { - return FALSE; - } - - for(i=0, j=0; ivtable->field_count && jcounter; 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 NULL; } - - return TRUE; -} - -MRCP_DECLARE(void) mrcp_header_property_add(mrcp_header_accessor_t *accessor, apr_size_t id) -{ - if(!accessor->vtable) { - return; - } - - 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(!accessor->vtable) { - return; + + header_field = apt_header_field_alloc(pool); + name = apt_string_table_str_get(accessor->vtable->field_table,accessor->vtable->field_count,id); + if(name) { + header_field->name = *name; } - 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++; + if(empty_value == FALSE) { + if(accessor->vtable->generate_field(accessor,id,&header_field->value,pool) == FALSE) { + return NULL; } } -} - - -MRCP_DECLARE(void) mrcp_header_property_remove(mrcp_header_accessor_t *accessor, apr_size_t id) -{ - if(!accessor->vtable) { - return; - } - 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; - } + return header_field; } -MRCP_DECLARE(apt_bool_t) mrcp_header_property_check(mrcp_header_accessor_t *accessor, apr_size_t id) +/** Duplicate header field value */ +MRCP_DECLARE(apt_bool_t) mrcp_header_field_value_duplicate(mrcp_header_accessor_t *accessor, const mrcp_header_accessor_t *src_accessor, apr_size_t id, const apt_str_t *value, apr_pool_t *pool) { if(!accessor->vtable) { return FALSE; } - - 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; ivtable->field_count && j < parent->counter; i++) { - if((parent->properties[i] & MRCP_HEADER_FIELD_NAME) == MRCP_HEADER_FIELD_NAME) { - j++; - if((accessor->properties[i] & MRCP_HEADER_FIELD_NAME) != MRCP_HEADER_FIELD_NAME) { - 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); - } - } + + if(value->length) { + if(accessor->vtable->duplicate_field(accessor,src_accessor,id,value,pool) == FALSE) { + return FALSE; } } return TRUE; } - -/** Generate completion-cause */ -MRCP_DECLARE(apt_bool_t) mrcp_completion_cause_generate(const apt_str_table_item_t table[], apr_size_t size, apr_size_t cause, apt_text_stream_t *stream) -{ - int length; - const apt_str_t *name = apt_string_table_str_get(table,size,cause); - if(!name) { - return FALSE; - } - length = sprintf(stream->pos,"%03"APR_SIZE_T_FMT" ",cause); - if(length <= 0) { - return FALSE; - } - stream->pos += length; - - memcpy(stream->pos,name->buf,name->length); - stream->pos += name->length; - return TRUE; -} diff --git a/libs/unimrcp/libs/mrcp/message/src/mrcp_message.c b/libs/unimrcp/libs/mrcp/message/src/mrcp_message.c index 96b52784f5..3a37b2900f 100644 --- a/libs/unimrcp/libs/mrcp/message/src/mrcp_message.c +++ b/libs/unimrcp/libs/mrcp/message/src/mrcp_message.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,214 +12,29 @@ * 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. + * + * $Id: mrcp_message.c 1701 2010-05-22 16:38:10Z achaloyan $ */ #include "mrcp_message.h" #include "mrcp_generic_header.h" #include "mrcp_resource.h" +#include "apt_text_message.h" #include "apt_log.h" -#define MRCP_CHANNEL_ID "Channel-Identifier" -#define MRCP_CHANNEL_ID_LENGTH (sizeof(MRCP_CHANNEL_ID)-1) - -/** 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); -} - -/** 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; -} - -/** Initialize MRCP message */ -static 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->resource = NULL; - message->pool = pool; -} - -/** 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_resource_set_by_id(mrcp_message_t *message, mrcp_resource_t *resource) +/** Associate MRCP resource with message */ +static apt_bool_t mrcp_message_resource_set_by_id(mrcp_message_t *message, const mrcp_resource_t *resource) { if(!resource) { return FALSE; } message->resource = resource; - message->channel_id.resource_name = resource->name; - - mrcp_generic_header_accessor_set(message); - message->header.resource_header_accessor.vtable = - resource->get_resource_header_vtable(message->start_line.version); + mrcp_message_header_data_alloc( + &message->header, + mrcp_generic_header_vtable_get(message->start_line.version), + resource->get_resource_header_vtable(message->start_line.version), + message->pool); /* associate method_name and method_id */ if(message->start_line.message_type == MRCP_MESSAGE_TYPE_REQUEST) { @@ -247,16 +62,17 @@ MRCP_DECLARE(apt_bool_t) mrcp_message_resource_set_by_id(mrcp_message_t *message } /** Associate MRCP resource specific data by resource name */ -MRCP_DECLARE(apt_bool_t) mrcp_message_resource_set(mrcp_message_t *message, mrcp_resource_t *resource) +MRCP_DECLARE(apt_bool_t) mrcp_message_resource_set(mrcp_message_t *message, const mrcp_resource_t *resource) { if(!resource) { return FALSE; } message->resource = resource; - - mrcp_generic_header_accessor_set(message); - message->header.resource_header_accessor.vtable = - resource->get_resource_header_vtable(message->start_line.version); + mrcp_message_header_data_alloc( + &message->header, + mrcp_generic_header_vtable_get(message->start_line.version), + resource->get_resource_header_vtable(message->start_line.version), + message->pool); /* associate method_name and method_id */ if(message->start_line.message_type == MRCP_MESSAGE_TYPE_REQUEST) { @@ -281,16 +97,21 @@ MRCP_DECLARE(apt_bool_t) mrcp_message_resource_set(mrcp_message_t *message, mrcp return TRUE; } -/** Create MRCP message */ +/** Create an 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); + 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->resource = NULL; + message->pool = pool; return message; } -/** Create MRCP request message */ -MRCP_DECLARE(mrcp_message_t*) mrcp_request_create(mrcp_resource_t *resource, mrcp_version_e version, mrcp_method_id method_id, apr_pool_t *pool) +/** Create an MRCP request message */ +MRCP_DECLARE(mrcp_message_t*) mrcp_request_create(const mrcp_resource_t *resource, mrcp_version_e version, 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; @@ -300,7 +121,7 @@ MRCP_DECLARE(mrcp_message_t*) mrcp_request_create(mrcp_resource_t *resource, mrc return request_message; } -/** Create MRCP response message */ +/** Create an 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); @@ -312,12 +133,13 @@ MRCP_DECLARE(mrcp_message_t*) mrcp_response_create(const mrcp_message_t *request response_message->start_line.request_id = request_message->start_line.request_id; response_message->start_line.version = request_message->start_line.version; response_message->start_line.method_id = request_message->start_line.method_id; + response_message->start_line.method_name = request_message->start_line.method_name; mrcp_message_resource_set_by_id(response_message,request_message->resource); } return response_message; } -/** Create MRCP event message */ +/** Create an 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); @@ -357,3 +179,81 @@ MRCP_DECLARE(apt_bool_t) mrcp_message_validate(mrcp_message_t *message) return TRUE; } + +/** Add MRCP generic header field by specified property (numeric identifier) */ +MRCP_DECLARE(apt_bool_t) mrcp_generic_header_property_add(mrcp_message_t *message, apr_size_t id) +{ + apt_header_field_t *header_field = mrcp_header_field_value_generate( + &message->header.generic_header_accessor, + id, + FALSE, + message->pool); + if(!header_field) { + return FALSE; + } + header_field->id = id; + return apt_header_section_field_add(&message->header.header_section,header_field); +} + +/** Add only the name of MRCP generic header field specified by property (numeric identifier) */ +MRCP_DECLARE(apt_bool_t) mrcp_generic_header_name_property_add(mrcp_message_t *message, apr_size_t id) +{ + apt_header_field_t *header_field = mrcp_header_field_value_generate( + &message->header.generic_header_accessor, + id, + TRUE, + message->pool); + if(!header_field) { + return FALSE; + } + header_field->id = id; + return apt_header_section_field_add(&message->header.header_section,header_field); +} + +/** Add MRCP resource header field by specified property (numeric identifier) */ +MRCP_DECLARE(apt_bool_t) mrcp_resource_header_property_add(mrcp_message_t *message, apr_size_t id) +{ + apt_header_field_t *header_field = mrcp_header_field_value_generate( + &message->header.resource_header_accessor, + id, + FALSE, + message->pool); + if(!header_field) { + return FALSE; + } + header_field->id = id + GENERIC_HEADER_COUNT; + return apt_header_section_field_add(&message->header.header_section,header_field); +} + +/** Add only the name of MRCP resource header field specified by property (numeric identifier) */ +MRCP_DECLARE(apt_bool_t) mrcp_resource_header_name_property_add(mrcp_message_t *message, apr_size_t id) +{ + apt_header_field_t *header_field = mrcp_header_field_value_generate( + &message->header.resource_header_accessor, + id, + TRUE, + message->pool); + if(!header_field) { + return FALSE; + } + header_field->id = id + GENERIC_HEADER_COUNT; + return apt_header_section_field_add(&message->header.header_section,header_field); +} + +/** Get the next MRCP header field */ +MRCP_DECLARE(apt_header_field_t*) mrcp_message_next_header_field_get(const mrcp_message_t *message, apt_header_field_t *header_field) +{ + const apt_header_section_t *header_section = &message->header.header_section; + if(header_field) { + apt_header_field_t *next = APR_RING_NEXT(header_field,link); + if(next == APR_RING_SENTINEL(&header_section->ring,apt_header_field_t,link)) { + return NULL; + } + return next; + } + + if(APR_RING_EMPTY(&header_section->ring,apt_header_field_t,link)) { + return NULL; + } + return APR_RING_FIRST(&header_section->ring); +} diff --git a/libs/unimrcp/libs/mrcp/message/src/mrcp_start_line.c b/libs/unimrcp/libs/mrcp/message/src/mrcp_start_line.c index 2a406663fa..f2a36b0351 100644 --- a/libs/unimrcp/libs/mrcp/message/src/mrcp_start_line.c +++ b/libs/unimrcp/libs/mrcp/message/src/mrcp_start_line.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_start_line.c 1671 2010-04-28 19:50:29Z achaloyan $ */ #include @@ -65,10 +67,20 @@ static mrcp_version_e mrcp_version_parse(const apt_str_t *field) /** Generate MRCP version */ static apt_bool_t mrcp_version_generate(mrcp_version_e version, apt_text_stream_t *stream) { + if(stream->pos + MRCP_NAME_LENGTH + 1 >= stream->end) { + return FALSE; + } 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); + + if(apt_text_size_value_insert(stream,version) == FALSE) { + return FALSE; + } + + if(stream->pos + 2 >= stream->end) { + return FALSE; + } *stream->pos++ = MRCP_VERSION_MAJOR_MINOR_SEPARATOR; *stream->pos++ = '0'; return TRUE; @@ -102,7 +114,7 @@ static APR_INLINE mrcp_status_code_e mrcp_status_code_parse(const apt_str_t *fie /** 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); + return apt_text_size_value_insert(stream,status_code); } @@ -318,18 +330,14 @@ 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) +MRCP_DECLARE(apt_bool_t) mrcp_start_line_parse(mrcp_start_line_t *start_line, apt_str_t *str, 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; - } - - apt_text_stream_reset(&line); + apt_text_stream_init(&line,str->buf,str->length); 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; @@ -383,11 +391,11 @@ MRCP_DECLARE(apt_bool_t) mrcp_start_line_generate(mrcp_start_line_t *start_line, status = mrcp_v2_start_line_generate(start_line,text_stream); } - if(status == TRUE) { - apt_text_eol_insert(text_stream); + if(status == FALSE) { + return FALSE; } - - return status; + + return apt_text_eol_insert(text_stream); } /** Finalize MRCP start-line generation */ diff --git a/libs/unimrcp/libs/mrcp/mrcp.2008.vcproj b/libs/unimrcp/libs/mrcp/mrcp.2008.vcproj deleted file mode 100644 index ae656d2749..0000000000 --- a/libs/unimrcp/libs/mrcp/mrcp.2008.vcproj +++ /dev/null @@ -1,422 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/unimrcp/libs/mrcp/mrcp.2010.vcxproj b/libs/unimrcp/libs/mrcp/mrcp.2010.vcxproj deleted file mode 100644 index e525a96146..0000000000 --- a/libs/unimrcp/libs/mrcp/mrcp.2010.vcxproj +++ /dev/null @@ -1,148 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - mrcp - {1C320193-46A6-4B34-9C56-8AB584FC1B56} - mrcp - Win32Proj - - - - StaticLibrary - Unicode - true - - - StaticLibrary - Unicode - - - StaticLibrary - Unicode - true - - - StaticLibrary - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - - - - %(AdditionalIncludeDirectories) - APT_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;%(PreprocessorDefinitions) - - - - - X64 - - - %(AdditionalIncludeDirectories) - APT_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;%(PreprocessorDefinitions) - ProgramDatabase - - - - - %(AdditionalIncludeDirectories) - APT_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;%(PreprocessorDefinitions) - - - - - X64 - - - %(AdditionalIncludeDirectories) - APT_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/libs/unimrcp/libs/mrcp/mrcp.2010.vcxproj.filters b/libs/unimrcp/libs/mrcp/mrcp.2010.vcxproj.filters deleted file mode 100644 index 119921b34b..0000000000 --- a/libs/unimrcp/libs/mrcp/mrcp.2010.vcxproj.filters +++ /dev/null @@ -1,133 +0,0 @@ - - - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {19ad4bde-c4f4-4937-9073-ca2780341d76} - - - {8ec996ac-8a0a-4bf0-9b3c-535616585109} - h;hpp;hxx;hm;inl;inc;xsd - - - {5ba77874-7c17-4748-b5ba-b07b7f0a2169} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {f30fd049-a10d-4aea-b4bb-3eb674690fdd} - - - {7e71717b-6f22-4c59-ba50-7b5a15516b2f} - h;hpp;hxx;hm;inl;inc;xsd - - - {c66dbb84-ce9d-4408-b54d-4d0ec51069fb} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {f20cfd62-4bb9-42de-bf1c-d578c8cd1a18} - - - {039a4834-7ddb-40e7-9177-55d11ef1e733} - h;hpp;hxx;hm;inl;inc;xsd - - - {dc087d31-8ecf-473c-baa1-f3091e16014d} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - - - include - - - include - - - message\include - - - message\include - - - message\include - - - message\include - - - control\include - - - control\include - - - control\include - - - control\include - - - resources\include - - - resources\include - - - resources\include - - - resources\include - - - resources\include - - - resources\include - - - - - message\src - - - message\src - - - message\src - - - message\src - - - control\src - - - control\src - - - control\src - - - resources\src - - - resources\src - - - resources\src - - - resources\src - - - resources\src - - - resources\src - - - \ No newline at end of file diff --git a/libs/unimrcp/libs/mrcp/mrcp.vcproj b/libs/unimrcp/libs/mrcp/mrcp.vcproj index de0721096c..dc421663c7 100644 --- a/libs/unimrcp/libs/mrcp/mrcp.vcproj +++ b/libs/unimrcp/libs/mrcp/mrcp.vcproj @@ -264,6 +264,10 @@ RelativePath=".\message\include\mrcp_generic_header.h" > + + @@ -285,6 +289,10 @@ RelativePath=".\message\src\mrcp_generic_header.c" > + + @@ -372,6 +380,14 @@ RelativePath=".\resources\include\mrcp_synth_resource.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 index 4b2192b399..40556d5790 100644 --- a/libs/unimrcp/libs/mrcp/resources/include/mrcp_recog_header.h +++ b/libs/unimrcp/libs/mrcp/resources/include/mrcp_recog_header.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_recog_header.h 1736 2010-06-14 20:16:22Z achaloyan $ */ -#ifndef __MRCP_RECOG_HEADER_H__ -#define __MRCP_RECOG_HEADER_H__ +#ifndef MRCP_RECOG_HEADER_H +#define MRCP_RECOG_HEADER_H /** * @file mrcp_recog_header.h @@ -27,7 +29,7 @@ APT_BEGIN_EXTERN_C -/** MRCP recognizer headers */ +/** MRCP recognizer header fields */ typedef enum { RECOGNIZER_HEADER_CONFIDENCE_THRESHOLD, RECOGNIZER_HEADER_SENSITIVITY_LEVEL, @@ -50,7 +52,7 @@ typedef enum { RECOGNIZER_HEADER_NEW_AUDIO_CHANNEL, RECOGNIZER_HEADER_SPEECH_LANGUAGE, - /** Additional headers for MRCP v2 */ + /** Additional header fields for MRCP v2 */ RECOGNIZER_HEADER_INPUT_TYPE, RECOGNIZER_HEADER_INPUT_WAVEFORM_URI, RECOGNIZER_HEADER_COMPLETION_REASON, @@ -64,6 +66,18 @@ typedef enum { RECOGNIZER_HEADER_DTMF_BUFFER_TIME, RECOGNIZER_HEADER_CLEAR_DTMF_BUFFER, RECOGNIZER_HEADER_EARLY_NO_MATCH, + RECOGNIZER_HEADER_NUM_MIN_CONSISTENT_PRONUNCIATIONS, + RECOGNIZER_HEADER_CONSISTENCY_THRESHOLD, + RECOGNIZER_HEADER_CLASH_THRESHOLD, + RECOGNIZER_HEADER_PERSONAL_GRAMMAR_URI, + RECOGNIZER_HEADER_ENROLL_UTTERANCE, + RECOGNIZER_HEADER_PHRASE_ID, + RECOGNIZER_HEADER_PHRASE_NL, + RECOGNIZER_HEADER_WEIGHT, + RECOGNIZER_HEADER_SAVE_BEST_WAVEFORM, + RECOGNIZER_HEADER_NEW_PHRASE_ID, + RECOGNIZER_HEADER_CONFUSABLE_PHRASES_URI, + RECOGNIZER_HEADER_ABORT_PHRASE_ENROLLMENT, RECOGNIZER_HEADER_COUNT } mrcp_recognizer_header_id; @@ -160,7 +174,7 @@ struct mrcp_recog_header_t { a session or request, if it is not specified within the data */ apt_str_t speech_language; - /** Additional headers for MRCP v2 */ + /** Additional header fields 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 @@ -169,10 +183,10 @@ struct mrcp_recog_header_t { /** 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 + /** 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 + /** 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; @@ -202,6 +216,49 @@ struct mrcp_recog_header_t { 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; + /** MAY be specified in a START-PHRASE-ENROLLMENT, "SET-PARAMS", or + "GET-PARAMS" method and is used to specify the minimum number of + consistent pronunciations that must be obtained to voice enroll a new phrase */ + apr_size_t num_min_consistent_pronunciations; + /** MAY be sent as part of the START-PHRASE-ENROLLMENT,"SET-PARAMS", or + "GET-PARAMS" method and is used during voice-enrollment to specify how similar + to a previously enrolled pronunciation of the same phrase an utterance needs + to be in order to be considered "consistent" */ + float consistency_threshold; + /** MAY be sent as part of the START-PHRASE-ENROLLMENT, SET-PARAMS, or + "GET-PARAMS" method and is used during voice-enrollment to specify + how similar the pronunciations of two different phrases can be + before they are considered to be clashing */ + float clash_threshold; + /** Specifies the speaker-trained grammar to be used or + referenced during enrollment operations */ + apt_str_t personal_grammar_uri; + /** MAY be specified in the RECOGNIZE method. If this header + is set to "true" and an Enrollment is active, the RECOGNIZE command + MUST add the collected utterance to the personal grammar that is + being enrolled */ + apt_bool_t enroll_utterance; + /** Identifies a phrase in an existing personal grammar for which + enrollment is desired. It is also returned to the client in the + RECOGNIZE complete event */ + apt_str_t phrase_id; + /** Specifies the interpreted text to be returned when the + phrase is recognized */ + apt_str_t phrase_nl; + /** Represents the occurrence likelihood of a phrase in an enrolled grammar */ + float weight; + /** Allows the client to request the recognizer resource to + save the audio stream for the best repetition of the phrase that was + used during the enrollment session */ + apt_bool_t save_best_waveform; + /** Replaces the id used to identify the phrase in a personal grammar */ + apt_str_t new_phrase_id; + /** Specifies a grammar that defines invalid phrases for enrollment */ + apt_str_t confusable_phrases_uri; + /** Can optionally be specified in the END-PHRASE-ENROLLMENT + method to abort the phrase enrollment, rather than committing the + phrase to the personal grammar */ + apt_bool_t abort_phrase_enrollment; }; @@ -213,4 +270,4 @@ MRCP_DECLARE(const apt_str_t*) mrcp_recog_completion_cause_get(mrcp_recog_comple APT_END_EXTERN_C -#endif /*__MRCP_RECOG_HEADER_H__*/ +#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 index 0131e9caed..64eddd9290 100644 --- a/libs/unimrcp/libs/mrcp/resources/include/mrcp_recog_resource.h +++ b/libs/unimrcp/libs/mrcp/resources/include/mrcp_recog_resource.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_recog_resource.h 1781 2010-09-01 07:33:00Z achaloyan $ */ -#ifndef __MRCP_RECOG_RESOURCE_H__ -#define __MRCP_RECOG_RESOURCE_H__ +#ifndef MRCP_RECOG_RESOURCE_H +#define MRCP_RECOG_RESOURCE_H /** * @file mrcp_recog_resource.h @@ -32,9 +34,15 @@ typedef enum { RECOGNIZER_GET_PARAMS, RECOGNIZER_DEFINE_GRAMMAR, RECOGNIZER_RECOGNIZE, + RECOGNIZER_INTERPRET, RECOGNIZER_GET_RESULT, RECOGNIZER_START_INPUT_TIMERS, RECOGNIZER_STOP, + RECOGNIZER_START_PHRASE_ENROLLMENT, + RECOGNIZER_ENROLLMENT_ROLLBACK, + RECOGNIZER_END_PHRASE_ENROLLMENT, + RECOGNIZER_MODIFY_PHRASE, + RECOGNIZER_DELETE_PHRASE, RECOGNIZER_METHOD_COUNT } mrcp_recognizer_method_id; @@ -43,6 +51,7 @@ typedef enum { typedef enum { RECOGNIZER_START_OF_INPUT, RECOGNIZER_RECOGNITION_COMPLETE, + RECOGNIZER_INTERPRETATION_COMPLETE, RECOGNIZER_EVENT_COUNT } mrcp_recognizer_event_id; @@ -52,4 +61,4 @@ MRCP_DECLARE(mrcp_resource_t*) mrcp_recog_resource_create(apr_pool_t *pool); APT_END_EXTERN_C -#endif /*__MRCP_RECOG_RESOURCE_H__*/ +#endif /* MRCP_RECOG_RESOURCE_H */ diff --git a/libs/unimrcp/libs/mrcp/resources/include/mrcp_recorder_header.h b/libs/unimrcp/libs/mrcp/resources/include/mrcp_recorder_header.h index af1772337a..2fadba5ea8 100644 --- a/libs/unimrcp/libs/mrcp/resources/include/mrcp_recorder_header.h +++ b/libs/unimrcp/libs/mrcp/resources/include/mrcp_recorder_header.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_recorder_header.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MRCP_RECORDER_HEADER_H__ -#define __MRCP_RECORDER_HEADER_H__ +#ifndef MRCP_RECORDER_HEADER_H +#define MRCP_RECORDER_HEADER_H /** * @file mrcp_recorder_header.h @@ -133,4 +135,4 @@ MRCP_DECLARE(const apt_str_t*) mrcp_recorder_completion_cause_get( APT_END_EXTERN_C -#endif /*__MRCP_RECORDER_HEADER_H__*/ +#endif /* MRCP_RECORDER_HEADER_H */ diff --git a/libs/unimrcp/libs/mrcp/resources/include/mrcp_recorder_resource.h b/libs/unimrcp/libs/mrcp/resources/include/mrcp_recorder_resource.h index b9afa34999..090992ba62 100644 --- a/libs/unimrcp/libs/mrcp/resources/include/mrcp_recorder_resource.h +++ b/libs/unimrcp/libs/mrcp/resources/include/mrcp_recorder_resource.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_recorder_resource.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MRCP_RECORDER_RESOURCE_H__ -#define __MRCP_RECORDER_RESOURCE_H__ +#ifndef MRCP_RECORDER_RESOURCE_H +#define MRCP_RECORDER_RESOURCE_H /** * @file mrcp_recorder_resource.h @@ -50,4 +52,4 @@ MRCP_DECLARE(mrcp_resource_t*) mrcp_recorder_resource_create(apr_pool_t *pool); APT_END_EXTERN_C -#endif /*__MRCP_RECORDER_RESOURCE_H__*/ +#endif /* MRCP_RECORDER_RESOURCE_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 index 359af6bd59..c711414471 100644 --- a/libs/unimrcp/libs/mrcp/resources/include/mrcp_synth_header.h +++ b/libs/unimrcp/libs/mrcp/resources/include/mrcp_synth_header.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_synth_header.h 1643 2010-04-08 13:40:09Z achaloyan $ */ -#ifndef __MRCP_SYNTH_HEADER_H__ -#define __MRCP_SYNTH_HEADER_H__ +#ifndef MRCP_SYNTH_HEADER_H +#define MRCP_SYNTH_HEADER_H /** * @file mrcp_synth_header.h @@ -27,7 +29,7 @@ APT_BEGIN_EXTERN_C -/** MRCP synthesizer headers */ +/** MRCP synthesizer header fields */ typedef enum { SYNTHESIZER_HEADER_JUMP_SIZE, SYNTHESIZER_HEADER_KILL_ON_BARGE_IN, @@ -248,9 +250,9 @@ struct mrcp_synth_header_t { /** 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 */ + /** This set of header fields defines the voice of the speaker */ mrcp_voice_param_t voice_param; - /** This set of headers defines the prosody of the speech */ + /** This set of header fields defines the prosody of the speech */ mrcp_prosody_param_t prosody_param; /** Contains timestamp information in a "timestamp" field */ apt_str_t speech_marker; @@ -285,7 +287,7 @@ struct mrcp_synth_header_t { 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 + /** Used to specify a list of active Lexicon URIs and the search order among the active lexicons */ apt_str_t lexicon_search_order; }; @@ -299,4 +301,4 @@ MRCP_DECLARE(const apt_str_t*) mrcp_synth_completion_cause_get(mrcp_synth_comple APT_END_EXTERN_C -#endif /*__MRCP_SYNTH_HEADER_H__*/ +#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 index d63fbdbfe3..256be1ac3c 100644 --- a/libs/unimrcp/libs/mrcp/resources/include/mrcp_synth_resource.h +++ b/libs/unimrcp/libs/mrcp/resources/include/mrcp_synth_resource.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_synth_resource.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MRCP_SYNTH_RESOURCE_H__ -#define __MRCP_SYNTH_RESOURCE_H__ +#ifndef MRCP_SYNTH_RESOURCE_H +#define MRCP_SYNTH_RESOURCE_H /** * @file mrcp_synth_resource.h @@ -55,4 +57,4 @@ MRCP_DECLARE(mrcp_resource_t*) mrcp_synth_resource_create(apr_pool_t *pool); APT_END_EXTERN_C -#endif /*__MRCP_SYNTH_RESOURCE_H__*/ +#endif /* MRCP_SYNTH_RESOURCE_H */ diff --git a/libs/unimrcp/libs/mrcp/resources/include/mrcp_verifier_header.h b/libs/unimrcp/libs/mrcp/resources/include/mrcp_verifier_header.h new file mode 100644 index 0000000000..cac29e01d1 --- /dev/null +++ b/libs/unimrcp/libs/mrcp/resources/include/mrcp_verifier_header.h @@ -0,0 +1,162 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: + */ + +#ifndef MRCP_VERIFIER_HEADER_H +#define MRCP_VERIFIER_HEADER_H + +/** + * @file mrcp_verifier_header.h + * @brief MRCP Verifier Header + */ + +#include "mrcp_types.h" +#include "mrcp_header_accessor.h" + +APT_BEGIN_EXTERN_C + +/** MRCP verifier header fields */ +typedef enum { + VERIFIER_HEADER_REPOSITORY_URI, + VERIFIER_HEADER_VOICEPRINT_IDENTIFIER, + VERIFIER_HEADER_VERIFICATION_MODE, + VERIFIER_HEADER_ADAPT_MODEL, + VERIFIER_HEADER_ABORT_MODEL, + VERIFIER_HEADER_MIN_VERIFICATION_SCORE, + VERIFIER_HEADER_NUM_MIN_VERIFICATION_PHRASES, + VERIFIER_HEADER_NUM_MAX_VERIFICATION_PHRASES, + VERIFIER_HEADER_NO_INPUT_TIMEOUT, + VERIFIER_HEADER_SAVE_WAVEFORM, + VERIFIER_HEADER_MEDIA_TYPE, + VERIFIER_HEADER_WAVEFORM_URI, + VERIFIER_HEADER_VOICEPRINT_EXISTS, + VERIFIER_HEADER_VER_BUFFER_UTTERANCE, + VERIFIER_HEADER_INPUT_WAVEFORM_URI, + VERIFIER_HEADER_COMPLETION_CAUSE, + VERIFIER_HEADER_COMPLETION_REASON, + VERIFIER_HEADER_SPEECH_COMPLETE_TIMEOUT, + VERIFIER_HEADER_NEW_AUDIO_CHANNEL, + VERIFIER_HEADER_ABORT_VERIFICATION, + VERIFIER_HEADER_START_INPUT_TIMERS, + + VERIFIER_HEADER_COUNT +} mrcp_verifier_header_id; + + +/** MRCP verifier completion-cause */ +typedef enum { + VERIFIER_COMPLETION_CAUSE_SUCCESS = 0, + VERIFIER_COMPLETION_CAUSE_ERROR = 1, + VERIFIER_COMPLETION_CAUSE_NO_INPUT_TIMEOUT = 2, + VERIFIER_COMPLETION_CAUSE_TOO_MUCH_SPEECH_TIMEOUT = 3, + VERIFIER_COMPLETION_CAUSE_SPEECH_TOO_EARLY = 4, + VERIFIER_COMPLETION_CAUSE_BUFFER_EMPTY = 5, + VERIFIER_COMPLETION_CAUSE_OUT_OF_SEQUENCE = 6, + VERIFIER_COMPLETION_CAUSE_REPOSITORY_URI_FAILURE = 7, + VERIFIER_COMPLETION_CAUSE_REPOSITORY_URI_MISSING = 8, + VERIFIER_COMPLETION_CAUSE_VOICEPRINT_ID_MISSING = 9, + VERIFIER_COMPLETION_CAUSE_VOICEPRINT_ID_NOT_EXIST = 10, + VERIFIER_COMPLETION_CAUSE_SPEECH_NOT_USABLE = 11, + + VERIFIER_COMPLETION_CAUSE_COUNT = 12, + VERIFIER_COMPLETION_CAUSE_UNKNOWN = VERIFIER_COMPLETION_CAUSE_COUNT +} mrcp_verifier_completion_cause_e; + + + +/** MRCP verifier-header declaration */ +typedef struct mrcp_verifier_header_t mrcp_verifier_header_t; + +/** MRCP verifier-header */ +struct mrcp_verifier_header_t { + /** Specifies the voiceprint repository to be used or referenced during + speaker verification or identification operations */ + apt_str_t repository_uri; + /** Specifies the claimed identity for verification applications */ + apt_str_t voiceprint_identifier; + /** Specifies the mode of the verification resource */ + apt_str_t verification_mode; + /** Indicates the desired behavior of the verification resource + after a successful verification operation */ + apt_bool_t adapt_model; + /** Indicates the desired behavior of the verification resource + upon session termination */ + apt_bool_t abort_model; + /** Determines the minimum verification score for which a verification + decision of "accepted" may be declared by the server */ + float min_verification_score; + /** Specifies the minimum number of valid utterances + before a positive decision is given for verification */ + apr_size_t num_min_verification_phrases; + /** Specifies the number of valid utterances required + before a decision is forced for verification */ + apr_size_t num_max_verification_phrases; + /** Sets the length of time from the start of the verification timers + (see START-INPUT-TIMERS) until the declaration of a no-input event + in the VERIFICATION-COMPLETE server event message */ + apr_size_t no_input_timeout; + /** Allows the client to request the verification resource to save + the audio stream that was used for verification/identification */ + apt_bool_t save_waveform; + /** Tells the server resource the Media Type of the captured audio or video + such as the one captured and returned by the Waveform-URI header field */ + apt_str_t media_type; + /** If the Save-Waveform header field is set to true, the verification resource + MUST attempt to record the incoming audio stream of the verification into + a file and provide a URI for the client to access it */ + apt_str_t waveform_uri; + /** Shows the status of the voiceprint specified + in the QUERY-VOICEPRINT method */ + apt_bool_t voiceprint_exists; + /** Indicates that this utterance could be + later considered for Speaker Verification */ + apt_bool_t ver_buffer_utterance; + /** Specifies stored audio content that the client requests the server + to fetch and process according to the current verification mode, + either to train the voiceprint or verify a claimed identity */ + apt_str_t input_waveform_uri; + /** Indicates the cause of VERIFY or VERIFY-FROM-BUFFER method completion */ + mrcp_verifier_completion_cause_e completion_cause; + /** MAY be specified in a VERIFICATION-COMPLETE event + coming from the verifier resource to the client */ + apt_str_t completion_reason; + /** Specifies the length of silence required following user + speech before the speech verifier finalizes a result */ + apr_size_t speech_complete_timeout; + /** MAY be specified in a VERIFIER 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; + /** MUST be sent in a STOP request to indicate + whether or not to abort a VERIFY method in progress */ + apt_bool_t abort_verification; + /** MAY be sent as part of a VERIFY request. A value of false + tells the verification resource to start the VERIFY operation, + but not to start the no-input timer yet */ + apt_bool_t start_input_timers; +}; + + +/** Get verifier header vtable */ +const mrcp_header_vtable_t* mrcp_verifier_header_vtable_get(mrcp_version_e version); + +/** Get verifier completion cause string */ +MRCP_DECLARE(const apt_str_t*) mrcp_verifier_completion_cause_get(mrcp_verifier_completion_cause_e completion_cause, mrcp_version_e version); + +APT_END_EXTERN_C + +#endif /* MRCP_VERIFIER_HEADER_H */ diff --git a/libs/unimrcp/libs/mrcp/resources/include/mrcp_verifier_resource.h b/libs/unimrcp/libs/mrcp/resources/include/mrcp_verifier_resource.h new file mode 100644 index 0000000000..5fcfaef2ce --- /dev/null +++ b/libs/unimrcp/libs/mrcp/resources/include/mrcp_verifier_resource.h @@ -0,0 +1,63 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: + */ + +#ifndef MRCP_VERIFIER_RESOURCE_H +#define MRCP_VERIFIER_RESOURCE_H + +/** + * @file mrcp_verifier_resource.h + * @brief MRCP Verifier Resource + */ + +#include "mrcp_types.h" + +APT_BEGIN_EXTERN_C + +/** MRCP verifier methods */ +typedef enum { + VERIFIER_SET_PARAMS, + VERIFIER_GET_PARAMS, + VERIFIER_START_SESSION, + VERIFIER_END_SESSION, + VERIFIER_QUERY_VOICEPRINT, + VERIFIER_DELETE_VOICEPRINT, + VERIFIER_VERIFY, + VERIFIER_VERIFY_FROM_BUFFER, + VERIFIER_VERIFY_ROLLBACK, + VERIFIER_STOP, + VERIFIER_CLEAR_BUFFER, + VERIFIER_START_INPUT_TIMERS, + VERIFIER_GET_INTERMIDIATE_RESULT, + + VERIFIER_METHOD_COUNT +} mrcp_verifier_method_id; + +/** MRCP verifier events */ +typedef enum { + VERIFIER_START_OF_INPUT, + VERIFIER_VERIFICATION_COMPLETE, + + VERIFIER_EVENT_COUNT +} mrcp_verifier_event_id; + +/** Create MRCP verifier resource */ +MRCP_DECLARE(mrcp_resource_t*) mrcp_verifier_resource_create(apr_pool_t *pool); + +APT_END_EXTERN_C + +#endif /* MRCP_VERIFIER_RESOURCE_H */ diff --git a/libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_header.c b/libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_header.c index 4bfbcbe16e..81ae07507d 100644 --- a/libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_header.c +++ b/libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_header.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,82 +12,108 @@ * 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. + * + * $Id: mrcp_recog_header.c 1736 2010-06-14 20:16:22Z achaloyan $ */ #include "mrcp_recog_header.h" -/** String table of MRCPv1 recognizer headers (mrcp_recog_header_id) */ +/** String table of MRCPv1 recognizer header fields (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} + {{"Confidence-Threshold", 20},16}, + {{"Sensitivity-Level", 17},14}, + {{"Speed-Vs-Accuracy", 17},4}, + {{"N-Best-List-Length", 18},1}, + {{"No-Input-Timeout", 16},2}, + {{"Recognition-Timeout", 19},19}, + {{"Waveform-Url", 12},4}, + {{"Completion-Cause", 16},16}, + {{"Recognizer-Context-Block", 24},16}, + {{"Recognizer-Start-Timers", 23},18}, + {{"Speech-Complete-Timeout", 23},7}, + {{"Speech-Incomplete-Timeout", 25},12}, + {{"DTMF-Interdigit-Timeout", 23},10}, + {{"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},17}, + {{"Speech-Language", 15},8}, + {{"Input-Type", 10},10}, + {{"Input-Waveform-Uri", 18},6}, + {{"Completion-Reason", 17},17}, + {{"Media-Type", 10},0}, + {{"Ver-Buffer-Utterance", 20},0}, + {{"Recognition-Mode", 16},16}, + {{"Cancel-If-Queue", 15},3}, + {{"Hotword-Max-Duration", 20},10}, + {{"Hotword-Min-Duration", 20},20}, + {{"Interpret-Text", 14},12}, + {{"DTMF-Buffer-Time", 16},16}, + {{"Clear-DTMF-Buffer", 17},11}, + {{"Early-No-Match", 14},4}, + {{"Num-Min-Consistent-Pronunciations",33},1}, + {{"Consistency-Threshold", 21},16}, + {{"Clash-Threshold", 15},2}, + {{"Personal-Grammar-URI", 20},9}, + {{"Enroll-Utterance", 16},10}, + {{"Phrase-ID", 9},8}, + {{"Phrase-NL", 9},9}, + {{"Weight", 6},3}, + {{"Save-Best-Waveform", 18},10}, + {{"New-Phrase-ID", 13},4}, + {{"Confusable-Phrases-URI", 22},4}, + {{"Abort-Phrase-Enrollment", 23},0} }; -/** String table of MRCPv2 recognizer headers (mrcp_recog_header_id) */ +/** String table of MRCPv2 recognizer header fields (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} + {{"Confidence-Threshold", 20},16}, + {{"Sensitivity-Level", 17},14}, + {{"Speed-Vs-Accuracy", 17},4}, + {{"N-Best-List-Length", 18},1}, + {{"No-Input-Timeout", 16},2}, + {{"Recognition-Timeout", 19},19}, + {{"Waveform-Uri", 12},4}, + {{"Completion-Cause", 16},16}, + {{"Recognizer-Context-Block", 24},7}, + {{"Start-Input-Timers", 18},18}, + {{"Speech-Complete-Timeout", 23},7}, + {{"Speech-Incomplete-Timeout", 25},12}, + {{"DTMF-Interdigit-Timeout", 23},10}, + {{"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},17}, + {{"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},16}, + {{"Cancel-If-Queue", 15},3}, + {{"Hotword-Max-Duration", 20},10}, + {{"Hotword-Min-Duration", 20},20}, + {{"Interpret-Text", 14},12}, + {{"DTMF-Buffer-Time", 16},16}, + {{"Clear-DTMF-Buffer", 17},11}, + {{"Early-No-Match", 14},4}, + {{"Num-Min-Consistent-Pronunciations",33},1}, + {{"Consistency-Threshold", 21},16}, + {{"Clash-Threshold", 15},15}, + {{"Personal-Grammar-URI", 20},9}, + {{"Enroll-Utterance", 16},10}, + {{"Phrase-ID", 9},8}, + {{"Phrase-NL", 9},9}, + {{"Weight", 6},3}, + {{"Save-Best-Waveform", 18},10}, + {{"New-Phrase-ID", 13},4}, + {{"Confusable-Phrases-URI", 22},4}, + {{"Abort-Phrase-Enrollment", 23},0} }; /** String table of MRCPv1 recognizer completion-cause fields (mrcp_recog_completion_cause_e) */ @@ -156,7 +182,7 @@ static void mrcp_recog_header_init(mrcp_recog_header_t *recog_header) recog_header->save_waveform = FALSE; recog_header->new_audio_channel = FALSE; apt_string_reset(&recog_header->speech_language); - /* initializes additionnal MRCPV2 recog headers */ + /* initializes additionnal MRCPV2 recog header fields */ apt_string_reset(&recog_header->input_type); apt_string_reset(&recog_header->input_waveform_uri); apt_string_reset(&recog_header->completion_reason); @@ -170,6 +196,18 @@ static void mrcp_recog_header_init(mrcp_recog_header_t *recog_header) recog_header->dtmf_buffer_time = 0; recog_header->clear_dtmf_buffer = FALSE; recog_header->early_no_match = FALSE; + recog_header->num_min_consistent_pronunciations = 0; + recog_header->consistency_threshold = 0.0; + recog_header->clash_threshold = 0.0; + apt_string_reset(&recog_header->personal_grammar_uri); + recog_header->enroll_utterance = FALSE; + apt_string_reset(&recog_header->phrase_id); + apt_string_reset(&recog_header->phrase_nl); + recog_header->weight = 0.0; + recog_header->save_best_waveform = FALSE; + apt_string_reset(&recog_header->new_phrase_id); + apt_string_reset(&recog_header->confusable_phrases_uri); + recog_header->abort_phrase_enrollment = FALSE; } /** Allocate MRCP recognizer header */ @@ -196,13 +234,13 @@ static apt_bool_t mrcp_recog_header_parse(mrcp_recog_header_t *recog_header, apr recog_header->recognition_timeout = apt_size_value_parse(value); break; case RECOGNIZER_HEADER_WAVEFORM_URI: - apt_string_copy(&recog_header->waveform_uri,value,pool); + recog_header->waveform_uri = *value; 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); + recog_header->recognizer_context_block = *value; break; case RECOGNIZER_HEADER_START_INPUT_TIMERS: apt_boolean_value_parse(value,&recog_header->start_input_timers); @@ -223,10 +261,10 @@ static apt_bool_t mrcp_recog_header_parse(mrcp_recog_header_t *recog_header, apr recog_header->dtmf_term_char = *value->buf; break; case RECOGNIZER_HEADER_FAILED_URI: - apt_string_copy(&recog_header->failed_uri,value,pool); + recog_header->failed_uri = *value; break; case RECOGNIZER_HEADER_FAILED_URI_CAUSE: - apt_string_copy(&recog_header->failed_uri_cause,value,pool); + recog_header->failed_uri_cause = *value; break; case RECOGNIZER_HEADER_SAVE_WAVEFORM: apt_boolean_value_parse(value,&recog_header->save_waveform); @@ -235,25 +273,25 @@ static apt_bool_t mrcp_recog_header_parse(mrcp_recog_header_t *recog_header, apr 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); + recog_header->speech_language = *value; break; case RECOGNIZER_HEADER_INPUT_TYPE: - apt_string_copy(&recog_header->input_type,value,pool); + recog_header->input_type = *value; break; case RECOGNIZER_HEADER_MEDIA_TYPE: - apt_string_copy(&recog_header->media_type,value,pool); + recog_header->media_type = *value; break; case RECOGNIZER_HEADER_INPUT_WAVEFORM_URI: - apt_string_copy(&recog_header->input_waveform_uri,value,pool); + recog_header->input_waveform_uri = *value; break; case RECOGNIZER_HEADER_COMPLETION_REASON: - apt_string_copy(&recog_header->completion_reason,value,pool); + recog_header->completion_reason = *value; 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); + recog_header->recognition_mode = *value; break; case RECOGNIZER_HEADER_CANCEL_IF_QUEUE: apt_boolean_value_parse(value,&recog_header->cancel_if_queue); @@ -265,7 +303,7 @@ static apt_bool_t mrcp_recog_header_parse(mrcp_recog_header_t *recog_header, apr 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); + recog_header->interpret_text = *value; break; case RECOGNIZER_HEADER_DTMF_BUFFER_TIME: recog_header->dtmf_buffer_time = apt_size_value_parse(value); @@ -276,6 +314,42 @@ static apt_bool_t mrcp_recog_header_parse(mrcp_recog_header_t *recog_header, apr case RECOGNIZER_HEADER_EARLY_NO_MATCH: apt_boolean_value_parse(value,&recog_header->early_no_match); break; + case RECOGNIZER_HEADER_NUM_MIN_CONSISTENT_PRONUNCIATIONS: + recog_header->num_min_consistent_pronunciations = apt_size_value_parse(value); + break; + case RECOGNIZER_HEADER_CONSISTENCY_THRESHOLD: + recog_header->consistency_threshold = apt_float_value_parse(value); + break; + case RECOGNIZER_HEADER_CLASH_THRESHOLD: + recog_header->clash_threshold = apt_float_value_parse(value); + break; + case RECOGNIZER_HEADER_PERSONAL_GRAMMAR_URI: + recog_header->personal_grammar_uri = *value; + break; + case RECOGNIZER_HEADER_ENROLL_UTTERANCE: + apt_boolean_value_parse(value,&recog_header->enroll_utterance); + break; + case RECOGNIZER_HEADER_PHRASE_ID: + recog_header->phrase_id = *value; + break; + case RECOGNIZER_HEADER_PHRASE_NL: + recog_header->phrase_nl = *value; + break; + case RECOGNIZER_HEADER_WEIGHT: + recog_header->weight = apt_float_value_parse(value); + break; + case RECOGNIZER_HEADER_SAVE_BEST_WAVEFORM: + apt_boolean_value_parse(value,&recog_header->save_best_waveform); + break; + case RECOGNIZER_HEADER_NEW_PHRASE_ID: + recog_header->new_phrase_id = *value; + break; + case RECOGNIZER_HEADER_CONFUSABLE_PHRASES_URI: + recog_header->confusable_phrases_uri = *value; + break; + case RECOGNIZER_HEADER_ABORT_PHRASE_ENROLLMENT: + apt_boolean_value_parse(value,&recog_header->abort_phrase_enrollment); + break; default: status = FALSE; } @@ -288,10 +362,10 @@ static APR_INLINE float apt_size_value_parse_as_float(const apt_str_t *value) return f / 100; } -static APR_INLINE apt_bool_t apt_size_value_generate_from_float(float value, apt_text_stream_t *stream) +static APR_INLINE apt_bool_t apt_size_value_generate_from_float(float value, apt_str_t *str, apr_pool_t *pool) { apr_size_t s = (apr_size_t)((value + 0.001f) * 100); - return apt_size_value_generate(s,stream); + return apt_size_value_generate(s,str,pool); } /** Parse MRCPv1 recognizer header */ @@ -333,95 +407,133 @@ static apt_bool_t mrcp_v2_recog_header_parse(mrcp_header_accessor_t *accessor, a } /** 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) +static apt_bool_t mrcp_recog_header_generate(const mrcp_recog_header_t *recog_header, apr_size_t id, apt_str_t *value, apr_pool_t *pool) { switch(id) { case RECOGNIZER_HEADER_N_BEST_LIST_LENGTH: - apt_size_value_generate(recog_header->n_best_list_length,value); + apt_size_value_generate(recog_header->n_best_list_length,value,pool); break; case RECOGNIZER_HEADER_NO_INPUT_TIMEOUT: - apt_size_value_generate(recog_header->no_input_timeout,value); + apt_size_value_generate(recog_header->no_input_timeout,value,pool); break; case RECOGNIZER_HEADER_RECOGNITION_TIMEOUT: - apt_size_value_generate(recog_header->recognition_timeout,value); + apt_size_value_generate(recog_header->recognition_timeout,value,pool); break; case RECOGNIZER_HEADER_WAVEFORM_URI: - apt_string_value_generate(&recog_header->waveform_uri,value); + *value = recog_header->waveform_uri; break; case RECOGNIZER_HEADER_RECOGNIZER_CONTEXT_BLOCK: - apt_string_value_generate(&recog_header->recognizer_context_block,value); + *value = recog_header->recognizer_context_block; break; case RECOGNIZER_HEADER_START_INPUT_TIMERS: - apt_boolean_value_generate(recog_header->start_input_timers,value); + apt_boolean_value_generate(recog_header->start_input_timers,value,pool); break; case RECOGNIZER_HEADER_SPEECH_COMPLETE_TIMEOUT: - apt_size_value_generate(recog_header->speech_complete_timeout,value); + apt_size_value_generate(recog_header->speech_complete_timeout,value,pool); break; case RECOGNIZER_HEADER_SPEECH_INCOMPLETE_TIMEOUT: - apt_size_value_generate(recog_header->speech_incomplete_timeout,value); + apt_size_value_generate(recog_header->speech_incomplete_timeout,value,pool); break; case RECOGNIZER_HEADER_DTMF_INTERDIGIT_TIMEOUT: - apt_size_value_generate(recog_header->dtmf_interdigit_timeout,value); + apt_size_value_generate(recog_header->dtmf_interdigit_timeout,value,pool); break; case RECOGNIZER_HEADER_DTMF_TERM_TIMEOUT: - apt_size_value_generate(recog_header->dtmf_term_timeout,value); + apt_size_value_generate(recog_header->dtmf_term_timeout,value,pool); break; case RECOGNIZER_HEADER_DTMF_TERM_CHAR: - *value->pos++ = recog_header->dtmf_term_char; + value->length = 1; + value->buf = apr_palloc(pool,value->length); + *value->buf = recog_header->dtmf_term_char; break; case RECOGNIZER_HEADER_FAILED_URI: - apt_string_value_generate(&recog_header->failed_uri,value); + *value = recog_header->failed_uri; break; case RECOGNIZER_HEADER_FAILED_URI_CAUSE: - apt_string_value_generate(&recog_header->failed_uri_cause,value); + *value = recog_header->failed_uri_cause; break; case RECOGNIZER_HEADER_SAVE_WAVEFORM: - apt_boolean_value_generate(recog_header->save_waveform,value); + apt_boolean_value_generate(recog_header->save_waveform,value,pool); break; case RECOGNIZER_HEADER_NEW_AUDIO_CHANNEL: - apt_boolean_value_generate(recog_header->new_audio_channel,value); + apt_boolean_value_generate(recog_header->new_audio_channel,value,pool); break; case RECOGNIZER_HEADER_SPEECH_LANGUAGE: - apt_string_value_generate(&recog_header->speech_language,value); + *value = recog_header->speech_language; break; case RECOGNIZER_HEADER_INPUT_TYPE: - apt_string_value_generate(&recog_header->input_type,value); + *value = recog_header->input_type; break; case RECOGNIZER_HEADER_INPUT_WAVEFORM_URI: - apt_string_value_generate(&recog_header->input_waveform_uri,value); + *value = recog_header->input_waveform_uri; break; case RECOGNIZER_HEADER_COMPLETION_REASON: - apt_string_value_generate(&recog_header->completion_reason,value); + *value = recog_header->completion_reason; break; case RECOGNIZER_HEADER_MEDIA_TYPE: - apt_string_value_generate(&recog_header->media_type,value); + *value = recog_header->media_type; break; case RECOGNIZER_HEADER_VER_BUFFER_UTTERANCE: - apt_boolean_value_generate(recog_header->ver_buffer_utterance,value); + apt_boolean_value_generate(recog_header->ver_buffer_utterance,value,pool); break; case RECOGNIZER_HEADER_RECOGNITION_MODE: - apt_string_value_generate(&recog_header->recognition_mode,value); + *value = recog_header->recognition_mode; break; case RECOGNIZER_HEADER_CANCEL_IF_QUEUE: - apt_boolean_value_generate(recog_header->cancel_if_queue,value); + apt_boolean_value_generate(recog_header->cancel_if_queue,value,pool); break; case RECOGNIZER_HEADER_HOTWORD_MAX_DURATION: - apt_size_value_generate(recog_header->hotword_max_duration,value); + apt_size_value_generate(recog_header->hotword_max_duration,value,pool); break; case RECOGNIZER_HEADER_HOTWORD_MIN_DURATION: - apt_size_value_generate(recog_header->hotword_min_duration,value); + apt_size_value_generate(recog_header->hotword_min_duration,value,pool); break; case RECOGNIZER_HEADER_INTERPRET_TEXT: - apt_string_value_generate(&recog_header->interpret_text,value); + *value = recog_header->interpret_text; break; case RECOGNIZER_HEADER_DTMF_BUFFER_TIME: - apt_size_value_generate(recog_header->dtmf_buffer_time,value); + apt_size_value_generate(recog_header->dtmf_buffer_time,value,pool); break; case RECOGNIZER_HEADER_CLEAR_DTMF_BUFFER: - apt_boolean_value_generate(recog_header->clear_dtmf_buffer,value); + apt_boolean_value_generate(recog_header->clear_dtmf_buffer,value,pool); break; case RECOGNIZER_HEADER_EARLY_NO_MATCH: - apt_boolean_value_generate(recog_header->early_no_match,value); + apt_boolean_value_generate(recog_header->early_no_match,value,pool); + break; + case RECOGNIZER_HEADER_NUM_MIN_CONSISTENT_PRONUNCIATIONS: + apt_size_value_generate(recog_header->num_min_consistent_pronunciations,value,pool); + break; + case RECOGNIZER_HEADER_CONSISTENCY_THRESHOLD: + apt_float_value_generate(recog_header->consistency_threshold,value,pool); + break; + case RECOGNIZER_HEADER_CLASH_THRESHOLD: + apt_float_value_generate(recog_header->clash_threshold,value,pool); + break; + case RECOGNIZER_HEADER_PERSONAL_GRAMMAR_URI: + *value = recog_header->personal_grammar_uri; + break; + case RECOGNIZER_HEADER_ENROLL_UTTERANCE: + apt_boolean_value_generate(recog_header->enroll_utterance,value,pool); + break; + case RECOGNIZER_HEADER_PHRASE_ID: + *value = recog_header->phrase_id; + break; + case RECOGNIZER_HEADER_PHRASE_NL: + *value = recog_header->phrase_nl; + break; + case RECOGNIZER_HEADER_WEIGHT: + apt_float_value_generate(recog_header->weight,value,pool); + break; + case RECOGNIZER_HEADER_SAVE_BEST_WAVEFORM: + apt_boolean_value_generate(recog_header->save_best_waveform,value,pool); + break; + case RECOGNIZER_HEADER_NEW_PHRASE_ID: + *value = recog_header->new_phrase_id; + break; + case RECOGNIZER_HEADER_CONFUSABLE_PHRASES_URI: + *value = recog_header->confusable_phrases_uri; + break; + case RECOGNIZER_HEADER_ABORT_PHRASE_ENROLLMENT: + apt_boolean_value_generate(recog_header->abort_phrase_enrollment,value,pool); break; default: break; @@ -430,53 +542,55 @@ static apt_bool_t mrcp_recog_header_generate(mrcp_recog_header_t *recog_header, } /** 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) +static apt_bool_t mrcp_v1_recog_header_generate(const mrcp_header_accessor_t *accessor, apr_size_t id, apt_str_t *value, apr_pool_t *pool) { 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); + return apt_size_value_generate_from_float(recog_header->confidence_threshold,value,pool); } else if(id == RECOGNIZER_HEADER_SENSITIVITY_LEVEL) { - return apt_size_value_generate_from_float(recog_header->sensitivity_level,value); + return apt_size_value_generate_from_float(recog_header->sensitivity_level,value,pool); } else if(id == RECOGNIZER_HEADER_SPEED_VS_ACCURACY) { - return apt_size_value_generate_from_float(recog_header->speed_vs_accuracy,value); + return apt_size_value_generate_from_float(recog_header->speed_vs_accuracy,value,pool); } else if(id == RECOGNIZER_HEADER_COMPLETION_CAUSE) { - return mrcp_completion_cause_generate( + return apt_completion_cause_generate( v1_completion_cause_string_table, RECOGNIZER_COMPLETION_CAUSE_COUNT, recog_header->completion_cause, - value); + value, + pool); } - return mrcp_recog_header_generate(recog_header,id,value); + return mrcp_recog_header_generate(recog_header,id,value,pool); } /** 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) +static apt_bool_t mrcp_v2_recog_header_generate(const mrcp_header_accessor_t *accessor, apr_size_t id, apt_str_t *value, apr_pool_t *pool) { mrcp_recog_header_t *recog_header = accessor->data; if(id == RECOGNIZER_HEADER_CONFIDENCE_THRESHOLD) { - return apt_float_value_generate(recog_header->confidence_threshold,value); + return apt_float_value_generate(recog_header->confidence_threshold,value,pool); } else if(id == RECOGNIZER_HEADER_SENSITIVITY_LEVEL) { - return apt_float_value_generate(recog_header->sensitivity_level,value); + return apt_float_value_generate(recog_header->sensitivity_level,value,pool); } else if(id == RECOGNIZER_HEADER_SPEED_VS_ACCURACY) { - return apt_float_value_generate(recog_header->speed_vs_accuracy,value); + return apt_float_value_generate(recog_header->speed_vs_accuracy,value,pool); } else if(id == RECOGNIZER_HEADER_COMPLETION_CAUSE) { - return mrcp_completion_cause_generate( + return apt_completion_cause_generate( v2_completion_cause_string_table, RECOGNIZER_COMPLETION_CAUSE_COUNT, recog_header->completion_cause, - value); + value, + pool); } - return mrcp_recog_header_generate(recog_header,id,value); + return mrcp_recog_header_generate(recog_header,id,value,pool); } /** 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) +static apt_bool_t mrcp_recog_header_duplicate(mrcp_header_accessor_t *accessor, const mrcp_header_accessor_t *src, apr_size_t id, const apt_str_t *value, apr_pool_t *pool) { mrcp_recog_header_t *recog_header = accessor->data; const mrcp_recog_header_t *src_recog_header = src->data; @@ -506,13 +620,13 @@ static apt_bool_t mrcp_recog_header_duplicate(mrcp_header_accessor_t *accessor, 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); + recog_header->waveform_uri = *value; 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); + recog_header->recognizer_context_block = *value; break; case RECOGNIZER_HEADER_START_INPUT_TIMERS: recog_header->start_input_timers = src_recog_header->start_input_timers; @@ -533,10 +647,10 @@ static apt_bool_t mrcp_recog_header_duplicate(mrcp_header_accessor_t *accessor, 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); + recog_header->failed_uri = *value; break; case RECOGNIZER_HEADER_FAILED_URI_CAUSE: - apt_string_copy(&recog_header->failed_uri_cause,&src_recog_header->failed_uri_cause,pool); + recog_header->failed_uri_cause = *value; break; case RECOGNIZER_HEADER_SAVE_WAVEFORM: recog_header->save_waveform = src_recog_header->save_waveform; @@ -545,25 +659,25 @@ static apt_bool_t mrcp_recog_header_duplicate(mrcp_header_accessor_t *accessor, 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); + recog_header->speech_language = *value; break; case RECOGNIZER_HEADER_INPUT_TYPE: - apt_string_copy(&recog_header->input_type,&src_recog_header->input_type,pool); + recog_header->input_type = *value; break; case RECOGNIZER_HEADER_INPUT_WAVEFORM_URI: - apt_string_copy(&recog_header->input_waveform_uri,&src_recog_header->input_waveform_uri,pool); + recog_header->input_waveform_uri = *value; break; case RECOGNIZER_HEADER_COMPLETION_REASON: - apt_string_copy(&recog_header->completion_reason,&src_recog_header->completion_reason,pool); + recog_header->completion_reason = *value; break; case RECOGNIZER_HEADER_MEDIA_TYPE: - apt_string_copy(&recog_header->media_type,&src_recog_header->media_type,pool); + recog_header->media_type = *value; 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); + recog_header->recognition_mode = *value; break; case RECOGNIZER_HEADER_CANCEL_IF_QUEUE: recog_header->cancel_if_queue = src_recog_header->cancel_if_queue; @@ -575,7 +689,7 @@ static apt_bool_t mrcp_recog_header_duplicate(mrcp_header_accessor_t *accessor, 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); + recog_header->interpret_text = *value; break; case RECOGNIZER_HEADER_DTMF_BUFFER_TIME: recog_header->dtmf_buffer_time = src_recog_header->dtmf_buffer_time; @@ -586,20 +700,48 @@ static apt_bool_t mrcp_recog_header_duplicate(mrcp_header_accessor_t *accessor, case RECOGNIZER_HEADER_EARLY_NO_MATCH: recog_header->early_no_match = src_recog_header->early_no_match; break; + case RECOGNIZER_HEADER_NUM_MIN_CONSISTENT_PRONUNCIATIONS: + recog_header->num_min_consistent_pronunciations = src_recog_header->num_min_consistent_pronunciations; + break; + case RECOGNIZER_HEADER_CONSISTENCY_THRESHOLD: + recog_header->consistency_threshold = src_recog_header->consistency_threshold; + break; + case RECOGNIZER_HEADER_CLASH_THRESHOLD: + recog_header->clash_threshold = src_recog_header->clash_threshold; + break; + case RECOGNIZER_HEADER_PERSONAL_GRAMMAR_URI: + recog_header->personal_grammar_uri = *value; + break; + case RECOGNIZER_HEADER_ENROLL_UTTERANCE: + recog_header->enroll_utterance = src_recog_header->enroll_utterance; + break; + case RECOGNIZER_HEADER_PHRASE_ID: + recog_header->phrase_id = *value; + break; + case RECOGNIZER_HEADER_PHRASE_NL: + recog_header->phrase_nl = *value; + break; + case RECOGNIZER_HEADER_WEIGHT: + recog_header->weight = src_recog_header->weight; + break; + case RECOGNIZER_HEADER_SAVE_BEST_WAVEFORM: + recog_header->save_best_waveform = src_recog_header->save_best_waveform; + break; + case RECOGNIZER_HEADER_NEW_PHRASE_ID: + recog_header->new_phrase_id = *value; + break; + case RECOGNIZER_HEADER_CONFUSABLE_PHRASES_URI: + recog_header->confusable_phrases_uri = *value; + break; + case RECOGNIZER_HEADER_ABORT_PHRASE_ENROLLMENT: + recog_header->abort_phrase_enrollment = src_recog_header->abort_phrase_enrollment; + 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 */ diff --git a/libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_resource.c b/libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_resource.c index bf9dc56f3a..108e1f638a 100644 --- a/libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_resource.c +++ b/libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_resource.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_recog_resource.c 1781 2010-09-01 07:33:00Z achaloyan $ */ #include "mrcp_recog_resource.h" @@ -22,34 +24,48 @@ static const apt_str_table_item_t v1_recog_method_string_table[] = { {{"SET-PARAMS", 10},10}, {{"GET-PARAMS", 10},10}, - {{"DEFINE-GRAMMAR", 14},0}, + {{"DEFINE-GRAMMAR", 14},2}, {{"RECOGNIZE", 9},7}, - {{"GET-RESULT", 10},4}, + {{"INTERPRET", 9},0}, + {{"GET-RESULT", 10},6}, {{"RECOGNITION-START-TIMERS", 24},7}, - {{"STOP", 4},1} + {{"STOP", 4},2}, + {{"START-PHRASE-ENROLLMENT", 23},2}, + {{"ENROLLMENT-ROLLBACK", 19},2}, + {{"END-PHRASE-ENROLLMENT", 21},5}, + {{"MODIFY-PHRASE", 13},0}, + {{"DELETE-PHRASE", 13},2} }; -/** String table of mrcpv2 recognizer methods (mrcp_recognizer_method_id) */ +/** 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} + {{"DEFINE-GRAMMAR", 14},2}, + {{"RECOGNIZE", 9},0}, + {{"INTERPRET", 9},0}, + {{"GET-RESULT", 10},6}, + {{"START-INPUT-TIMERS", 18},7}, + {{"STOP", 4},2}, + {{"START-PHRASE-ENROLLMENT", 23},6}, + {{"ENROLLMENT-ROLLBACK", 19},2}, + {{"END-PHRASE-ENROLLMENT", 21},5}, + {{"MODIFY-PHRASE", 13},0}, + {{"DELETE-PHRASE", 13},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} + {{"RECOGNITION-COMPLETE", 20},0}, + {{"INTERPRETATION-COMPLETE", 23},0} }; -/** String table of mrcpv2 recognizer events (mrcp_recognizer_event_id) */ +/** 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} + {{"RECOGNITION-COMPLETE", 20},0}, + {{"INTERPRETATION-COMPLETE", 23},0} }; diff --git a/libs/unimrcp/libs/mrcp/resources/src/mrcp_recorder_header.c b/libs/unimrcp/libs/mrcp/resources/src/mrcp_recorder_header.c index 34902c12c8..fdfea41373 100644 --- a/libs/unimrcp/libs/mrcp/resources/src/mrcp_recorder_header.c +++ b/libs/unimrcp/libs/mrcp/resources/src/mrcp_recorder_header.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,11 +12,13 @@ * 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. + * + * $Id: mrcp_recorder_header.c 1632 2010-03-30 20:46:25Z achaloyan $ */ #include "mrcp_recorder_header.h" -/** String table of recorder headers (mrcp_recorder_header_id) */ +/** String table of recorder header fields (mrcp_recorder_header_id) */ static const apt_str_table_item_t recorder_header_string_table[] = { {{"Sensitivity-Level", 17},3}, {{"No-Input-Timeout", 16},2}, @@ -90,19 +92,19 @@ static apt_bool_t mrcp_recorder_header_parse(mrcp_header_accessor_t *accessor, a recorder_header->completion_cause = apt_size_value_parse(value); break; case RECORDER_HEADER_COMPLETION_REASON: - apt_string_copy(&recorder_header->completion_reason,value,pool); + recorder_header->completion_reason = *value; break; case RECORDER_HEADER_FAILED_URI: - apt_string_copy(&recorder_header->failed_uri,value,pool); + recorder_header->failed_uri = *value; break; case RECORDER_HEADER_FAILED_URI_CAUSE: - apt_string_copy(&recorder_header->failed_uri_cause,value,pool); + recorder_header->failed_uri_cause = *value; break; case RECORDER_HEADER_RECORD_URI: - apt_string_copy(&recorder_header->record_uri,value,pool); + recorder_header->record_uri = *value; break; case RECORDER_HEADER_MEDIA_TYPE: - apt_string_copy(&recorder_header->media_type,value,pool); + recorder_header->media_type = *value; break; case RECORDER_HEADER_MAX_TIME: recorder_header->max_time = apt_size_value_parse(value); @@ -132,60 +134,61 @@ static apt_bool_t mrcp_recorder_header_parse(mrcp_header_accessor_t *accessor, a } /** Generate MRCP recorder header */ -static apt_bool_t mrcp_recorder_header_generate(mrcp_header_accessor_t *accessor, apr_size_t id, apt_text_stream_t *value) +static apt_bool_t mrcp_recorder_header_generate(const mrcp_header_accessor_t *accessor, apr_size_t id, apt_str_t *value, apr_pool_t *pool) { mrcp_recorder_header_t *recorder_header = accessor->data; switch(id) { case RECORDER_HEADER_SENSITIVITY_LEVEL: - apt_float_value_generate(recorder_header->sensitivity_level,value); + apt_float_value_generate(recorder_header->sensitivity_level,value,pool); break; case RECORDER_HEADER_NO_INPUT_TIMEOUT: - apt_size_value_generate(recorder_header->no_input_timeout,value); + apt_size_value_generate(recorder_header->no_input_timeout,value,pool); break; case RECORDER_HEADER_COMPLETION_CAUSE: { - mrcp_completion_cause_generate( + apt_completion_cause_generate( completion_cause_string_table, RECORDER_COMPLETION_CAUSE_COUNT, recorder_header->completion_cause, - value); + value, + pool); break; } case RECORDER_HEADER_COMPLETION_REASON: - apt_string_value_generate(&recorder_header->completion_reason,value); + *value = recorder_header->completion_reason; break; case RECORDER_HEADER_FAILED_URI: - apt_string_value_generate(&recorder_header->failed_uri,value); + *value = recorder_header->failed_uri; break; case RECORDER_HEADER_FAILED_URI_CAUSE: - apt_string_value_generate(&recorder_header->failed_uri_cause,value); + *value = recorder_header->failed_uri_cause; break; case RECORDER_HEADER_RECORD_URI: - apt_string_value_generate(&recorder_header->record_uri,value); + *value = recorder_header->record_uri; break; case RECORDER_HEADER_MEDIA_TYPE: - apt_string_value_generate(&recorder_header->media_type,value); + *value = recorder_header->media_type; break; case RECORDER_HEADER_MAX_TIME: - apt_size_value_generate(recorder_header->max_time,value); + apt_size_value_generate(recorder_header->max_time,value,pool); break; case RECORDER_HEADER_TRIM_LENGTH: - apt_size_value_generate(recorder_header->trim_length,value); + apt_size_value_generate(recorder_header->trim_length,value,pool); break; case RECORDER_HEADER_FINAL_SILENCE: - apt_size_value_generate(recorder_header->final_silence,value); + apt_size_value_generate(recorder_header->final_silence,value,pool); break; case RECORDER_HEADER_CAPTURE_ON_SPEECH: - apt_boolean_value_generate(recorder_header->capture_on_speech,value); + apt_boolean_value_generate(recorder_header->capture_on_speech,value,pool); break; case RECORDER_HEADER_VER_BUFFER_UTTERANCE: - apt_boolean_value_generate(recorder_header->ver_buffer_utterance,value); + apt_boolean_value_generate(recorder_header->ver_buffer_utterance,value,pool); break; case RECORDER_HEADER_START_INPUT_TIMERS: - apt_boolean_value_generate(recorder_header->start_input_timers,value); + apt_boolean_value_generate(recorder_header->start_input_timers,value,pool); break; case RECORDER_HEADER_NEW_AUDIO_CHANNEL: - apt_boolean_value_generate(recorder_header->new_audio_channel,value); + apt_boolean_value_generate(recorder_header->new_audio_channel,value,pool); break; default: break; @@ -194,7 +197,7 @@ static apt_bool_t mrcp_recorder_header_generate(mrcp_header_accessor_t *accessor } /** Duplicate MRCP recorder header */ -static apt_bool_t mrcp_recorder_header_duplicate(mrcp_header_accessor_t *accessor, const mrcp_header_accessor_t *src, apr_size_t id, apr_pool_t *pool) +static apt_bool_t mrcp_recorder_header_duplicate(mrcp_header_accessor_t *accessor, const mrcp_header_accessor_t *src, apr_size_t id, const apt_str_t *value, apr_pool_t *pool) { mrcp_recorder_header_t *recorder_header = accessor->data; const mrcp_recorder_header_t *src_recorder_header = src->data; @@ -215,19 +218,19 @@ static apt_bool_t mrcp_recorder_header_duplicate(mrcp_header_accessor_t *accesso recorder_header->completion_cause = src_recorder_header->completion_cause; break; case RECORDER_HEADER_COMPLETION_REASON: - apt_string_copy(&recorder_header->completion_reason,&src_recorder_header->completion_reason,pool); + recorder_header->completion_reason = *value; break; case RECORDER_HEADER_FAILED_URI: - apt_string_copy(&recorder_header->failed_uri,&src_recorder_header->failed_uri,pool); + recorder_header->failed_uri = *value; break; case RECORDER_HEADER_FAILED_URI_CAUSE: - apt_string_copy(&recorder_header->failed_uri_cause,&src_recorder_header->failed_uri_cause,pool); + recorder_header->failed_uri_cause = *value; break; case RECORDER_HEADER_RECORD_URI: - apt_string_copy(&recorder_header->record_uri,&src_recorder_header->record_uri,pool); + recorder_header->record_uri = *value; break; case RECORDER_HEADER_MEDIA_TYPE: - apt_string_copy(&recorder_header->media_type,&src_recorder_header->media_type,pool); + recorder_header->media_type = *value; break; case RECORDER_HEADER_MAX_TIME: recorder_header->max_time = src_recorder_header->max_time; diff --git a/libs/unimrcp/libs/mrcp/resources/src/mrcp_recorder_resource.c b/libs/unimrcp/libs/mrcp/resources/src/mrcp_recorder_resource.c index edb047c5a9..24254c1a7c 100644 --- a/libs/unimrcp/libs/mrcp/resources/src/mrcp_recorder_resource.c +++ b/libs/unimrcp/libs/mrcp/resources/src/mrcp_recorder_resource.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_recorder_resource.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include "mrcp_recorder_resource.h" diff --git a/libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_header.c b/libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_header.c index 51ec8667c7..45b88087d3 100644 --- a/libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_header.c +++ b/libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_header.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,11 +12,13 @@ * 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. + * + * $Id: mrcp_synth_header.c 1632 2010-03-30 20:46:25Z achaloyan $ */ #include "mrcp_synth_header.h" -/** String table of MRCP synthesizer headers (mrcp_synthesizer_header_id) */ +/** String table of MRCP synthesizer header fields (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}, @@ -95,7 +97,7 @@ static APR_INLINE apr_size_t apt_string_table_value_parse(const apt_str_table_it 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) +static apt_bool_t apt_string_table_value_generate(const apt_str_table_item_t *string_table, apr_size_t count, apr_size_t id, apt_text_stream_t *stream) { const apt_str_t *name = apt_string_table_str_get(string_table,count,id); if(!name) { @@ -107,6 +109,17 @@ static apt_bool_t apt_string_table_value_generate(const apt_str_table_item_t *st return TRUE; } +static apt_bool_t apt_string_table_value_pgenerate(const apt_str_table_item_t *string_table, apr_size_t count, apr_size_t id, apt_str_t *str, apr_pool_t *pool) +{ + const apt_str_t *name = apt_string_table_str_get(string_table,count,id); + if(!name) { + return FALSE; + } + + apt_string_copy(str,name,pool); + 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) { @@ -133,13 +146,18 @@ static apt_bool_t mrcp_prosody_param_rate_parse(mrcp_prosody_rate_t *prosody_rat } /** Generate MRCP prosody-rate value */ -static apt_bool_t mrcp_prosody_rate_generate(mrcp_prosody_rate_t *prosody_rate, apt_text_stream_t *stream) +static apt_bool_t mrcp_prosody_rate_generate(mrcp_prosody_rate_t *prosody_rate, apt_str_t *str, apr_pool_t *pool) { 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); + apt_string_table_value_pgenerate( + prosody_rate_string_table, + PROSODY_RATE_COUNT, + prosody_rate->value.label, + str, + pool); } else { - apt_float_value_generate(prosody_rate->value.relative, stream); + apt_float_value_generate(prosody_rate->value.relative,str,pool); } return TRUE; @@ -177,16 +195,21 @@ static apt_bool_t mrcp_prosody_param_volume_parse(mrcp_prosody_volume_t *prosody } /** Generate MRCP prosody-volume value */ -static apt_bool_t mrcp_prosody_volume_generate(mrcp_prosody_volume_t *prosody_volume, apt_text_stream_t *stream) +static apt_bool_t mrcp_prosody_volume_generate(mrcp_prosody_volume_t *prosody_volume, apt_str_t *str, apr_pool_t *pool) { 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); + apt_string_table_value_pgenerate( + prosody_volume_string_table, + PROSODY_VOLUME_COUNT, + prosody_volume->value.label, + str, + pool); } else if (prosody_volume->type == PROSODY_VOLUME_TYPE_NUMERIC) { - apt_float_value_generate(prosody_volume->value.numeric, stream); + apt_float_value_generate(prosody_volume->value.numeric,str,pool); } else { - apt_float_value_generate(prosody_volume->value.relative, stream); + apt_float_value_generate(prosody_volume->value.relative,str,pool); } return TRUE; @@ -229,25 +252,29 @@ static apt_bool_t mrcp_speech_length_value_parse(mrcp_speech_length_value_t *spe } /** 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) +static apt_bool_t mrcp_speech_length_generate(mrcp_speech_length_value_t *speech_length, apt_str_t *str, apr_pool_t *pool) { 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; + apt_string_copy(str,tag,pool); } } else { + char buf[256]; + apt_text_stream_t stream; + apt_text_stream_init(&stream,buf,sizeof(buf)); if(speech_length->type == SPEECH_LENGTH_TYPE_NUMERIC_POSITIVE) { - *stream->pos++ = '+'; + *stream.pos++ = '+'; } else { - *stream->pos++ = '-'; + *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); + apt_text_size_value_insert(&stream,speech_length->value.numeric.length); + *stream.pos++ = APT_TOKEN_SP; + apt_string_table_value_generate(speech_unit_string_table,SPEECH_UNIT_COUNT,speech_length->value.numeric.unit,&stream); + + apt_string_assign_n(str,stream.text.buf, stream.pos - stream.text.buf, pool); } return TRUE; } @@ -301,13 +328,13 @@ static apt_bool_t mrcp_synth_header_parse(mrcp_header_accessor_t *accessor, size 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); + synth_header->speaker_profile = *value; 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); + synth_header->completion_reason = *value; break; case SYNTHESIZER_HEADER_VOICE_GENDER: synth_header->voice_param.gender = apt_string_table_value_parse(voice_gender_string_table,VOICE_GENDER_COUNT,value); @@ -319,7 +346,7 @@ static apt_bool_t mrcp_synth_header_parse(mrcp_header_accessor_t *accessor, size 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); + synth_header->voice_param.name = *value; break; case SYNTHESIZER_HEADER_PROSODY_VOLUME: mrcp_prosody_param_volume_parse(&synth_header->prosody_param.volume,value,pool); @@ -328,22 +355,22 @@ static apt_bool_t mrcp_synth_header_parse(mrcp_header_accessor_t *accessor, size 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); + synth_header->speech_marker = *value; break; case SYNTHESIZER_HEADER_SPEECH_LANGUAGE: - apt_string_copy(&synth_header->speech_language,value,pool); + synth_header->speech_language = *value; break; case SYNTHESIZER_HEADER_FETCH_HINT: - apt_string_copy(&synth_header->fetch_hint,value,pool); + synth_header->fetch_hint = *value; break; case SYNTHESIZER_HEADER_AUDIO_FETCH_HINT: - apt_string_copy(&synth_header->audio_fetch_hint,value,pool); + synth_header->audio_fetch_hint = *value; break; case SYNTHESIZER_HEADER_FAILED_URI: - apt_string_copy(&synth_header->failed_uri,value,pool); + synth_header->failed_uri = *value; break; case SYNTHESIZER_HEADER_FAILED_URI_CAUSE: - apt_string_copy(&synth_header->failed_uri_cause,value,pool); + synth_header->failed_uri_cause = *value; break; case SYNTHESIZER_HEADER_SPEAK_RESTART: apt_boolean_value_parse(value,&synth_header->speak_restart); @@ -355,7 +382,7 @@ static apt_bool_t mrcp_synth_header_parse(mrcp_header_accessor_t *accessor, size 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); + synth_header->lexicon_search_order = *value; break; default: status = FALSE; @@ -364,76 +391,82 @@ static apt_bool_t mrcp_synth_header_parse(mrcp_header_accessor_t *accessor, size } /** 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) +static apt_bool_t mrcp_synth_header_generate(const mrcp_header_accessor_t *accessor, size_t id, apt_str_t *value, apr_pool_t *pool) { mrcp_synth_header_t *synth_header = accessor->data; switch(id) { case SYNTHESIZER_HEADER_JUMP_SIZE: - mrcp_speech_length_generate(&synth_header->jump_size,value); + mrcp_speech_length_generate(&synth_header->jump_size,value,pool); break; case SYNTHESIZER_HEADER_KILL_ON_BARGE_IN: - apt_boolean_value_generate(synth_header->kill_on_barge_in,value); + apt_boolean_value_generate(synth_header->kill_on_barge_in,value,pool); break; case SYNTHESIZER_HEADER_SPEAKER_PROFILE: - apt_string_value_generate(&synth_header->speaker_profile,value); + *value = synth_header->speaker_profile,value; break; case SYNTHESIZER_HEADER_COMPLETION_CAUSE: - mrcp_completion_cause_generate( + apt_completion_cause_generate( completion_cause_string_table, SYNTHESIZER_COMPLETION_CAUSE_COUNT, synth_header->completion_cause, - value); + value, + pool); break; case SYNTHESIZER_HEADER_COMPLETION_REASON: - apt_string_value_generate(&synth_header->completion_reason,value); + *value = synth_header->completion_reason; break; case SYNTHESIZER_HEADER_VOICE_GENDER: - apt_string_table_value_generate(voice_gender_string_table,VOICE_GENDER_COUNT,synth_header->voice_param.gender,value); + apt_string_table_value_pgenerate( + voice_gender_string_table, + VOICE_GENDER_COUNT, + synth_header->voice_param.gender, + value, + pool); break; case SYNTHESIZER_HEADER_VOICE_AGE: - apt_size_value_generate(synth_header->voice_param.age,value); + apt_size_value_generate(synth_header->voice_param.age,value,pool); break; case SYNTHESIZER_HEADER_VOICE_VARIANT: - apt_size_value_generate(synth_header->voice_param.variant,value); + apt_size_value_generate(synth_header->voice_param.variant,value,pool); break; case SYNTHESIZER_HEADER_VOICE_NAME: - apt_string_value_generate(&synth_header->voice_param.name,value); + *value = synth_header->voice_param.name,value; break; case SYNTHESIZER_HEADER_PROSODY_VOLUME: - mrcp_prosody_volume_generate(&synth_header->prosody_param.volume,value); + mrcp_prosody_volume_generate(&synth_header->prosody_param.volume,value,pool); break; case SYNTHESIZER_HEADER_PROSODY_RATE: - mrcp_prosody_rate_generate(&synth_header->prosody_param.rate,value); + mrcp_prosody_rate_generate(&synth_header->prosody_param.rate,value,pool); break; case SYNTHESIZER_HEADER_SPEECH_MARKER: - apt_string_value_generate(&synth_header->speech_marker,value); + *value = synth_header->speech_marker; break; case SYNTHESIZER_HEADER_SPEECH_LANGUAGE: - apt_string_value_generate(&synth_header->speech_language,value); + *value = synth_header->speech_language; break; case SYNTHESIZER_HEADER_FETCH_HINT: - apt_string_value_generate(&synth_header->fetch_hint,value); + *value = synth_header->fetch_hint; break; case SYNTHESIZER_HEADER_AUDIO_FETCH_HINT: - apt_string_value_generate(&synth_header->audio_fetch_hint,value); + *value = synth_header->audio_fetch_hint; break; case SYNTHESIZER_HEADER_FAILED_URI: - apt_string_value_generate(&synth_header->failed_uri,value); + *value = synth_header->failed_uri; break; case SYNTHESIZER_HEADER_FAILED_URI_CAUSE: - apt_string_value_generate(&synth_header->failed_uri_cause,value); + *value = synth_header->failed_uri_cause; break; case SYNTHESIZER_HEADER_SPEAK_RESTART: - apt_boolean_value_generate(synth_header->speak_restart,value); + apt_boolean_value_generate(synth_header->speak_restart,value,pool); break; case SYNTHESIZER_HEADER_SPEAK_LENGTH: - mrcp_speech_length_generate(&synth_header->speak_length,value); + mrcp_speech_length_generate(&synth_header->speak_length,value,pool); break; case SYNTHESIZER_HEADER_LOAD_LEXICON: - apt_boolean_value_generate(synth_header->load_lexicon,value); + apt_boolean_value_generate(synth_header->load_lexicon,value,pool); break; case SYNTHESIZER_HEADER_LEXICON_SEARCH_ORDER: - apt_string_value_generate(&synth_header->lexicon_search_order,value); + *value = synth_header->lexicon_search_order; break; default: break; @@ -442,7 +475,7 @@ static apt_bool_t mrcp_synth_header_generate(mrcp_header_accessor_t *accessor, s } /** 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) +static apt_bool_t mrcp_synth_header_duplicate(mrcp_header_accessor_t *accessor, const mrcp_header_accessor_t *src, size_t id, const apt_str_t *value, apr_pool_t *pool) { mrcp_synth_header_t *synth_header = accessor->data; const mrcp_synth_header_t *src_synth_header = src->data; @@ -460,13 +493,13 @@ static apt_bool_t mrcp_synth_header_duplicate(mrcp_header_accessor_t *accessor, 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); + synth_header->speaker_profile = *value; 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); + synth_header->completion_reason = *value; break; case SYNTHESIZER_HEADER_VOICE_GENDER: synth_header->voice_param.gender = src_synth_header->voice_param.gender; @@ -478,7 +511,7 @@ static apt_bool_t mrcp_synth_header_duplicate(mrcp_header_accessor_t *accessor, 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); + synth_header->voice_param.name = *value; break; case SYNTHESIZER_HEADER_PROSODY_VOLUME: synth_header->prosody_param.volume = src_synth_header->prosody_param.volume; @@ -487,22 +520,22 @@ static apt_bool_t mrcp_synth_header_duplicate(mrcp_header_accessor_t *accessor, 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); + synth_header->speech_marker = *value; break; case SYNTHESIZER_HEADER_SPEECH_LANGUAGE: - apt_string_copy(&synth_header->speech_language,&src_synth_header->speech_language,pool); + synth_header->speech_language = *value; break; case SYNTHESIZER_HEADER_FETCH_HINT: - apt_string_copy(&synth_header->fetch_hint,&src_synth_header->fetch_hint,pool); + synth_header->fetch_hint = *value; break; case SYNTHESIZER_HEADER_AUDIO_FETCH_HINT: - apt_string_copy(&synth_header->audio_fetch_hint,&src_synth_header->audio_fetch_hint,pool); + synth_header->audio_fetch_hint = *value; break; case SYNTHESIZER_HEADER_FAILED_URI: - apt_string_copy(&synth_header->failed_uri,&src_synth_header->failed_uri,pool); + synth_header->failed_uri = *value; break; case SYNTHESIZER_HEADER_FAILED_URI_CAUSE: - apt_string_copy(&synth_header->failed_uri_cause,&src_synth_header->failed_uri_cause,pool); + synth_header->failed_uri_cause = *value; break; case SYNTHESIZER_HEADER_SPEAK_RESTART: synth_header->speak_restart = src_synth_header->speak_restart; @@ -514,7 +547,7 @@ static apt_bool_t mrcp_synth_header_duplicate(mrcp_header_accessor_t *accessor, 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); + synth_header->lexicon_search_order = *value; break; default: status = FALSE; diff --git a/libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_resource.c b/libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_resource.c index 702af0a6e5..fb17ce67e1 100644 --- a/libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_resource.c +++ b/libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_resource.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_synth_resource.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include "mrcp_synth_resource.h" diff --git a/libs/unimrcp/libs/mrcp/resources/src/mrcp_verifier_header.c b/libs/unimrcp/libs/mrcp/resources/src/mrcp_verifier_header.c new file mode 100644 index 0000000000..9a15924b43 --- /dev/null +++ b/libs/unimrcp/libs/mrcp/resources/src/mrcp_verifier_header.c @@ -0,0 +1,352 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: + */ + +#include "mrcp_verifier_header.h" + +/** String table of MRCP verifier header fields (mrcp_verifier_header_id) */ +static const apt_str_table_item_t verifier_header_string_table[] = { + {{"Repository-URI", 14},0}, + {{"Voiceprint-Identifier", 21},12}, + {{"Verification-Mode", 17},6}, + {{"Adapt-Model", 11},1}, + {{"Abort-Model", 11},11}, + {{"Min-Verification-Score", 22},1}, + {{"Num-Min-Verification-Phrases",28},6}, + {{"Num-Max-Verification-Phrases",28},5}, + {{"No-Input-Timeout", 16},2}, + {{"Save-Waveform", 13},4}, + {{"Media-Type", 10},2}, + {{"Waveform-URI", 12},0}, + {{"Voiceprint-Exists", 17},11}, + {{"Ver-Buffer-Utterance", 20},4}, + {{"Input-Waveform-URI", 18},0}, + {{"Completion-Cause", 16},11}, + {{"Completion-Reason", 17},15}, + {{"Speech-Complete-Timeout", 23},1}, + {{"New-Audio-Channel", 17},2}, + {{"Abort-Verification", 18},6}, + {{"Start-Input-Timers", 18},1} +}; + +/** String table of MRCP verifier completion-cause fields (mrcp_verifier_completion_cause_e) */ +static const apt_str_table_item_t completion_cause_string_table[] = { + {{"success", 7},2}, + {{"error", 5},0}, + {{"no-input-timeout", 16},0}, + {{"too-much-speech-timeout",23},0}, + {{"speech-too-early", 16},9}, + {{"buffer-empty", 12},0}, + {{"out-of-sequence", 15},0}, + {{"repository-uri-failure", 22},15}, + {{"repository-uri-missing", 22},15}, + {{"voiceprint-id-missing", 21},14}, + {{"voiceprint-id-not-exist",23},14}, + {{"speech-not-usable", 17},7} +}; + + +/** Initialize verifier header */ +static void mrcp_verifier_header_init(mrcp_verifier_header_t *verifier_header) +{ + apt_string_reset(&verifier_header->repository_uri); + apt_string_reset(&verifier_header->voiceprint_identifier); + apt_string_reset(&verifier_header->verification_mode); + verifier_header->adapt_model = FALSE; + verifier_header->abort_model = FALSE; + verifier_header->min_verification_score = 0.0; + verifier_header->num_min_verification_phrases = 0; + verifier_header->num_max_verification_phrases = 0; + verifier_header->no_input_timeout = 0; + verifier_header->save_waveform = FALSE; + apt_string_reset(&verifier_header->media_type); + apt_string_reset(&verifier_header->waveform_uri); + verifier_header->voiceprint_exists = FALSE; + verifier_header->ver_buffer_utterance = FALSE; + apt_string_reset(&verifier_header->input_waveform_uri); + verifier_header->completion_cause = VERIFIER_COMPLETION_CAUSE_UNKNOWN; + apt_string_reset(&verifier_header->completion_reason); + verifier_header->speech_complete_timeout = 0; + verifier_header->new_audio_channel = FALSE; + verifier_header->abort_verification = FALSE; + verifier_header->start_input_timers = FALSE; +} + +/** Allocate MRCP verifier header */ +static void* mrcp_verifier_header_allocate(mrcp_header_accessor_t *accessor, apr_pool_t *pool) +{ + mrcp_verifier_header_t *verifier_header = apr_palloc(pool,sizeof(mrcp_verifier_header_t)); + mrcp_verifier_header_init(verifier_header); + accessor->data = verifier_header; + return accessor->data; +} + +/** Parse MRCP verifier header */ +static apt_bool_t mrcp_verifier_header_parse(mrcp_header_accessor_t *accessor, apr_size_t id, const apt_str_t *value, apr_pool_t *pool) +{ + mrcp_verifier_header_t *verifier_header = accessor->data; + apt_bool_t status = TRUE; + switch(id) { + case VERIFIER_HEADER_REPOSITORY_URI: + verifier_header->repository_uri = *value; + break; + case VERIFIER_HEADER_VOICEPRINT_IDENTIFIER: + verifier_header->voiceprint_identifier = *value; + break; + case VERIFIER_HEADER_VERIFICATION_MODE: + verifier_header->verification_mode = *value; + break; + case VERIFIER_HEADER_ADAPT_MODEL: + apt_boolean_value_parse(value,&verifier_header->adapt_model); + break; + case VERIFIER_HEADER_ABORT_MODEL: + apt_boolean_value_parse(value,&verifier_header->abort_model); + break; + case VERIFIER_HEADER_MIN_VERIFICATION_SCORE: + verifier_header->min_verification_score = apt_float_value_parse(value); + break; + case VERIFIER_HEADER_NUM_MIN_VERIFICATION_PHRASES: + verifier_header->num_min_verification_phrases = apt_size_value_parse(value); + break; + case VERIFIER_HEADER_NUM_MAX_VERIFICATION_PHRASES: + verifier_header->num_max_verification_phrases = apt_size_value_parse(value); + break; + case VERIFIER_HEADER_NO_INPUT_TIMEOUT: + verifier_header->no_input_timeout = apt_size_value_parse(value); + break; + case VERIFIER_HEADER_SAVE_WAVEFORM: + apt_boolean_value_parse(value,&verifier_header->save_waveform); + break; + case VERIFIER_HEADER_MEDIA_TYPE: + verifier_header->media_type = *value; + break; + case VERIFIER_HEADER_WAVEFORM_URI: + verifier_header->waveform_uri = *value; + break; + case VERIFIER_HEADER_VOICEPRINT_EXISTS: + apt_boolean_value_parse(value,&verifier_header->voiceprint_exists); + break; + case VERIFIER_HEADER_VER_BUFFER_UTTERANCE: + apt_boolean_value_parse(value,&verifier_header->ver_buffer_utterance); + break; + case VERIFIER_HEADER_INPUT_WAVEFORM_URI: + verifier_header->input_waveform_uri = *value; + break; + case VERIFIER_HEADER_COMPLETION_CAUSE: + verifier_header->completion_cause = apt_size_value_parse(value); + break; + case VERIFIER_HEADER_COMPLETION_REASON: + verifier_header->completion_reason = *value; + break; + case VERIFIER_HEADER_SPEECH_COMPLETE_TIMEOUT: + verifier_header->speech_complete_timeout = apt_size_value_parse(value); + break; + case VERIFIER_HEADER_NEW_AUDIO_CHANNEL: + apt_boolean_value_parse(value,&verifier_header->new_audio_channel); + break; + case VERIFIER_HEADER_ABORT_VERIFICATION: + apt_boolean_value_parse(value,&verifier_header->abort_verification); + break; + case VERIFIER_HEADER_START_INPUT_TIMERS: + apt_boolean_value_parse(value,&verifier_header->start_input_timers); + break; + default: + status = FALSE; + } + return status; +} + +/** Generate MRCP verifier header */ +static apt_bool_t mrcp_verifier_header_generate(const mrcp_header_accessor_t *accessor, apr_size_t id, apt_str_t *value, apr_pool_t *pool) +{ + mrcp_verifier_header_t *verifier_header = accessor->data; + switch(id) { + case VERIFIER_HEADER_REPOSITORY_URI: + *value = verifier_header->repository_uri; + break; + case VERIFIER_HEADER_VOICEPRINT_IDENTIFIER: + *value = verifier_header->voiceprint_identifier; + break; + case VERIFIER_HEADER_VERIFICATION_MODE: + *value = verifier_header->verification_mode; + break; + case VERIFIER_HEADER_ADAPT_MODEL: + apt_boolean_value_generate(verifier_header->adapt_model,value,pool); + break; + case VERIFIER_HEADER_ABORT_MODEL: + apt_boolean_value_generate(verifier_header->abort_model,value,pool); + break; + case VERIFIER_HEADER_MIN_VERIFICATION_SCORE: + apt_float_value_generate(verifier_header->min_verification_score,value,pool); + break; + case VERIFIER_HEADER_NUM_MIN_VERIFICATION_PHRASES: + apt_size_value_generate(verifier_header->num_min_verification_phrases,value,pool); + break; + case VERIFIER_HEADER_NUM_MAX_VERIFICATION_PHRASES: + apt_size_value_generate(verifier_header->num_max_verification_phrases,value,pool); + break; + case VERIFIER_HEADER_NO_INPUT_TIMEOUT: + apt_size_value_generate(verifier_header->no_input_timeout,value,pool); + break; + case VERIFIER_HEADER_SAVE_WAVEFORM: + apt_boolean_value_generate(verifier_header->save_waveform,value,pool); + break; + case VERIFIER_HEADER_MEDIA_TYPE: + *value = verifier_header->media_type; + break; + case VERIFIER_HEADER_WAVEFORM_URI: + *value = verifier_header->waveform_uri; + break; + case VERIFIER_HEADER_VOICEPRINT_EXISTS: + apt_boolean_value_generate(verifier_header->voiceprint_exists,value,pool); + break; + case VERIFIER_HEADER_VER_BUFFER_UTTERANCE: + apt_boolean_value_generate(verifier_header->ver_buffer_utterance,value,pool); + break; + case VERIFIER_HEADER_INPUT_WAVEFORM_URI: + *value = verifier_header->input_waveform_uri; + break; + case VERIFIER_HEADER_COMPLETION_CAUSE: + apt_completion_cause_generate( + completion_cause_string_table, + VERIFIER_COMPLETION_CAUSE_COUNT, + verifier_header->completion_cause, + value, + pool); + break; + case VERIFIER_HEADER_COMPLETION_REASON: + *value = verifier_header->completion_reason; + break; + case VERIFIER_HEADER_SPEECH_COMPLETE_TIMEOUT: + apt_size_value_generate(verifier_header->speech_complete_timeout,value,pool); + break; + case VERIFIER_HEADER_NEW_AUDIO_CHANNEL: + apt_boolean_value_generate(verifier_header->new_audio_channel,value,pool); + break; + case VERIFIER_HEADER_ABORT_VERIFICATION: + apt_boolean_value_generate(verifier_header->abort_verification,value,pool); + break; + case VERIFIER_HEADER_START_INPUT_TIMERS: + apt_boolean_value_generate(verifier_header->start_input_timers,value,pool); + break; + default: + break; + } + return TRUE; +} + +/** Duplicate MRCP verifier header */ +static apt_bool_t mrcp_verifier_header_duplicate(mrcp_header_accessor_t *accessor, const mrcp_header_accessor_t *src, apr_size_t id, const apt_str_t *value, apr_pool_t *pool) +{ + mrcp_verifier_header_t *verifier_header = accessor->data; + const mrcp_verifier_header_t *src_verifier_header = src->data; + apt_bool_t status = TRUE; + + if(!verifier_header || !src_verifier_header) { + return FALSE; + } + + switch(id) { + case VERIFIER_HEADER_REPOSITORY_URI: + verifier_header->repository_uri = *value; + break; + case VERIFIER_HEADER_VOICEPRINT_IDENTIFIER: + verifier_header->voiceprint_identifier = *value; + break; + case VERIFIER_HEADER_VERIFICATION_MODE: + verifier_header->verification_mode = *value; + break; + case VERIFIER_HEADER_ADAPT_MODEL: + verifier_header->adapt_model = src_verifier_header->adapt_model; + break; + case VERIFIER_HEADER_ABORT_MODEL: + verifier_header->abort_model = src_verifier_header->abort_model; + break; + case VERIFIER_HEADER_MIN_VERIFICATION_SCORE: + verifier_header->min_verification_score = src_verifier_header->min_verification_score; + break; + case VERIFIER_HEADER_NUM_MIN_VERIFICATION_PHRASES: + verifier_header->num_min_verification_phrases = src_verifier_header->num_min_verification_phrases; + break; + case VERIFIER_HEADER_NUM_MAX_VERIFICATION_PHRASES: + verifier_header->num_max_verification_phrases = src_verifier_header->num_max_verification_phrases; + break; + case VERIFIER_HEADER_NO_INPUT_TIMEOUT: + verifier_header->no_input_timeout = src_verifier_header->no_input_timeout; + break; + case VERIFIER_HEADER_SAVE_WAVEFORM: + verifier_header->save_waveform = src_verifier_header->save_waveform; + break; + case VERIFIER_HEADER_MEDIA_TYPE: + verifier_header->media_type = *value; + break; + case VERIFIER_HEADER_WAVEFORM_URI: + verifier_header->waveform_uri = *value; + break; + case VERIFIER_HEADER_VOICEPRINT_EXISTS: + verifier_header->voiceprint_exists = src_verifier_header->voiceprint_exists; + break; + case VERIFIER_HEADER_VER_BUFFER_UTTERANCE: + verifier_header->ver_buffer_utterance = src_verifier_header->ver_buffer_utterance; + break; + case VERIFIER_HEADER_INPUT_WAVEFORM_URI: + verifier_header->input_waveform_uri = *value; + break; + case VERIFIER_HEADER_COMPLETION_CAUSE: + verifier_header->completion_cause = src_verifier_header->completion_cause; + break; + case VERIFIER_HEADER_COMPLETION_REASON: + verifier_header->completion_reason = *value; + break; + case VERIFIER_HEADER_SPEECH_COMPLETE_TIMEOUT: + verifier_header->speech_complete_timeout = src_verifier_header->speech_complete_timeout; + break; + case VERIFIER_HEADER_NEW_AUDIO_CHANNEL: + verifier_header->new_audio_channel = src_verifier_header->new_audio_channel; + break; + case VERIFIER_HEADER_ABORT_VERIFICATION: + verifier_header->abort_verification = src_verifier_header->abort_verification; + break; + case VERIFIER_HEADER_START_INPUT_TIMERS: + verifier_header->start_input_timers = src_verifier_header->start_input_timers; + break; + default: + status = FALSE; + } + return status; +} + +static const mrcp_header_vtable_t header_vtable = { + mrcp_verifier_header_allocate, + NULL, /* nothing to destroy */ + mrcp_verifier_header_parse, + mrcp_verifier_header_generate, + mrcp_verifier_header_duplicate, + verifier_header_string_table, + VERIFIER_HEADER_COUNT +}; + +const mrcp_header_vtable_t* mrcp_verifier_header_vtable_get(mrcp_version_e version) +{ + return &header_vtable; +} + +MRCP_DECLARE(const apt_str_t*) mrcp_verifier_completion_cause_get(mrcp_verifier_completion_cause_e completion_cause, mrcp_version_e version) +{ + const apt_str_table_item_t *table = completion_cause_string_table; + return apt_string_table_str_get(table,VERIFIER_COMPLETION_CAUSE_COUNT,completion_cause); +} diff --git a/libs/unimrcp/libs/mrcp/resources/src/mrcp_verifier_resource.c b/libs/unimrcp/libs/mrcp/resources/src/mrcp_verifier_resource.c new file mode 100644 index 0000000000..71d6b28c1f --- /dev/null +++ b/libs/unimrcp/libs/mrcp/resources/src/mrcp_verifier_resource.c @@ -0,0 +1,68 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: + */ + +#include "mrcp_verifier_resource.h" +#include "mrcp_verifier_header.h" +#include "mrcp_resource.h" + +/** String table of MRCP verifier methods (mrcp_verifier_method_id) */ +static const apt_str_table_item_t verifier_method_string_table[] = { + {{"SET-PARAMS", 10},10}, + {{"GET-PARAMS", 10},10}, + {{"START-SESSION", 13},8}, + {{"END-SESSION", 11},0}, + {{"QUERY-VOICEPRINT", 16},0}, + {{"DELETE-VOICEPRINT", 17},0}, + {{"VERIFY", 6},6}, + {{"VERIFY-FROM-BUFFER", 18},7}, + {{"VERIFY-ROLLBACK", 15},7}, + {{"STOP", 4},2}, + {{"CLEAR-BUFFER", 12},0}, + {{"START-INPUT-TIMERS", 18},6}, + {{"GET-INTERMEDIATE-RESULT",23},4}, +}; + +/** String table of MRCP verifier events (mrcp_verifier_event_id) */ +static const apt_str_table_item_t verifier_event_string_table[] = { + {{"START-OF-INPUT", 14},0}, + {{"VERIFICATION-COMPLETE",21},0}, +}; + +static APR_INLINE const apt_str_table_item_t* verifier_method_string_table_get(mrcp_version_e version) +{ + return verifier_method_string_table; +} + +static APR_INLINE const apt_str_table_item_t* verifier_event_string_table_get(mrcp_version_e version) +{ + return verifier_event_string_table; +} + + +/** Create MRCP verifier resource */ +MRCP_DECLARE(mrcp_resource_t*) mrcp_verifier_resource_create(apr_pool_t *pool) +{ + mrcp_resource_t *resource = mrcp_resource_create(pool); + + resource->method_count = VERIFIER_METHOD_COUNT; + resource->event_count = VERIFIER_EVENT_COUNT; + resource->get_method_str_table = verifier_method_string_table_get; + resource->get_event_str_table = verifier_event_string_table_get; + resource->get_resource_header_vtable = mrcp_verifier_header_vtable_get; + return resource; +} diff --git a/libs/unimrcp/libs/mrcpv2-transport/include/mrcp_client_connection.h b/libs/unimrcp/libs/mrcpv2-transport/include/mrcp_client_connection.h index 29181692cc..b8e83f5a5d 100644 --- a/libs/unimrcp/libs/mrcpv2-transport/include/mrcp_client_connection.h +++ b/libs/unimrcp/libs/mrcpv2-transport/include/mrcp_client_connection.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_client_connection.h 1792 2011-01-10 21:08:52Z achaloyan $ */ -#ifndef __MRCP_CLIENT_CONNECTION_H__ -#define __MRCP_CLIENT_CONNECTION_H__ +#ifndef MRCP_CLIENT_CONNECTION_H +#define MRCP_CLIENT_CONNECTION_H /** * @file mrcp_client_connection.h @@ -29,12 +31,14 @@ APT_BEGIN_EXTERN_C /** * Create connection agent. + * @param id the identifier of the 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, + const char *id, + apr_size_t max_connection_count, apt_bool_t offer_new_connection, apr_pool_t *pool); @@ -74,20 +78,51 @@ MRCP_DECLARE(void) mrcp_client_connection_agent_handler_set( * @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); + mrcp_connection_agent_t *agent, + const mrcp_resource_factory_t *resource_factory); +/** + * Set rx buffer size. + * @param agent the agent to set buffer size for + * @param size the size of rx buffer to set + */ +MRCP_DECLARE(void) mrcp_client_connection_rx_size_set( + mrcp_connection_agent_t *agent, + apr_size_t size); + +/** + * Set tx buffer size. + * @param agent the agent to set buffer size for + * @param size the size of the rx buffer to set + */ +MRCP_DECLARE(void) mrcp_client_connection_tx_size_set( + mrcp_connection_agent_t *agent, + apr_size_t size); +/** + * Set request timeout. + * @param agent the agent to set timeout for + * @param timeout the timeout to set + */ +MRCP_DECLARE(void) mrcp_client_connection_timeout_set( + mrcp_connection_agent_t *agent, + apr_size_t timeout); /** * 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); +MRCP_DECLARE(apt_task_t*) mrcp_client_connection_agent_task_get(const 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); +MRCP_DECLARE(void*) mrcp_client_connection_agent_object_get(const mrcp_connection_agent_t *agent); + +/** + * Get string identifier. + * @param agent the agent to get identifier of + */ +MRCP_DECLARE(const char*) mrcp_client_connection_agent_id_get(const mrcp_connection_agent_t *agent); /** @@ -96,21 +131,28 @@ MRCP_DECLARE(void*) mrcp_client_connection_agent_object_get(mrcp_connection_agen * @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); +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); +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); +MRCP_DECLARE(apt_bool_t) mrcp_client_control_channel_modify( + mrcp_control_channel_t *channel, + mrcp_control_descriptor_t *descriptor); /** * Remove MRCPv2 control channel. @@ -131,7 +173,14 @@ MRCP_DECLARE(apt_bool_t) mrcp_client_control_channel_destroy(mrcp_control_channe */ MRCP_DECLARE(apt_bool_t) mrcp_client_control_message_send(mrcp_control_channel_t *channel, mrcp_message_t *message); +/** + * Set the logger object. + * @param channel the control channel to set the object for + * @param log_obj the object to set + */ +MRCP_DECLARE(void) mrcp_client_control_channel_log_obj_set(mrcp_control_channel_t *channel, void *log_obj); + APT_END_EXTERN_C -#endif /*__MRCP_CLIENT_CONNECTION_H__*/ +#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 index 82d44ea865..08031c3a55 100644 --- a/libs/unimrcp/libs/mrcpv2-transport/include/mrcp_connection.h +++ b/libs/unimrcp/libs/mrcpv2-transport/include/mrcp_connection.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_connection.h 1710 2010-05-24 17:36:19Z achaloyan $ */ -#ifndef __MRCP_CONNECTION_H__ -#define __MRCP_CONNECTION_H__ +#ifndef MRCP_CONNECTION_H +#define MRCP_CONNECTION_H /** * @file mrcp_connection.h @@ -50,6 +52,9 @@ struct mrcp_connection_t { apt_str_t remote_ip; /** String identifier used for traces */ const char *id; + /** Transparently dump whatever received/sent on transport layer, + if verbose is set to TRUE (default) */ + apt_bool_t verbose; /** Reference count */ apr_size_t access_count; @@ -62,22 +67,24 @@ struct mrcp_connection_t { apr_hash_t *channel_table; /** Rx buffer */ - char rx_buffer[MRCP_STREAM_BUFFER_SIZE]; + char *rx_buffer; + /** Rx buffer size */ + apr_size_t rx_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 */ + char *tx_buffer; + /** Tx buffer size */ + apr_size_t tx_buffer_size; + /** MRCP generator to generate MRCP messages into tx stream */ mrcp_generator_t *generator; }; /** Create MRCP connection. */ -mrcp_connection_t* mrcp_connection_create(void); +mrcp_connection_t* mrcp_connection_create(); /** Destroy MRCP connection. */ void mrcp_connection_destroy(mrcp_connection_t *connection); @@ -86,7 +93,7 @@ void mrcp_connection_destroy(mrcp_connection_t *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); +mrcp_control_channel_t* mrcp_connection_channel_find(const 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); @@ -96,4 +103,4 @@ apt_bool_t mrcp_connection_disconnect_raise(mrcp_connection_t *connection, const APT_END_EXTERN_C -#endif /*__MRCP_CONNECTION_H__*/ +#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 index c7a02c0419..e61c66cafa 100644 --- a/libs/unimrcp/libs/mrcpv2-transport/include/mrcp_connection_types.h +++ b/libs/unimrcp/libs/mrcpv2-transport/include/mrcp_connection_types.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_connection_types.h 1792 2011-01-10 21:08:52Z achaloyan $ */ -#ifndef __MRCP_CONNECTION_TYPES_H__ -#define __MRCP_CONNECTION_TYPES_H__ +#ifndef MRCP_CONNECTION_TYPES_H +#define MRCP_CONNECTION_TYPES_H /** * @file mrcp_connection_types.h @@ -24,6 +26,7 @@ #include #include "apt_string.h" +#include "apt_timer_queue.h" #include "mrcp_types.h" APT_BEGIN_EXTERN_C @@ -63,10 +66,16 @@ struct mrcp_control_channel_t { mrcp_connection_agent_t *agent; /** MRCPv2 (shared) connection */ mrcp_connection_t *connection; + /** Request sent to the server and waiting for a response */ + mrcp_message_t *active_request; + /** Timer used for request timeouts */ + apt_timer_t *request_timer; /** Indicate removed connection (safe to destroy) */ apt_bool_t removed; /** External object associated with the channel */ void *obj; + /** External logger object associated with the channel */ + void *log_obj; /** Pool to allocate memory from */ apr_pool_t *pool; /** Channel identifier (id at resource) */ @@ -125,4 +134,4 @@ static APR_INLINE apt_bool_t mrcp_connection_message_receive( APT_END_EXTERN_C -#endif /*__MRCP_CONNECTION_TYPES_H__*/ +#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 index b5dbc44c5f..40535d4b5b 100644 --- a/libs/unimrcp/libs/mrcpv2-transport/include/mrcp_control_descriptor.h +++ b/libs/unimrcp/libs/mrcpv2-transport/include/mrcp_control_descriptor.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_control_descriptor.h 1710 2010-05-24 17:36:19Z achaloyan $ */ -#ifndef __MRCP_CONTROL_DESCRIPTOR_H__ -#define __MRCP_CONTROL_DESCRIPTOR_H__ +#ifndef MRCP_CONTROL_DESCRIPTOR_H +#define MRCP_CONTROL_DESCRIPTOR_H /** * @file mrcp_control_descriptor.h @@ -110,7 +112,7 @@ MRCP_DECLARE(mrcp_control_descriptor_t*) mrcp_control_answer_create(mrcp_control MRCP_DECLARE(void) mrcp_cmid_add(apr_array_header_t *cmid_arr, apr_size_t cmid); /** Find cmid in cmid_arr */ -MRCP_DECLARE(apt_bool_t) mrcp_cmid_find(apr_array_header_t *cmid_arr, apr_size_t cmid); +MRCP_DECLARE(apt_bool_t) mrcp_cmid_find(const apr_array_header_t *cmid_arr, apr_size_t cmid); /** Get MRCP protocol transport name by identifier */ MRCP_DECLARE(const apt_str_t*) mrcp_proto_get(mrcp_proto_type_e proto); @@ -142,4 +144,4 @@ MRCP_DECLARE(mrcp_connection_type_e) mrcp_connection_type_find(const apt_str_t * APT_END_EXTERN_C -#endif /*__MRCP_CONTROL_DESCRIPTOR_H__*/ +#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 index c72b9c5ef8..a5ee18c1a2 100644 --- a/libs/unimrcp/libs/mrcpv2-transport/include/mrcp_server_connection.h +++ b/libs/unimrcp/libs/mrcpv2-transport/include/mrcp_server_connection.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_server_connection.h 1721 2010-06-01 05:45:46Z achaloyan $ */ -#ifndef __MRCP_SERVER_CONNECTION_H__ -#define __MRCP_SERVER_CONNECTION_H__ +#ifndef MRCP_SERVER_CONNECTION_H +#define MRCP_SERVER_CONNECTION_H /** * @file mrcp_server_connection.h @@ -29,13 +31,15 @@ APT_BEGIN_EXTERN_C /** * Create connection agent. - * @param listen_ip the listen IP address - * @param listen_port the listen port + * @param id the identifier of the engine + * @param listen_ip the IP address to listen on + * @param listen_port the port to listen on * @param max_connection_count the number of max MRCPv2 connections - * @param force_new_connection the connection establishment policy in o/a + * @param force_new_connection the policy used in o/a for connection establishment * @param pool the pool to allocate memory from */ MRCP_DECLARE(mrcp_connection_agent_t*) mrcp_server_connection_agent_create( + const char *id, const char *listen_ip, apr_port_t listen_port, apr_size_t max_connection_count, @@ -77,20 +81,44 @@ MRCP_DECLARE(void) mrcp_server_connection_agent_handler_set( * @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); + mrcp_connection_agent_t *agent, + const mrcp_resource_factory_t *resource_factory); + +/** + * Set rx buffer size. + * @param agent the agent to set buffer size for + * @param size the size of rx buffer to set + */ +MRCP_DECLARE(void) mrcp_server_connection_rx_size_set( + mrcp_connection_agent_t *agent, + apr_size_t size); + +/** + * Set tx buffer size. + * @param agent the agent to set buffer size for + * @param size the size of the rx buffer to set + */ +MRCP_DECLARE(void) mrcp_server_connection_tx_size_set( + mrcp_connection_agent_t *agent, + apr_size_t size); /** * 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); +MRCP_DECLARE(apt_task_t*) mrcp_server_connection_agent_task_get(const 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); +MRCP_DECLARE(void*) mrcp_server_connection_agent_object_get(const mrcp_connection_agent_t *agent); + +/** + * Get string identifier. + * @param agent the agent to get identifier of + */ +MRCP_DECLARE(const char*) mrcp_server_connection_agent_id_get(const mrcp_connection_agent_t *agent); /** @@ -99,21 +127,28 @@ MRCP_DECLARE(void*) mrcp_server_connection_agent_object_get(mrcp_connection_agen * @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); +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); +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); +MRCP_DECLARE(apt_bool_t) mrcp_server_control_channel_modify( + mrcp_control_channel_t *channel, + mrcp_control_descriptor_t *descriptor); /** * Remove MRCPv2 control channel. @@ -137,4 +172,4 @@ MRCP_DECLARE(apt_bool_t) mrcp_server_control_message_send(mrcp_control_channel_t APT_END_EXTERN_C -#endif /*__MRCP_SERVER_CONNECTION_H__*/ +#endif /* MRCP_SERVER_CONNECTION_H */ diff --git a/libs/unimrcp/libs/mrcpv2-transport/mrcpv2transport.2008.vcproj b/libs/unimrcp/libs/mrcpv2-transport/mrcpv2transport.2008.vcproj deleted file mode 100644 index 87ed8335a3..0000000000 --- a/libs/unimrcp/libs/mrcpv2-transport/mrcpv2transport.2008.vcproj +++ /dev/null @@ -1,301 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/unimrcp/libs/mrcpv2-transport/mrcpv2transport.2010.vcxproj b/libs/unimrcp/libs/mrcpv2-transport/mrcpv2transport.2010.vcxproj deleted file mode 100644 index 33ed618305..0000000000 --- a/libs/unimrcp/libs/mrcpv2-transport/mrcpv2transport.2010.vcxproj +++ /dev/null @@ -1,124 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - mrcpv2transport - {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA} - mrcpv2transport - Win32Proj - - - - StaticLibrary - Unicode - true - - - StaticLibrary - Unicode - - - StaticLibrary - Unicode - true - - - StaticLibrary - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - - - - APT_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;%(PreprocessorDefinitions) - - - - - X64 - - - APT_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;%(PreprocessorDefinitions) - ProgramDatabase - - - - - APT_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;%(PreprocessorDefinitions) - - - - - X64 - - - APT_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/libs/unimrcp/libs/mrcpv2-transport/mrcpv2transport.2010.vcxproj.filters b/libs/unimrcp/libs/mrcpv2-transport/mrcpv2transport.2010.vcxproj.filters deleted file mode 100644 index 452f77e19d..0000000000 --- a/libs/unimrcp/libs/mrcpv2-transport/mrcpv2transport.2010.vcxproj.filters +++ /dev/null @@ -1,44 +0,0 @@ - - - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {a92d3b8c-d54d-416c-b458-dc57ac24d2e9} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - - - include - - - include - - - include - - - include - - - include - - - - - src - - - src - - - src - - - src - - - \ No newline at end of file diff --git a/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_client_connection.c b/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_client_connection.c index 94b25bad26..5d67271fa8 100644 --- a/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_client_connection.c +++ b/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_client_connection.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_client_connection.c 1792 2011-01-10 21:08:52Z achaloyan $ */ #include "mrcp_connection.h" @@ -20,27 +22,21 @@ #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_poller_task.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; + apr_pool_t *pool; + apt_poller_task_t *task; + const mrcp_resource_factory_t *resource_factory; - mrcp_resource_factory_t *resource_factory; + apt_obj_list_t *connection_list; - 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; + apr_uint32_t request_timeout; + apt_bool_t offer_new_connection; + apr_size_t tx_buffer_size; + apr_size_t rx_buffer_size; void *obj; const mrcp_connection_event_vtable_t *vtable; @@ -50,8 +46,7 @@ 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_SEND_MESSAGE } connection_task_msg_type_e; typedef struct connection_task_msg_t connection_task_msg_t; @@ -64,79 +59,75 @@ struct connection_task_msg_t { }; -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); +static apt_bool_t mrcp_client_agent_msg_process(apt_task_t *task, apt_task_msg_t *task_msg); +static apt_bool_t mrcp_client_poller_signal_process(void *obj, const apr_pollfd_t *descriptor); +static void mrcp_client_timer_proc(apt_timer_t *timer, void *obj); /** Create connection agent. */ MRCP_DECLARE(mrcp_connection_agent_t*) mrcp_client_connection_agent_create( + const char *id, apr_size_t max_connection_count, apt_bool_t offer_new_connection, apr_pool_t *pool) { + apt_task_t *task; apt_task_vtable_t *vtable; + apt_task_msg_pool_t *msg_pool; mrcp_connection_agent_t *agent; - apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create "MRCPV2_CONNECTION_TASK_NAME" [%"APR_SIZE_T_FMT"]",max_connection_count); + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create MRCPv2 Agent [%s] [%"APR_SIZE_T_FMT"]", + id, 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->request_timeout = 0; agent->offer_new_connection = offer_new_connection; + agent->rx_buffer_size = MRCP_STREAM_BUFFER_SIZE; + agent->tx_buffer_size = MRCP_STREAM_BUFFER_SIZE; - agent->task = apt_task_create(agent,NULL,pool); + msg_pool = apt_task_msg_pool_create_dynamic(sizeof(connection_task_msg_t),pool); + + agent->task = apt_poller_task_create( + max_connection_count, + mrcp_client_poller_signal_process, + agent, + msg_pool, + pool); if(!agent->task) { return NULL; } - apt_task_name_set(agent->task,MRCPV2_CONNECTION_TASK_NAME); - vtable = apt_task_vtable_get(agent->task); + task = apt_poller_task_base_get(agent->task); + if(task) { + apt_task_name_set(task,id); + } + + vtable = apt_poller_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; + vtable->process_msg = mrcp_client_agent_msg_process; } - apt_task_auto_ready_set(agent->task,FALSE); 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); + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy MRCPv2 Agent [%s]", + mrcp_client_connection_agent_id_get(agent)); + return apt_poller_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); + return apt_poller_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); + return apt_poller_task_terminate(agent->task); } /** Set connection event handler. */ @@ -151,24 +142,61 @@ MRCP_DECLARE(void) mrcp_client_connection_agent_handler_set( /** Set MRCP resource factory */ MRCP_DECLARE(void) mrcp_client_connection_resource_factory_set( - mrcp_connection_agent_t *agent, - mrcp_resource_factory_t *resource_factroy) + mrcp_connection_agent_t *agent, + const mrcp_resource_factory_t *resource_factroy) { agent->resource_factory = resource_factroy; } +/** Set rx buffer size */ +MRCP_DECLARE(void) mrcp_client_connection_rx_size_set( + mrcp_connection_agent_t *agent, + apr_size_t size) +{ + if(size < MRCP_STREAM_BUFFER_SIZE) { + size = MRCP_STREAM_BUFFER_SIZE; + } + agent->rx_buffer_size = size; +} + +/** Set tx buffer size */ +MRCP_DECLARE(void) mrcp_client_connection_tx_size_set( + mrcp_connection_agent_t *agent, + apr_size_t size) +{ + if(size < MRCP_STREAM_BUFFER_SIZE) { + size = MRCP_STREAM_BUFFER_SIZE; + } + agent->tx_buffer_size = size; +} + +/** Set request timeout */ +MRCP_DECLARE(void) mrcp_client_connection_timeout_set( + mrcp_connection_agent_t *agent, + apr_size_t timeout) +{ + agent->request_timeout = (apr_uint32_t)timeout; +} + /** Get task */ -MRCP_DECLARE(apt_task_t*) mrcp_client_connection_agent_task_get(mrcp_connection_agent_t *agent) +MRCP_DECLARE(apt_task_t*) mrcp_client_connection_agent_task_get(const mrcp_connection_agent_t *agent) { - return agent->task; + return apt_poller_task_base_get(agent->task); } /** Get external object */ -MRCP_DECLARE(void*) mrcp_client_connection_agent_object_get(mrcp_connection_agent_t *agent) +MRCP_DECLARE(void*) mrcp_client_connection_agent_object_get(const mrcp_connection_agent_t *agent) { return agent->obj; } +/** Get string identifier */ +MRCP_DECLARE(const char*) mrcp_client_connection_agent_id_get(const mrcp_connection_agent_t *agent) +{ + apt_task_t *task = apt_poller_task_base_get(agent->task); + return apt_task_name_get(task); +} + /** 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) @@ -176,12 +204,27 @@ MRCP_DECLARE(mrcp_control_channel_t*) mrcp_client_control_channel_create(mrcp_co mrcp_control_channel_t *channel = apr_palloc(pool,sizeof(mrcp_control_channel_t)); channel->agent = agent; channel->connection = NULL; + channel->active_request = NULL; + channel->request_timer = NULL; channel->removed = FALSE; channel->obj = obj; + channel->log_obj = NULL; channel->pool = pool; + + channel->request_timer = apt_poller_task_timer_create( + agent->task, + mrcp_client_timer_proc, + channel, + pool); return channel; } +/** Set the logger object */ +MRCP_DECLARE(void) mrcp_client_control_channel_log_obj_set(mrcp_control_channel_t *channel, void *log_obj) +{ + channel->log_obj = log_obj; +} + /** Destroy MRCPv2 control channel */ MRCP_DECLARE(apt_bool_t) mrcp_client_control_channel_destroy(mrcp_control_channel_t *channel) { @@ -194,6 +237,7 @@ MRCP_DECLARE(apt_bool_t) mrcp_client_control_channel_destroy(mrcp_control_channe return TRUE; } +/** Signal task message */ static apt_bool_t mrcp_client_control_message_signal( connection_task_msg_type_e type, mrcp_connection_agent_t *agent, @@ -201,22 +245,18 @@ static apt_bool_t mrcp_client_control_message_signal( 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; + apt_task_t *task = apt_poller_task_base_get(agent->task); + apt_task_msg_t *task_msg = apt_task_msg_get(task); + if(task_msg) { + connection_task_msg_t *msg = (connection_task_msg_t*)task_msg->data; + msg->type = type; + msg->agent = agent; + msg->channel = channel; + msg->descriptor = descriptor; + msg->message = message; + apt_task_msg_signal(task,task_msg); } - return status; + return TRUE; } /** Add MRCPv2 control channel */ @@ -247,6 +287,7 @@ static mrcp_connection_t* mrcp_client_agent_connection_create(mrcp_connection_ag { char *local_ip = NULL; char *remote_ip = NULL; + apt_pollset_t *pollset = apt_poller_task_pollset_get(agent->task); mrcp_connection_t *connection = mrcp_connection_create(); apr_sockaddr_info_get(&connection->r_sockaddr,descriptor->ip.buf,APR_INET,descriptor->port,0,connection->pool); @@ -287,7 +328,8 @@ static mrcp_connection_t* mrcp_client_agent_connection_create(mrcp_connection_ag 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) { + if(apt_pollset_add(pollset, &connection->sock_pfd) != TRUE) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Add to Pollset %s",connection->id); apr_socket_close(connection->sock); mrcp_connection_destroy(connection); return NULL; @@ -296,8 +338,23 @@ static mrcp_connection_t* mrcp_client_agent_connection_create(mrcp_connection_ag 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); + + connection->tx_buffer_size = agent->tx_buffer_size; + connection->tx_buffer = apr_palloc(connection->pool,connection->tx_buffer_size+1); + + connection->rx_buffer_size = agent->rx_buffer_size; + connection->rx_buffer = apr_palloc(connection->pool,connection->rx_buffer_size+1); + apt_text_stream_init(&connection->rx_stream,connection->rx_buffer,connection->rx_buffer_size); + + if(apt_log_masking_get() != APT_LOG_MASKING_NONE) { + connection->verbose = FALSE; + mrcp_parser_verbose_set(connection->parser,TRUE); + mrcp_generator_verbose_set(connection->generator,TRUE); + } + return connection; } @@ -324,12 +381,17 @@ static mrcp_connection_t* mrcp_client_agent_connection_find(mrcp_connection_agen static apt_bool_t mrcp_client_agent_connection_remove(mrcp_connection_agent_t *agent, mrcp_connection_t *connection) { + apt_pollset_t *pollset = apt_poller_task_pollset_get(agent->task); + /* 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(pollset) { + apt_pollset_remove(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); @@ -338,7 +400,6 @@ static apt_bool_t mrcp_client_agent_connection_remove(mrcp_connection_agent_t *a 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) { @@ -367,20 +428,20 @@ static apt_bool_t mrcp_client_agent_channel_modify(mrcp_connection_agent_t *agen /* 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"); + apt_obj_log(APT_LOG_MARK,APT_PRIO_WARNING,channel->log_obj,"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"); + apt_obj_log(APT_LOG_MARK,APT_PRIO_WARNING,channel->log_obj,"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]", + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,channel->log_obj,"Add Control Channel <%s> %s [%d]", channel->identifier.buf, connection->id, apr_hash_count(connection->channel_table)); @@ -404,7 +465,7 @@ static apt_bool_t mrcp_client_agent_channel_remove(mrcp_connection_agent_t *agen 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]", + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,channel->log_obj,"Remove Control Channel <%s> [%d]", channel->identifier.buf, apr_hash_count(connection->channel_table)); if(!connection->access_count) { @@ -419,71 +480,124 @@ static apt_bool_t mrcp_client_agent_channel_remove(mrcp_connection_agent_t *agen return mrcp_control_channel_remove_respond(agent->vtable,channel,TRUE); } +static apt_bool_t mrcp_client_agent_request_cancel(mrcp_connection_agent_t *agent, mrcp_control_channel_t *channel, mrcp_message_t *message) +{ + mrcp_message_t *response; + apt_obj_log(APT_LOG_MARK,APT_PRIO_WARNING,channel->log_obj,"Cancel MRCP Request <%s@%s> [%d]", + MRCP_MESSAGE_SIDRES(message), + message->start_line.request_id); + response = mrcp_response_create(message,message->pool); + response->start_line.status_code = MRCP_STATUS_CODE_METHOD_FAILED; + return mrcp_connection_message_receive(agent->vtable,channel,response); +} + +static apt_bool_t mrcp_client_agent_disconnect_raise(mrcp_connection_agent_t *agent, mrcp_connection_t *connection) +{ + mrcp_control_channel_t *channel; + void *val; + apr_hash_index_t *it = apr_hash_first(connection->pool,connection->channel_table); + /* walk through the list of channels and raise disconnect event for them */ + for(; it; it = apr_hash_next(it)) { + apr_hash_this(it,NULL,NULL,&val); + channel = val; + if(!channel) continue; + + if(channel->active_request) { + mrcp_client_agent_request_cancel(channel->agent,channel,channel->active_request); + channel->active_request = NULL; + if(channel->request_timer) { + apt_timer_kill(channel->request_timer); + } + } + else if(agent->vtable->on_disconnect){ + agent->vtable->on_disconnect(channel); + } + } + return 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_status_e result; + apt_text_stream_t stream; + apt_message_status_e result; if(!connection || !connection->sock) { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No MRCPv2 Connection"); + apt_obj_log(APT_LOG_MARK,APT_PRIO_WARNING,channel->log_obj,"Null MRCPv2 Connection "APT_SIDRES_FMT,MRCP_MESSAGE_SIDRES(message)); + mrcp_client_agent_request_cancel(agent,channel,message); 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_STATUS_INVALID) { - stream->text.length = stream->pos - stream->text.buf; - *stream->pos = '\0'; + apt_text_stream_init(&stream,connection->tx_buffer,connection->tx_buffer_size); + result = mrcp_generator_run(connection->generator,message,&stream); + if(result != APT_MESSAGE_STATUS_INVALID) { + 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", + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,channel->log_obj,"Send MRCPv2 Stream %s [%"APR_SIZE_T_FMT" 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) { + stream.text.length, + connection->verbose == TRUE ? stream.text.length : 0, + 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"); + apt_obj_log(APT_LOG_MARK,APT_PRIO_WARNING,channel->log_obj,"Failed to Send MRCPv2 Stream %s", + connection->id); } } else { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Generate MRCPv2 Stream"); + apt_obj_log(APT_LOG_MARK,APT_PRIO_WARNING,channel->log_obj,"Failed to Generate MRCPv2 Stream %s", + connection->id); } } - while(result == MRCP_STREAM_STATUS_INCOMPLETE); + while(result == APT_MESSAGE_STATUS_INCOMPLETE); - 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); + if(status == TRUE) { + channel->active_request = message; + if(channel->request_timer && agent->request_timeout) { + apt_timer_set(channel->request_timer,agent->request_timeout); + } } - return TRUE; + else { + mrcp_client_agent_request_cancel(agent,channel,message); + } + return status; } -static apt_bool_t mrcp_client_message_handler(void *obj, mrcp_message_t *message, mrcp_stream_status_e status) +static apt_bool_t mrcp_client_message_handler(mrcp_connection_t *connection, mrcp_message_t *message, apt_message_status_e status) { - if(status == MRCP_STREAM_STATUS_COMPLETE) { + if(status == APT_MESSAGE_STATUS_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; + if(message->start_line.message_type == MRCP_MESSAGE_TYPE_RESPONSE) { + if(!channel->active_request || + channel->active_request->start_line.request_id != message->start_line.request_id) { + apt_obj_log(APT_LOG_MARK,APT_PRIO_WARNING,channel->log_obj,"Unexpected MRCP Response "APT_SIDRES_FMT" [%d]", + MRCP_MESSAGE_SIDRES(message), + message->start_line.request_id); + return FALSE; + } + if(channel->request_timer) { + apt_timer_kill(channel->request_timer); + } + channel->active_request = NULL; + } + 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, + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Find Channel "APT_SIDRES_FMT" in Connection %s [%d]", + MRCP_MESSAGE_SIDRES(message), connection->id, apr_hash_count(connection->channel_table)); } @@ -491,151 +605,104 @@ static apt_bool_t mrcp_client_message_handler(void *obj, mrcp_message_t *message return TRUE; } -static apt_bool_t mrcp_client_agent_messsage_receive(mrcp_connection_agent_t *agent, mrcp_connection_t *connection) +/* Receive MRCP message through TCP/MRCPv2 connection */ +static apt_bool_t mrcp_client_poller_signal_process(void *obj, const apr_pollfd_t *descriptor) { + mrcp_connection_agent_t *agent = obj; + mrcp_connection_t *connection = descriptor->client_data; apr_status_t status; apr_size_t offset; apr_size_t length; apt_text_stream_t *stream; + mrcp_message_t *message; + apt_message_status_e msg_status; 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; + length = connection->rx_buffer_size - offset; + status = apr_socket_recv(connection->sock,stream->pos,&length); if(status == APR_EOF || length == 0) { + apt_pollset_t *pollset = apt_poller_task_pollset_get(agent->task); apt_log(APT_LOG_MARK,APT_PRIO_INFO,"TCP/MRCPv2 Peer Disconnected %s",connection->id); - apt_pollset_remove(agent->pollset,&connection->sock_pfd); + if(pollset) { + apt_pollset_remove(pollset,&connection->sock_pfd); + } apr_socket_close(connection->sock); connection->sock = NULL; - mrcp_connection_disconnect_raise(connection,agent->vtable); + mrcp_client_agent_disconnect_raise(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); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive MRCPv2 Stream %s [%"APR_SIZE_T_FMT" bytes]\n%.*s", + connection->id, + length, + connection->verbose == TRUE ? length : 0, + stream->pos); /* reset pos */ apt_text_stream_reset(stream); - /* walk through the stream parsing MRCP 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; + msg_status = mrcp_parser_run(connection->parser,stream,&message); + if(mrcp_client_message_handler(connection,message,msg_status) == FALSE) { + return FALSE; } } - while(running == TRUE); - return status; + while(apt_text_is_eos(stream) == FALSE); + + /* scroll remaining stream */ + apt_text_stream_scroll(stream); + return TRUE; } -static apt_bool_t mrcp_client_agent_task_run(apt_task_t *task) +/* Process task message */ +static apt_bool_t mrcp_client_agent_msg_process(apt_task_t *task, apt_task_msg_t *task_msg) { - 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; + apt_poller_task_t *poller_task = apt_task_object_get(task); + mrcp_connection_agent_t *agent = apt_poller_task_object_get(poller_task); + connection_task_msg_t *msg = (connection_task_msg_t*) task_msg->data; + + 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; } - 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; - } - - /* explicitly indicate task is ready to process messages */ - apt_task_ready(agent->task); - - 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) +/* Timer callback */ +static void mrcp_client_timer_proc(apt_timer_t *timer, void *obj) { - 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"); + mrcp_control_channel_t *channel = obj; + if(!channel) { + return; + } + + if(channel->request_timer == timer) { + if(channel->active_request) { + mrcp_client_agent_request_cancel(channel->agent,channel,channel->active_request); + channel->active_request = NULL; } } - return status; } diff --git a/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_connection.c b/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_connection.c index d174cb78d0..29a06abd87 100644 --- a/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_connection.c +++ b/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_connection.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_connection.c 1710 2010-05-24 17:36:19Z achaloyan $ */ #include "mrcp_connection.h" @@ -32,13 +34,17 @@ mrcp_connection_t* mrcp_connection_create() connection->r_sockaddr = NULL; connection->sock = NULL; connection->id = NULL; + connection->verbose = TRUE; 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; + connection->rx_buffer = NULL; + connection->rx_buffer_size = 0; + connection->tx_buffer = NULL; + connection->tx_buffer_size = 0; + return connection; } @@ -60,7 +66,7 @@ apt_bool_t mrcp_connection_channel_add(mrcp_connection_t *connection, mrcp_contr return TRUE; } -mrcp_control_channel_t* mrcp_connection_channel_find(mrcp_connection_t *connection, const apt_str_t *identifier) +mrcp_control_channel_t* mrcp_connection_channel_find(const mrcp_connection_t *connection, const apt_str_t *identifier) { if(!connection || !identifier) { return NULL; diff --git a/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_control_descriptor.c b/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_control_descriptor.c index de0de51aa9..0f8fd8b1f4 100644 --- a/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_control_descriptor.c +++ b/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_control_descriptor.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_control_descriptor.c 1710 2010-05-24 17:36:19Z achaloyan $ */ #include "apt_string_table.h" @@ -133,7 +135,7 @@ MRCP_DECLARE(void) mrcp_cmid_add(apr_array_header_t *cmid_arr, apr_size_t cmid) } /** Find cmid in cmid_arr */ -MRCP_DECLARE(apt_bool_t) mrcp_cmid_find(apr_array_header_t *cmid_arr, apr_size_t cmid) +MRCP_DECLARE(apt_bool_t) mrcp_cmid_find(const apr_array_header_t *cmid_arr, apr_size_t cmid) { int i; for(i=0; inelts; i++) { diff --git a/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_server_connection.c b/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_server_connection.c index 0b370a6498..f85a3813cd 100644 --- a/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_server_connection.c +++ b/libs/unimrcp/libs/mrcpv2-transport/src/mrcp_server_connection.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_server_connection.c 1792 2011-01-10 21:08:52Z achaloyan $ */ #include "mrcp_connection.h" @@ -20,33 +22,27 @@ #include "mrcp_resource_factory.h" #include "mrcp_message.h" #include "apt_text_stream.h" -#include "apt_task.h" +#include "apt_poller_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; + apr_pool_t *pool; + apt_poller_task_t *task; + const mrcp_resource_factory_t *resource_factory; - apt_obj_list_t *connection_list; - mrcp_connection_t *null_connection; + apt_obj_list_t *connection_list; + mrcp_connection_t *null_connection; - apt_bool_t force_new_connection; - apr_size_t max_connection_count; + apt_bool_t force_new_connection; + apr_size_t tx_buffer_size; + apr_size_t rx_buffer_size; - 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; + apr_sockaddr_t *sockaddr; + apr_socket_t *listen_sock; + apr_pollfd_t listen_sock_pfd; void *obj; const mrcp_connection_event_vtable_t *vtable; @@ -56,8 +52,7 @@ 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_SEND_MESSAGE } connection_task_msg_type_e; typedef struct connection_task_msg_t connection_task_msg_t; @@ -69,94 +64,125 @@ struct connection_task_msg_t { 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); +static apt_bool_t mrcp_server_agent_on_destroy(apt_task_t *task); +static apt_bool_t mrcp_server_agent_msg_process(apt_task_t *task, apt_task_msg_t *task_msg); +static apt_bool_t mrcp_server_poller_signal_process(void *obj, const apr_pollfd_t *descriptor); + +static apt_bool_t mrcp_server_agent_listening_socket_create(mrcp_connection_agent_t *agent); +static void mrcp_server_agent_listening_socket_destroy(mrcp_connection_agent_t *agent); + /** Create connection agent */ MRCP_DECLARE(mrcp_connection_agent_t*) mrcp_server_connection_agent_create( + const char *id, 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_t *task; apt_task_vtable_t *vtable; + apt_task_msg_pool_t *msg_pool; 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 [%"APR_SIZE_T_FMT"]", - listen_ip,listen_port,max_connection_count); + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create MRCPv2 Agent [%s] %s:%hu [%"APR_SIZE_T_FMT"]", + id,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; + agent->rx_buffer_size = MRCP_STREAM_BUFFER_SIZE; + agent->tx_buffer_size = MRCP_STREAM_BUFFER_SIZE; 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); + msg_pool = apt_task_msg_pool_create_dynamic(sizeof(connection_task_msg_t),pool); + + agent->task = apt_poller_task_create( + max_connection_count + 1, + mrcp_server_poller_signal_process, + agent, + msg_pool, + 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; + task = apt_poller_task_base_get(agent->task); + if(task) { + apt_task_name_set(task,id); } - apt_task_auto_ready_set(agent->task,FALSE); - agent->msg_queue = apt_cyclic_queue_create(CYCLIC_QUEUE_DEFAULT_SIZE); - apr_thread_mutex_create(&agent->guard,APR_THREAD_MUTEX_UNNESTED,pool); + vtable = apt_poller_task_vtable_get(agent->task); + if(vtable) { + vtable->destroy = mrcp_server_agent_on_destroy; + vtable->process_msg = mrcp_server_agent_msg_process; + } agent->connection_list = NULL; agent->null_connection = NULL; + + if(mrcp_server_agent_listening_socket_create(agent) == TRUE) { + /* add listening socket to pollset */ + apt_pollset_t *pollset = apt_poller_task_pollset_get(agent->task); + 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(pollset, &agent->listen_sock_pfd) != TRUE) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Add Listening Socket to Pollset"); + mrcp_server_agent_listening_socket_destroy(agent); + } + } + else { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Listening Socket"); + } return agent; } -/** Virtual destroy handler. */ -static apt_bool_t mrcp_server_agent_task_on_destroy(apt_task_t *task) +static apt_bool_t mrcp_server_agent_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; + apt_poller_task_t *poller_task = apt_task_object_get(task); + mrcp_connection_agent_t *agent = apt_poller_task_object_get(poller_task); + + apt_pollset_t *pollset = apt_poller_task_pollset_get(poller_task); + if(pollset) { + apt_pollset_remove(pollset,&agent->listen_sock_pfd); } + mrcp_server_agent_listening_socket_destroy(agent); + + apt_poller_task_cleanup(poller_task); 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); + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy MRCPv2 Agent [%s]", + mrcp_server_connection_agent_id_get(agent)); + return apt_poller_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); + return apt_poller_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); + return apt_poller_task_terminate(agent->task); } /** Set connection event handler. */ @@ -172,31 +198,64 @@ MRCP_DECLARE(void) mrcp_server_connection_agent_handler_set( /** Set MRCP resource factory */ MRCP_DECLARE(void) mrcp_server_connection_resource_factory_set( mrcp_connection_agent_t *agent, - mrcp_resource_factory_t *resource_factroy) + const mrcp_resource_factory_t *resource_factroy) { agent->resource_factory = resource_factroy; } +/** Set rx buffer size */ +MRCP_DECLARE(void) mrcp_server_connection_rx_size_set( + mrcp_connection_agent_t *agent, + apr_size_t size) +{ + if(size < MRCP_STREAM_BUFFER_SIZE) { + size = MRCP_STREAM_BUFFER_SIZE; + } + agent->rx_buffer_size = size; +} + +/** Set tx buffer size */ +MRCP_DECLARE(void) mrcp_server_connection_tx_size_set( + mrcp_connection_agent_t *agent, + apr_size_t size) +{ + if(size < MRCP_STREAM_BUFFER_SIZE) { + size = MRCP_STREAM_BUFFER_SIZE; + } + agent->tx_buffer_size = size; +} + /** Get task */ -MRCP_DECLARE(apt_task_t*) mrcp_server_connection_agent_task_get(mrcp_connection_agent_t *agent) +MRCP_DECLARE(apt_task_t*) mrcp_server_connection_agent_task_get(const mrcp_connection_agent_t *agent) { - return agent->task; + return apt_poller_task_base_get(agent->task); } /** Get external object */ -MRCP_DECLARE(void*) mrcp_server_connection_agent_object_get(mrcp_connection_agent_t *agent) +MRCP_DECLARE(void*) mrcp_server_connection_agent_object_get(const mrcp_connection_agent_t *agent) { return agent->obj; } +/** Get string identifier */ +MRCP_DECLARE(const char*) mrcp_server_connection_agent_id_get(const mrcp_connection_agent_t *agent) +{ + apt_task_t *task = apt_poller_task_base_get(agent->task); + return apt_task_name_get(task); +} + + /** 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->active_request = NULL; + channel->request_timer = NULL; channel->removed = FALSE; channel->obj = obj; + channel->log_obj = NULL; channel->pool = pool; return channel; } @@ -213,6 +272,7 @@ MRCP_DECLARE(apt_bool_t) mrcp_server_control_channel_destroy(mrcp_control_channe return TRUE; } +/** Signal task message */ static apt_bool_t mrcp_server_control_message_signal( connection_task_msg_type_e type, mrcp_connection_agent_t *agent, @@ -220,22 +280,18 @@ static apt_bool_t mrcp_server_control_message_signal( 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; + apt_task_t *task = apt_poller_task_base_get(agent->task); + apt_task_msg_t *task_msg = apt_task_msg_get(task); + if(task_msg) { + connection_task_msg_t *msg = (connection_task_msg_t*)task_msg->data; + msg->type = type; + msg->agent = agent; + msg->channel = channel; + msg->descriptor = descriptor; + msg->message = message; + apt_task_msg_signal(task,task_msg); } - return status; + return TRUE; } /** Add MRCPv2 control channel */ @@ -262,8 +318,7 @@ MRCP_DECLARE(apt_bool_t) mrcp_server_control_message_send(mrcp_control_channel_t 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) +static apt_bool_t mrcp_server_agent_listening_socket_create(mrcp_connection_agent_t *agent) { apr_status_t status; if(!agent->sockaddr) { @@ -296,7 +351,7 @@ static apt_bool_t mrcp_server_agent_listen_socket_create(mrcp_connection_agent_t return TRUE; } -static void mrcp_server_agent_listen_socket_destroy(mrcp_connection_agent_t *agent) +static void mrcp_server_agent_listening_socket_destroy(mrcp_connection_agent_t *agent) { if(agent->listen_sock) { apr_socket_close(agent->listen_sock); @@ -304,44 +359,6 @@ static void mrcp_server_agent_listen_socket_destroy(mrcp_connection_agent_t *age } } -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; @@ -356,7 +373,7 @@ static mrcp_control_channel_t* mrcp_connection_channel_associate(mrcp_connection 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]", + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Attach Control Channel <%s> to Connection %s [%d]", channel->identifier.buf, connection->id, apr_hash_count(connection->channel_table)); @@ -395,7 +412,7 @@ static apt_bool_t mrcp_connection_remove(mrcp_connection_agent_t *agent, mrcp_co } 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"); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Destroy Container for Pending Control Channels"); mrcp_connection_destroy(agent->null_connection); agent->null_connection = NULL; agent->connection_list = NULL; @@ -410,11 +427,13 @@ static apt_bool_t mrcp_server_agent_connection_accept(mrcp_connection_agent_t *a char *remote_ip = NULL; apr_socket_t *sock; apr_pool_t *pool; + apt_pollset_t *pollset = apt_poller_task_pollset_get(agent->task); mrcp_connection_t *connection; if(!agent->null_connection) { pool = apt_pool_create(); if(apr_socket_accept(&sock,agent->listen_sock,pool) != APR_SUCCESS) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Accept Connection"); return FALSE; } apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Rejected TCP/MRCPv2 Connection"); @@ -425,6 +444,7 @@ static apt_bool_t mrcp_server_agent_connection_accept(mrcp_connection_agent_t *a pool = agent->null_connection->pool; if(apr_socket_accept(&sock,agent->listen_sock,pool) != APR_SUCCESS) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Accept Connection"); return FALSE; } @@ -433,6 +453,7 @@ static apt_bool_t mrcp_server_agent_connection_accept(mrcp_connection_agent_t *a 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) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Get Socket Address"); apr_socket_close(sock); mrcp_connection_destroy(connection); return FALSE; @@ -450,8 +471,8 @@ static apt_bool_t mrcp_server_agent_connection_accept(mrcp_connection_agent_t *a 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"); + if(apt_pollset_add(pollset, &connection->sock_pfd) != TRUE) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Add to Pollset %s",connection->id); apr_socket_close(sock); mrcp_connection_destroy(connection); return FALSE; @@ -460,15 +481,30 @@ static apt_bool_t mrcp_server_agent_connection_accept(mrcp_connection_agent_t *a 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); + + connection->tx_buffer_size = agent->tx_buffer_size; + connection->tx_buffer = apr_palloc(connection->pool,connection->tx_buffer_size+1); + + connection->rx_buffer_size = agent->rx_buffer_size; + connection->rx_buffer = apr_palloc(connection->pool,connection->rx_buffer_size+1); + apt_text_stream_init(&connection->rx_stream,connection->rx_buffer,connection->rx_buffer_size); + + if(apt_log_masking_get() != APT_LOG_MASKING_NONE) { + connection->verbose = FALSE; + mrcp_parser_verbose_set(connection->parser,TRUE); + mrcp_generator_verbose_set(connection->generator,TRUE); + } return TRUE; } static apt_bool_t mrcp_server_agent_connection_close(mrcp_connection_agent_t *agent, mrcp_connection_t *connection) { + apt_pollset_t *pollset = apt_poller_task_pollset_get(agent->task); apt_log(APT_LOG_MARK,APT_PRIO_INFO,"TCP/MRCPv2 Peer Disconnected %s",connection->id); - apt_pollset_remove(agent->pollset,&connection->sock_pfd); + apt_pollset_remove(pollset,&connection->sock_pfd); apr_socket_close(connection->sock); connection->sock = NULL; if(!connection->access_count) { @@ -503,12 +539,12 @@ static apt_bool_t mrcp_server_agent_channel_add(mrcp_connection_agent_t *agent, } if(!agent->null_connection) { - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Create Pending Connection"); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Create Container for Pending Control Channels"); 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]", + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Add Pending Control Channel <%s> [%d]", channel->identifier.buf, apr_hash_count(agent->null_connection->channel_table)); /* send response */ @@ -536,7 +572,7 @@ static apt_bool_t mrcp_server_agent_channel_remove(mrcp_connection_agent_t *agen 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"); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Destroy Container for Pending Control Channels"); mrcp_connection_destroy(agent->null_connection); agent->null_connection = NULL; agent->connection_list = NULL; @@ -545,7 +581,7 @@ static apt_bool_t mrcp_server_agent_channel_remove(mrcp_connection_agent_t *agen 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"); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Mark Connection for Removal %s",connection->id); channel->connection = connection; channel->removed = TRUE; } @@ -557,27 +593,27 @@ static apt_bool_t mrcp_server_agent_channel_remove(mrcp_connection_agent_t *agen 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_status_e result; + apt_text_stream_t stream; + apt_message_status_e result; if(!connection || !connection->sock) { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No MRCPv2 Connection"); + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Null MRCPv2 Connection "APT_SIDRES_FMT,MRCP_MESSAGE_SIDRES(message)); 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_STATUS_INVALID) { - 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) { + apt_text_stream_init(&stream,connection->tx_buffer,connection->tx_buffer_size); + result = mrcp_generator_run(connection->generator,message,&stream); + if(result != APT_MESSAGE_STATUS_INVALID) { + stream.text.length = stream.pos - stream.text.buf; + *stream.pos = '\0'; + + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Send MRCPv2 Stream %s [%"APR_SIZE_T_FMT" bytes]\n%.*s", + connection->id, + stream.text.length, + connection->verbose == TRUE ? stream.text.length : 0, + stream.text.buf); + + if(apr_socket_send(connection->sock,stream.text.buf,&stream.text.length) == APR_SUCCESS) { status = TRUE; } else { @@ -588,32 +624,30 @@ static apt_bool_t mrcp_server_agent_messsage_send(mrcp_connection_agent_t *agent apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Generate MRCPv2 Stream"); } } - while(result == MRCP_STREAM_STATUS_INCOMPLETE); + while(result == APT_MESSAGE_STATUS_INCOMPLETE); return status; } -static apt_bool_t mrcp_server_message_handler(void *obj, mrcp_message_t *message, mrcp_stream_status_e status) +static apt_bool_t mrcp_server_message_handler(mrcp_connection_t *connection, mrcp_message_t *message, apt_message_status_e status) { - mrcp_connection_t *connection = obj; mrcp_connection_agent_t *agent = connection->agent; - if(status == MRCP_STREAM_STATUS_COMPLETE) { + if(status == APT_MESSAGE_STATUS_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, + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Find Channel "APT_SIDRES_FMT" in Connection %s", + MRCP_MESSAGE_SIDRES(message), connection->id); } } - else if(status == MRCP_STREAM_STATUS_INVALID) { + else if(status == APT_MESSAGE_STATUS_INVALID) { /* error case */ apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse MRCPv2 Stream"); - if(message->resource) { + if(message && message->resource) { mrcp_message_t *response; response = mrcp_response_create(message,message->pool); response->start_line.status_code = MRCP_STATUS_CODE_UNRECOGNIZED_MESSAGE; @@ -625,149 +659,83 @@ static apt_bool_t mrcp_server_message_handler(void *obj, mrcp_message_t *message return TRUE; } -static apt_bool_t mrcp_server_agent_messsage_receive(mrcp_connection_agent_t *agent, mrcp_connection_t *connection) +/* Receive MRCP message through TCP/MRCPv2 connection */ +static apt_bool_t mrcp_server_poller_signal_process(void *obj, const apr_pollfd_t *descriptor) { + mrcp_connection_agent_t *agent = obj; + mrcp_connection_t *connection = descriptor->client_data; apr_status_t status; apr_size_t offset; apr_size_t length; apt_text_stream_t *stream; + mrcp_message_t *message; + apt_message_status_e msg_status; + if(descriptor->desc.s == agent->listen_sock) { + return mrcp_server_agent_connection_accept(agent); + } + 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; + length = connection->rx_buffer_size - 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); + + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive MRCPv2 Stream %s [%"APR_SIZE_T_FMT" bytes]\n%.*s", + connection->id, + length, + connection->verbose == TRUE ? length : 0, + stream->pos); /* reset pos */ apt_text_stream_reset(stream); - /* walk through the stream parsing MRCP 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; - } - - /* explicitly indicate task is ready to process messages */ - apt_task_ready(agent->task); - - 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); + msg_status = mrcp_parser_run(connection->parser,stream,&message); + if(mrcp_server_message_handler(connection,message,msg_status) == FALSE) { + return FALSE; } } + while(apt_text_is_eos(stream) == FALSE); - mrcp_server_agent_pollset_destroy(agent); - - apt_task_child_terminate(agent->task); + /* scroll remaining stream */ + apt_text_stream_scroll(stream); return TRUE; } -static apt_bool_t mrcp_server_agent_task_terminate(apt_task_t *task) +/* Process task message */ +static apt_bool_t mrcp_server_agent_msg_process(apt_task_t *task, apt_task_msg_t *task_msg) { - 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"); - } + apt_poller_task_t *poller_task = apt_task_object_get(task); + mrcp_connection_agent_t *agent = apt_poller_task_object_get(poller_task); + connection_task_msg_t *msg = (connection_task_msg_t*) task_msg->data; + 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; } - return status; + + return TRUE; } diff --git a/libs/unimrcp/libs/uni-rtsp/include/rtsp.h b/libs/unimrcp/libs/uni-rtsp/include/rtsp.h index d2d029f635..fbc55d6ef1 100644 --- a/libs/unimrcp/libs/uni-rtsp/include/rtsp.h +++ b/libs/unimrcp/libs/uni-rtsp/include/rtsp.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: rtsp.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __RTSP_H__ -#define __RTSP_H__ +#ifndef RTSP_H +#define RTSP_H /** * @file rtsp.h @@ -40,4 +42,4 @@ #define RTSP_DECLARE(type) type #endif -#endif /*__RTSP_H__*/ +#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 index 4d3bd1f1c6..0209e7211a 100644 --- a/libs/unimrcp/libs/uni-rtsp/include/rtsp_client.h +++ b/libs/unimrcp/libs/uni-rtsp/include/rtsp_client.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: rtsp_client.h 1710 2010-05-24 17:36:19Z achaloyan $ */ -#ifndef __RTSP_CLIENT_H__ -#define __RTSP_CLIENT_H__ +#ifndef RTSP_CLIENT_H +#define RTSP_CLIENT_H /** * @file rtsp_client.h @@ -50,12 +52,14 @@ struct rtsp_client_vtable_t { /** * Create RTSP client. * @param max_connection_count the number of max RTSP connections + * @param request_timeout the request timeout to set * @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, + apr_size_t request_timeout, void *obj, const rtsp_client_vtable_t *handler, apr_pool_t *pool); @@ -82,13 +86,13 @@ 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); +RTSP_DECLARE(apt_task_t*) rtsp_client_task_get(const 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); +RTSP_DECLARE(void*) rtsp_client_object_get(const rtsp_client_t *client); /** @@ -146,4 +150,4 @@ RTSP_DECLARE(const apt_str_t*) rtsp_client_session_id_get(const rtsp_client_sess APT_END_EXTERN_C -#endif /*__RTSP_CLIENT_H__*/ +#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 index 2a71c6ed2d..4345ad4606 100644 --- a/libs/unimrcp/libs/uni-rtsp/include/rtsp_header.h +++ b/libs/unimrcp/libs/uni-rtsp/include/rtsp_header.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: rtsp_header.h 1648 2010-04-12 20:03:59Z achaloyan $ */ -#ifndef __RTSP_HEADER_H__ -#define __RTSP_HEADER_H__ +#ifndef RTSP_HEADER_H +#define RTSP_HEADER_H /** * @file rtsp_header.h @@ -23,7 +25,7 @@ */ #include "rtsp.h" -#include "apt_text_stream.h" +#include "apt_header_field.h" APT_BEGIN_EXTERN_C @@ -99,9 +101,6 @@ typedef enum { } 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; @@ -156,8 +155,8 @@ struct rtsp_header_t { /** Content length */ apr_size_t content_length; - /** Property set */ - rtsp_header_property_t property_set; + /** Header section (collection of header fields)*/ + apt_header_section_t header_section; }; @@ -188,7 +187,7 @@ static APR_INLINE void rtsp_transport_init(rtsp_transport_t *transport) } /** Initialize header */ -static APR_INLINE void rtsp_header_init(rtsp_header_t *header) +static APR_INLINE void rtsp_header_init(rtsp_header_t *header, apr_pool_t *pool) { header->cseq = 0; rtsp_transport_init(&header->transport); @@ -196,37 +195,38 @@ static APR_INLINE void rtsp_header_init(rtsp_header_t *header) apt_string_reset(&header->rtp_info); header->content_type = RTSP_CONTENT_TYPE_NONE; header->content_length = 0; - header->property_set = 0; + + apt_header_section_init(&header->header_section); + apt_header_section_array_alloc(&header->header_section,RTSP_HEADER_FIELD_COUNT,pool); } -/** 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 RTSP header field */ +RTSP_DECLARE(apt_bool_t) rtsp_header_field_add(rtsp_header_t *header, apt_header_field_t *header_field, apr_pool_t *pool); +/** Parse RTSP header fields */ +RTSP_DECLARE(apt_bool_t) rtsp_header_fields_parse(rtsp_header_t *header, apr_pool_t *pool); -/** 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; -} +/** Add RTSP header field property */ +RTSP_DECLARE(apt_bool_t) rtsp_header_property_add(rtsp_header_t *header, rtsp_header_field_id id, apr_pool_t *pool); -/** Remove property from property set */ -static APR_INLINE void rtsp_header_property_remove(rtsp_header_property_t *property_set, apr_size_t id) +/** Remove RTSP header field property */ +static APR_INLINE apt_bool_t rtsp_header_property_remove(rtsp_header_t *header, rtsp_header_field_id id) { - int mask = 1 << id; - *property_set &= ~mask; + apt_header_field_t *header_field = apt_header_section_field_get(&header->header_section,id); + if(header_field) { + return apt_header_section_field_remove(&header->header_section,header_field); + } + return FALSE; } -/** 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) +/** Check RTSP header field property */ +static APR_INLINE apt_bool_t rtsp_header_property_check(const rtsp_header_t *header, rtsp_header_field_id id) { - int mask = 1 << id; - return ((*property_set & mask) == mask) ? TRUE : FALSE; + return apt_header_section_field_check(&header->header_section,id); } + APT_END_EXTERN_C -#endif /*__RTSP_HEADER_H__*/ +#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 index ae57237614..71546d31e5 100644 --- a/libs/unimrcp/libs/uni-rtsp/include/rtsp_message.h +++ b/libs/unimrcp/libs/uni-rtsp/include/rtsp_message.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: rtsp_message.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __RTSP_MESSAGE_H__ -#define __RTSP_MESSAGE_H__ +#ifndef RTSP_MESSAGE_H +#define RTSP_MESSAGE_H /** * @file rtsp_message.h @@ -73,4 +75,4 @@ RTSP_DECLARE(void) rtsp_message_destroy(rtsp_message_t *message); APT_END_EXTERN_C -#endif /*__RTSP_MESSAGE_H__*/ +#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 index bf57ce176f..19e2131fb3 100644 --- a/libs/unimrcp/libs/uni-rtsp/include/rtsp_server.h +++ b/libs/unimrcp/libs/uni-rtsp/include/rtsp_server.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: rtsp_server.h 1710 2010-05-24 17:36:19Z achaloyan $ */ -#ifndef __RTSP_SERVER_H__ -#define __RTSP_SERVER_H__ +#ifndef RTSP_SERVER_H +#define RTSP_SERVER_H /** * @file rtsp_server.h @@ -84,13 +86,13 @@ 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); +RTSP_DECLARE(apt_task_t*) rtsp_server_task_get(const 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); +RTSP_DECLARE(void*) rtsp_server_object_get(const rtsp_server_t *server); /** * Send RTSP message. @@ -140,4 +142,4 @@ RTSP_DECLARE(const char*) rtsp_server_session_destination_get(const rtsp_server_ APT_END_EXTERN_C -#endif /*__RTSP_SERVER_H__*/ +#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 index 99b73880e6..8fe8c85c37 100644 --- a/libs/unimrcp/libs/uni-rtsp/include/rtsp_start_line.h +++ b/libs/unimrcp/libs/uni-rtsp/include/rtsp_start_line.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: rtsp_start_line.h 1632 2010-03-30 20:46:25Z achaloyan $ */ -#ifndef __RTSP_START_LINE_H__ -#define __RTSP_START_LINE_H__ +#ifndef RTSP_START_LINE_H +#define RTSP_START_LINE_H /** * @file rtsp_start_line.h @@ -65,6 +67,8 @@ typedef enum { RTSP_STATUS_CODE_NOT_FOUND = 404, RTSP_STATUS_CODE_METHOD_NOT_ALLOWED = 405, RTSP_STATUS_CODE_NOT_ACCEPTABLE = 406, + RTSP_STATUS_CODE_PROXY_AUTH_REQUIRED = 407, + RTSP_STATUS_CODE_REQUEST_TIMEOUT = 408, RTSP_STATUS_CODE_SESSION_NOT_FOUND = 454, RTSP_STATUS_CODE_INTERNAL_SERVER_ERROR = 500, @@ -80,6 +84,8 @@ typedef enum { RTSP_REASON_PHRASE_NOT_FOUND, RTSP_REASON_PHRASE_METHOD_NOT_ALLOWED, RTSP_REASON_PHRASE_NOT_ACCEPTABLE, + RTSP_REASON_PHRASE_PROXY_AUTH_REQUIRED, + RTSP_REASON_PHRASE_REQUEST_TIMEOUT, RTSP_REASON_PHRASE_SESSION_NOT_FOUND, RTSP_REASON_PHRASE_INTERNAL_SERVER_ERROR, RTSP_REASON_PHRASE_NOT_IMPLEMENTED, @@ -162,7 +168,7 @@ static APR_INLINE void rtsp_start_line_init(rtsp_start_line_t *start_line, rtsp_ } /** 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); +RTSP_DECLARE(apt_bool_t) rtsp_start_line_parse(rtsp_start_line_t *start_line, apt_str_t *str, 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); @@ -172,4 +178,4 @@ RTSP_DECLARE(const apt_str_t*) rtsp_reason_phrase_get(rtsp_reason_phrase_e reaso APT_END_EXTERN_C -#endif /*__RTSP_START_LINE_H__*/ +#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 index 3d9e31b260..ecebef6055 100644 --- a/libs/unimrcp/libs/uni-rtsp/include/rtsp_stream.h +++ b/libs/unimrcp/libs/uni-rtsp/include/rtsp_stream.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: rtsp_stream.h 1632 2010-03-30 20:46:25Z achaloyan $ */ -#ifndef __RTSP_STREAM_H__ -#define __RTSP_STREAM_H__ +#ifndef RTSP_STREAM_H +#define RTSP_STREAM_H /** * @file rtsp_stream.h @@ -23,47 +25,30 @@ */ #include "rtsp_message.h" +#include "apt_text_message.h" APT_BEGIN_EXTERN_C -/** Status of RTSP stream processing (parse/generate) */ -typedef enum { - RTSP_STREAM_STATUS_COMPLETE, - RTSP_STREAM_STATUS_INCOMPLETE, - RTSP_STREAM_STATUS_INVALID -} rtsp_stream_status_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_status_e status); /** Create RTSP stream parser */ RTSP_DECLARE(rtsp_parser_t*) rtsp_parser_create(apr_pool_t *pool); /** Parse RTSP stream */ -RTSP_DECLARE(rtsp_stream_status_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); +RTSP_DECLARE(apt_message_status_e) rtsp_parser_run(rtsp_parser_t *parser, apt_text_stream_t *stream, rtsp_message_t **message); /** 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_status_e) rtsp_generator_run(rtsp_generator_t *generator, apt_text_stream_t *stream); - +RTSP_DECLARE(apt_message_status_e) rtsp_generator_run(rtsp_generator_t *generator, rtsp_message_t *message, 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__*/ +#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 index 044dd0623e..9c4d23ba90 100644 --- a/libs/unimrcp/libs/uni-rtsp/src/rtsp_client.c +++ b/libs/unimrcp/libs/uni-rtsp/src/rtsp_client.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,12 +12,14 @@ * 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. + * + * $Id: rtsp_client.c 1710 2010-05-24 17:36:19Z achaloyan $ */ #include #include "rtsp_client.h" #include "rtsp_stream.h" -#include "apt_net_client_task.h" +#include "apt_poller_task.h" #include "apt_text_stream.h" #include "apt_pool.h" #include "apt_obj_list.h" @@ -36,42 +38,50 @@ typedef enum { /** RTSP client */ struct rtsp_client_t { apr_pool_t *pool; - apt_net_client_task_t *task; + apt_poller_task_t *task; apr_pool_t *sub_pool; apt_obj_list_t *connection_list; + apr_uint32_t request_timeout; + void *obj; const rtsp_client_vtable_t *vtable; }; /** RTSP connection */ struct rtsp_client_connection_t { - /** Connection base */ - apt_net_client_connection_t *base; + /** Memory pool */ + apr_pool_t *pool; + /** Connected socket */ + apr_socket_t *sock; + /** Socket poll descriptor */ + apr_pollfd_t sock_pfd; + /** String identifier used for traces */ + const char *id; /** RTSP client, connection belongs to */ - rtsp_client_t *client; + rtsp_client_t *client; /** Element of the connection list in agent */ - apt_list_elem_t *it; + apt_list_elem_t *it; /** Handle table (rtsp_client_session_t*) */ - apr_hash_t *handle_table; + apr_hash_t *handle_table; /** Session table (rtsp_client_session_t*) */ - apr_hash_t *session_table; + apr_hash_t *session_table; /** Inprogress request/session queue (rtsp_client_session_t*) */ - apt_obj_list_t *inprogress_request_queue; + apt_obj_list_t *inprogress_request_queue; /** Last CSeq sent */ - apr_size_t last_cseq; + apr_size_t last_cseq; - char rx_buffer[RTSP_STREAM_BUFFER_SIZE]; - apt_text_stream_t rx_stream; - rtsp_parser_t *parser; + 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; + char tx_buffer[RTSP_STREAM_BUFFER_SIZE]; + apt_text_stream_t tx_stream; + rtsp_generator_t *generator; }; /** RTSP session */ @@ -93,6 +103,9 @@ struct rtsp_client_session_t { /** Pending request queue (rtsp_message_t*) */ apt_obj_list_t *pending_request_queue; + /** Timer used for request timeouts */ + apt_timer_t *request_timer; + /** Resource table */ apr_hash_t *resource_table; @@ -116,23 +129,22 @@ struct task_msg_data_t { 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 apt_bool_t rtsp_client_poller_signal_process(void *obj, const apr_pollfd_t *descriptor); -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_message_send(rtsp_client_t *client, rtsp_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); +static void rtsp_client_timer_proc(apt_timer_t *timer, void *obj); + /** 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) + apr_size_t max_connection_count, + apr_size_t request_timeout, + void *obj, + const rtsp_client_vtable_t *handler, + apr_pool_t *pool) { apt_task_vtable_t *vtable; apt_task_msg_pool_t *msg_pool; @@ -146,18 +158,24 @@ RTSP_DECLARE(rtsp_client_t*) rtsp_client_create( 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); + client->task = apt_poller_task_create( + max_connection_count, + rtsp_client_poller_signal_process, + client, + msg_pool, + pool); if(!client->task) { return NULL; } - vtable = apt_net_client_task_vtable_get(client->task); + vtable = apt_poller_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; + client->request_timeout = (apr_uint32_t)request_timeout; return client; } @@ -165,29 +183,29 @@ RTSP_DECLARE(rtsp_client_t*) rtsp_client_create( 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); + return apt_poller_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); + return apt_poller_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); + return apt_poller_task_terminate(client->task); } /** Get task */ -RTSP_DECLARE(apt_task_t*) rtsp_client_task_get(rtsp_client_t *client) +RTSP_DECLARE(apt_task_t*) rtsp_client_task_get(const rtsp_client_t *client) { - return apt_net_client_task_base_get(client->task); + return apt_poller_task_base_get(client->task); } /** Get external object */ -RTSP_DECLARE(void*) rtsp_client_object_get(rtsp_client_t *client) +RTSP_DECLARE(void*) rtsp_client_object_get(const rtsp_client_t *client) { return client->obj; } @@ -217,7 +235,7 @@ static apt_bool_t rtsp_client_control_message_signal( rtsp_client_session_t *session, rtsp_message_t *message) { - apt_task_t *task = apt_net_client_task_base_get(client->task); + apt_task_t *task = apt_poller_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; @@ -245,6 +263,11 @@ RTSP_DECLARE(rtsp_client_session_t*) rtsp_client_session_create( session->connection = NULL; session->active_request = NULL; session->pending_request_queue = apt_list_create(pool); + session->request_timer = apt_poller_task_timer_create( + client->task, + rtsp_client_timer_proc, + session, + pool); session->resource_table = apr_hash_make(pool); session->term_state = TERMINATION_STATE_NONE; @@ -277,31 +300,107 @@ RTSP_DECLARE(apt_bool_t) rtsp_client_session_request(rtsp_client_t *client, rtsp return rtsp_client_control_message_signal(TASK_MSG_SEND_MESSAGE,client,session,message); } + +/** Create connection */ +static apt_bool_t rtsp_client_connect(rtsp_client_connection_t *connection, apt_pollset_t *pollset, 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; + + if(apr_sockaddr_info_get(&r_sockaddr,ip,APR_INET,port,0,connection->pool) != APR_SUCCESS) { + return FALSE; + } + + if(apr_socket_create(&connection->sock,r_sockaddr->family,SOCK_STREAM,APR_PROTO_TCP,connection->pool) != APR_SUCCESS) { + return FALSE; + } + + 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); + connection->sock = NULL; + return FALSE; + } + + if(apr_socket_addr_get(&l_sockaddr,APR_LOCAL,connection->sock) != APR_SUCCESS) { + apr_socket_close(connection->sock); + connection->sock = NULL; + return FALSE; + } + + apr_sockaddr_ip_get(&local_ip,l_sockaddr); + apr_sockaddr_ip_get(&remote_ip,r_sockaddr); + connection->id = apr_psprintf(connection->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(pollset,&connection->sock_pfd) != TRUE) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Add to Pollset %s",connection->id); + apr_socket_close(connection->sock); + connection->sock = NULL; + return FALSE; + } + + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Established RTSP Connection %s",connection->id); + return TRUE; +} + +/** Close connection */ +static apt_bool_t rtsp_client_connection_close(rtsp_client_connection_t *connection, apt_pollset_t *pollset) +{ + if(connection->sock) { + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close RTSP Connection %s",connection->id); + apt_pollset_remove(pollset,&connection->sock_pfd); + apr_socket_close(connection->sock); + connection->sock = NULL; + } + return TRUE; +} + + /* 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); + apt_pollset_t *pollset = apt_poller_task_pollset_get(client->task); + apr_pool_t *pool = apt_pool_create(); + if(!pool) { + return FALSE; + } + + rtsp_connection = apr_palloc(pool,sizeof(rtsp_client_connection_t)); + rtsp_connection->pool = pool; + rtsp_connection->sock = NULL; + + if(rtsp_client_connect(rtsp_connection,pollset,session->server_ip.buf,session->server_port) == FALSE) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Connect to RTSP Server %s:%hu", + session->server_ip.buf,session->server_port); + apr_pool_destroy(pool); 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); + rtsp_connection->handle_table = apr_hash_make(pool); + rtsp_connection->session_table = apr_hash_make(pool); + rtsp_connection->inprogress_request_queue = apt_list_create(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->parser = rtsp_parser_create(pool); + rtsp_connection->generator = rtsp_generator_create(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); + rtsp_connection->it = apt_list_push_back(client->connection_list,rtsp_connection,pool); session->connection = rtsp_connection; return TRUE; } @@ -310,8 +409,11 @@ static apt_bool_t rtsp_client_connection_create(rtsp_client_t *client, rtsp_clie static apt_bool_t rtsp_client_connection_destroy(rtsp_client_connection_t *rtsp_connection) { rtsp_client_t *client = rtsp_connection->client; + apt_pollset_t *pollset = apt_poller_task_pollset_get(client->task); apt_list_elem_remove(client->connection_list,rtsp_connection->it); - apt_net_client_disconnect(client->task,rtsp_connection->base); + rtsp_client_connection_close(rtsp_connection,pollset); + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy RTSP Connection %s",rtsp_connection->id); + apr_pool_destroy(rtsp_connection->pool); if(apt_list_is_empty(client->connection_list) == TRUE) { apr_pool_clear(client->sub_pool); @@ -389,14 +491,14 @@ static apt_bool_t rtsp_client_session_url_generate(rtsp_client_session_t *sessio { 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", + url->buf = apr_psprintf(message->pool,"rtsp://%s:%hu/%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", + url->buf = apr_psprintf(message->pool,"rtsp://%s:%hu/%s", session->server_ip.buf, session->server_port, message->start_line.common.request_line.resource_name); @@ -414,6 +516,9 @@ static apt_bool_t rtsp_client_request_push(rtsp_client_connection_t *rtsp_connec message->header.cseq); apt_list_push_back(rtsp_connection->inprogress_request_queue,session,session->pool); session->active_request = message; + if(rtsp_connection->client->request_timeout) { + apt_timer_set(session->request_timer,rtsp_connection->client->request_timeout); + } return TRUE; } @@ -435,6 +540,7 @@ static apt_bool_t rtsp_client_request_pop(rtsp_client_connection_t *rtsp_connect response->header.cseq); apt_list_elem_remove(rtsp_connection->inprogress_request_queue,elem); session->active_request = NULL; + apt_timer_kill(session->request_timer); return TRUE; } elem = apt_list_next_elem_get(rtsp_connection->inprogress_request_queue,elem); @@ -459,13 +565,13 @@ static apt_bool_t rtsp_client_session_request_process(rtsp_client_t *client, rts if(session->id.length) { message->header.session_id = session->id; - rtsp_header_property_add(&message->header.property_set,RTSP_HEADER_FIELD_SESSION_ID); + rtsp_header_property_add(&message->header,RTSP_HEADER_FIELD_SESSION_ID,message->pool); } message->header.cseq = ++session->connection->last_cseq; - rtsp_header_property_add(&message->header.property_set,RTSP_HEADER_FIELD_CSEQ); + rtsp_header_property_add(&message->header,RTSP_HEADER_FIELD_CSEQ,message->pool); - if(rtsp_client_message_send(client,session->connection->base,message) == FALSE) { + if(rtsp_client_message_send(client,session->connection,message) == FALSE) { /* respond with error */ return FALSE; } @@ -533,7 +639,7 @@ static apt_bool_t rtsp_client_session_event_process(rtsp_client_t *client, rtsp_ { 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) { + if(rtsp_header_property_check(&message->header,RTSP_HEADER_FIELD_SESSION_ID) == TRUE) { /* find existing session */ session = apr_hash_get( rtsp_connection->session_table, @@ -543,9 +649,9 @@ static apt_bool_t rtsp_client_session_event_process(rtsp_client_t *client, rtsp_ 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) { + if(rtsp_header_property_check(&message->header,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); + rtsp_header_property_add(&response->header,RTSP_HEADER_FIELD_SESSION_ID,message->pool); } client->vtable->on_session_event(client,session,message); } @@ -553,7 +659,7 @@ static apt_bool_t rtsp_client_session_event_process(rtsp_client_t *client, rtsp_ 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); + return rtsp_client_message_send(client,rtsp_connection,response); } /* Process incoming RTSP response */ @@ -564,7 +670,7 @@ static apt_bool_t rtsp_client_session_response_process(rtsp_client_t *client, rt 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) { + if(rtsp_header_property_check(&response->header,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, @@ -629,32 +735,55 @@ static apt_bool_t rtsp_client_session_terminate_raise(rtsp_client_t *client, rts return TRUE; } +/* Cancel RTSP request */ +static apt_bool_t rtsp_client_request_cancel(rtsp_client_t *client, rtsp_client_session_t *session, rtsp_status_code_e status_code, rtsp_reason_phrase_e reason) +{ + rtsp_message_t *request; + rtsp_message_t *response; + if(!session->active_request) { + return FALSE; + } + + request = session->active_request; + session->active_request = NULL; + + response = rtsp_response_create( + request, + status_code, + reason, + session->pool); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Cancel RTSP Request "APT_PTRSID_FMT" CSeq:%"APR_SIZE_T_FMT" [%d]", + session, + request->header.session_id.buf ? request->header.session_id.buf : "new", + request->header.cseq, + status_code); + rtsp_client_session_response_process(client,session,request,response); + 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_pollset_t *pollset = apt_poller_task_pollset_get(client->task); - 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); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"RTSP Peer Disconnected %s", rtsp_connection->id); + rtsp_client_connection_close(rtsp_connection,pollset); /* 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); + if(session) { + if(rtsp_client_request_cancel( + client, + session, + RTSP_STATUS_CODE_INTERNAL_SERVER_ERROR, + RTSP_REASON_PHRASE_INTERNAL_SERVER_ERROR) == TRUE) { + cancelled_requests++; + apt_timer_kill(session->request_timer); + } } } while(session); @@ -665,7 +794,7 @@ static apt_bool_t rtsp_client_on_disconnect(rtsp_client_t *client, rtsp_client_c void *val; apr_hash_index_t *it; apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Terminate Remaining RTSP Handles [%"APR_SIZE_T_FMT"]",remaining_handles); - it = apr_hash_first(rtsp_connection->base->pool,rtsp_connection->session_table); + it = apr_hash_first(rtsp_connection->pool,rtsp_connection->session_table); for(; it; it = apr_hash_next(it)) { apr_hash_this(it,NULL,NULL,&val); session = val; @@ -683,34 +812,31 @@ static apt_bool_t rtsp_client_on_disconnect(rtsp_client_t *client, rtsp_client_c } /* 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) +static apt_bool_t rtsp_client_message_send(rtsp_client_t *client, rtsp_client_connection_t *rtsp_connection, rtsp_message_t *message) { apt_bool_t status = FALSE; - rtsp_client_connection_t *rtsp_connection; apt_text_stream_t *stream; - rtsp_stream_status_e result; + apt_message_status_e result; - if(!connection || !connection->sock) { + if(!rtsp_connection || !rtsp_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; apt_text_stream_reset(stream); - result = rtsp_generator_run(rtsp_connection->generator,stream); - if(result != RTSP_STREAM_STATUS_INVALID) { + result = rtsp_generator_run(rtsp_connection->generator,message,stream); + if(result != APT_MESSAGE_STATUS_INVALID) { 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, + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Send RTSP Stream %s [%"APR_SIZE_T_FMT" bytes]\n%s", + rtsp_connection->id, stream->text.length, stream->text.buf); - if(apr_socket_send(connection->sock,stream->text.buf,&stream->text.length) == APR_SUCCESS) { + if(apr_socket_send(rtsp_connection->sock,stream->text.buf,&stream->text.length) == APR_SUCCESS) { status = TRUE; } else { @@ -721,16 +847,15 @@ static apt_bool_t rtsp_client_message_send(rtsp_client_t *client, apt_net_client apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Generate RTSP Stream"); } } - while(result == RTSP_STREAM_STATUS_INCOMPLETE); + while(result == APT_MESSAGE_STATUS_INCOMPLETE); return status; } -/** return TRUE to proceed with the next message in the stream (if any) */ -static apt_bool_t rtsp_client_message_handler(void *obj, rtsp_message_t *message, rtsp_stream_status_e status) +/** Return TRUE to proceed with the next message in the stream (if any) */ +static apt_bool_t rtsp_client_message_handler(rtsp_client_connection_t *rtsp_connection, rtsp_message_t *message, apt_message_status_e status) { - rtsp_client_connection_t *rtsp_connection = obj; - if(status != RTSP_STREAM_STATUS_COMPLETE) { + if(status != APT_MESSAGE_STATUS_COMPLETE) { /* message is not completely parsed, nothing to do */ return TRUE; } @@ -776,50 +901,61 @@ static apt_bool_t rtsp_client_message_handler(void *obj, rtsp_message_t *message } /* 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) +static apt_bool_t rtsp_client_poller_signal_process(void *obj, const apr_pollfd_t *descriptor) { - rtsp_client_t *client = apt_net_client_task_object_get(task); - rtsp_client_connection_t *rtsp_connection; + rtsp_client_t *client = obj; + rtsp_client_connection_t *rtsp_connection = descriptor->client_data; apr_status_t status; apr_size_t offset; apr_size_t length; apt_text_stream_t *stream; + rtsp_message_t *message; + apt_message_status_e msg_status; - if(!connection || !connection->sock) { + if(!rtsp_connection || !rtsp_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); + length = sizeof(rtsp_connection->rx_buffer) - 1 - offset; + + status = apr_socket_recv(rtsp_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, + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive RTSP Stream %s [%"APR_SIZE_T_FMT" bytes]\n%s", + rtsp_connection->id, length, stream->pos); /* reset pos */ apt_text_stream_reset(stream); - /* walk through the stream parsing RTSP messages */ - return rtsp_stream_walk(rtsp_connection->parser,stream,rtsp_client_message_handler,rtsp_connection); + + do { + msg_status = rtsp_parser_run(rtsp_connection->parser,stream,&message); + if(rtsp_client_message_handler(rtsp_connection,message,msg_status) == FALSE) { + return FALSE; + } + } + while(apt_text_is_eos(stream) == FALSE); + + /* scroll remaining stream */ + apt_text_stream_scroll(stream); + return TRUE; } /* 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); + apt_poller_task_t *poller_task = apt_task_object_get(task); + rtsp_client_t *client = apt_poller_task_object_get(poller_task); task_msg_data_t *data = (task_msg_data_t*) task_msg->data; switch(data->type) { @@ -833,3 +969,20 @@ static apt_bool_t rtsp_client_task_msg_process(apt_task_t *task, apt_task_msg_t return TRUE; } + +/* Timer callback */ +static void rtsp_client_timer_proc(apt_timer_t *timer, void *obj) +{ + rtsp_client_session_t *session = obj; + if(!session || !session->connection || !session->connection->client) { + return; + } + + if(session->request_timer == timer) { + rtsp_client_request_cancel( + session->connection->client, + session, + RTSP_STATUS_CODE_REQUEST_TIMEOUT, + RTSP_REASON_PHRASE_REQUEST_TIMEOUT); + } +} diff --git a/libs/unimrcp/libs/uni-rtsp/src/rtsp_header.c b/libs/unimrcp/libs/uni-rtsp/src/rtsp_header.c index b090fd7303..de19f125f4 100644 --- a/libs/unimrcp/libs/uni-rtsp/src/rtsp_header.c +++ b/libs/unimrcp/libs/uni-rtsp/src/rtsp_header.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,13 @@ * 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. + * + * $Id: rtsp_header.c 1718 2010-05-31 13:12:43Z achaloyan $ */ #include "rtsp_header.h" #include "apt_string_table.h" +#include "apt_text_stream.h" /** String table of RTSP header fields (rtsp_header_field_id) */ static const apt_str_table_item_t rtsp_header_string_table[] = { @@ -87,12 +90,12 @@ static apt_bool_t rtsp_port_range_generate(rtsp_transport_attrib_e attrib, const if(!str) { return FALSE; } - apt_string_value_generate(str,text_stream); + apt_text_string_insert(text_stream,str); apt_text_char_insert(text_stream,'='); - apt_size_value_generate(port_range->min,text_stream); + apt_text_size_value_insert(text_stream,port_range->min); if(port_range->max > port_range->min) { apt_text_char_insert(text_stream,'-'); - apt_size_value_generate(port_range->max,text_stream); + apt_text_size_value_insert(text_stream,port_range->max); } return TRUE; } @@ -197,13 +200,12 @@ static apt_bool_t rtsp_transport_protocol_parse(rtsp_transport_t *transport, con } /** Parse RTSP transport */ -static apt_bool_t rtsp_transport_parse(rtsp_transport_t *transport, const apt_str_t *line, apr_pool_t *pool) +static apt_bool_t rtsp_transport_parse(rtsp_transport_t *transport, const apt_str_t *value, apr_pool_t *pool) { apt_str_t field; apt_text_stream_t stream; - stream.text = *line; - apt_text_stream_reset(&stream); + apt_text_stream_init(&stream,value->buf,value->length); /* read transport protocol (RTP/AVP[/UDP]) */ if(apt_text_field_read(&stream,';',TRUE,&field) == FALSE) { return FALSE; @@ -223,16 +225,20 @@ static apt_bool_t rtsp_transport_parse(rtsp_transport_t *transport, const apt_st } /** Generate RTSP transport */ -static apt_bool_t rtsp_transport_generate(rtsp_transport_t *transport, apt_text_stream_t *text_stream) +static apt_bool_t rtsp_transport_generate(const rtsp_transport_t *transport, apt_str_t *value, apr_pool_t *pool) { + char buf[256]; + 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); + + apt_text_stream_init(&text_stream,buf,sizeof(buf)); + apt_text_string_insert(&text_stream,protocol); + apt_text_char_insert(&text_stream,'/'); + apt_text_string_insert(&text_stream,profile); if(transport->delivery != RTSP_DELIVERY_NONE) { const apt_str_t *delivery = NULL; @@ -248,29 +254,33 @@ static apt_bool_t rtsp_transport_generate(rtsp_transport_t *transport, apt_text_ return FALSE; } - apt_text_char_insert(text_stream,';'); - apt_string_value_generate(delivery,text_stream); + apt_text_char_insert(&text_stream,';'); + apt_text_string_insert(&text_stream,delivery); } 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); + 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); + apt_text_char_insert(&text_stream,';'); + rtsp_port_range_generate(RTSP_TRANSPORT_ATTRIB_SERVER_PORT,&transport->server_port_range,&text_stream); } if(transport->mode.length) { const apt_str_t *str; str = apt_string_table_str_get(rtsp_transport_attrib_string_table,RTSP_TRANSPORT_ATTRIB_COUNT,RTSP_TRANSPORT_ATTRIB_MODE); if(str) { - apt_text_char_insert(text_stream,';'); - apt_string_value_generate(str,text_stream); - apt_text_char_insert(text_stream,'='); - apt_string_value_generate(&transport->mode,text_stream); + apt_text_char_insert(&text_stream,';'); + apt_text_string_insert(&text_stream,str); + apt_text_char_insert(&text_stream,'='); + apt_text_string_insert(&text_stream,&transport->mode); } } + value->length = text_stream.pos - text_stream.text.buf; + value->buf = apr_palloc(pool,value->length + 1); + memcpy(value->buf,text_stream.text.buf,value->length); + value->buf[value->length] = '\0'; return TRUE; } @@ -290,8 +300,8 @@ static apt_bool_t rtsp_session_id_parse(apt_str_t *session_id, const apt_str_t * 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) +/** Parse RTSP header field value */ +static apt_bool_t rtsp_header_field_value_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) { @@ -305,7 +315,7 @@ static apt_bool_t rtsp_header_field_parse(rtsp_header_t *header, rtsp_header_fie 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); + header->rtp_info = *value; 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); @@ -319,32 +329,32 @@ static apt_bool_t rtsp_header_field_parse(rtsp_header_t *header, rtsp_header_fie 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) +/** Generate RTSP header field value */ +static apt_bool_t rtsp_header_field_value_generate(const rtsp_header_t *header, rtsp_header_field_id id, apt_str_t *value, apr_pool_t *pool) { switch(id) { case RTSP_HEADER_FIELD_CSEQ: - apt_size_value_generate(header->cseq,value); + apt_size_value_generate(header->cseq,value,pool); break; case RTSP_HEADER_FIELD_TRANSPORT: - rtsp_transport_generate(&header->transport,value); + rtsp_transport_generate(&header->transport,value,pool); break; case RTSP_HEADER_FIELD_SESSION_ID: - apt_string_value_generate(&header->session_id,value); + *value = header->session_id; break; case RTSP_HEADER_FIELD_RTP_INFO: - apt_string_value_generate(&header->rtp_info,value); + *value = header->rtp_info; 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); + *value = *name; } break; } case RTSP_HEADER_FIELD_CONTENT_LENGTH: - apt_size_value_generate(header->content_length,value); + apt_size_value_generate(header->content_length,value,pool); break; default: break; @@ -352,58 +362,59 @@ static apr_size_t rtsp_header_field_generate(rtsp_header_t *header, apr_size_t i 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) +/** Add RTSP header field */ +RTSP_DECLARE(apt_bool_t) rtsp_header_field_add(rtsp_header_t *header, apt_header_field_t *header_field, 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; - } - } + /* parse header field (name-value) */ + header_field->id = apt_string_table_id_find( + rtsp_header_string_table, + RTSP_HEADER_FIELD_COUNT, + &header_field->name); + if(apt_string_is_empty(&header_field->value) == FALSE) { + rtsp_header_field_value_parse(header,header_field->id,&header_field->value,pool); } - while(apt_text_is_eos(text_stream) == FALSE); - return result; + return apt_header_section_field_add(&header->header_section,header_field); } -/** Generate RTSP header */ -RTSP_DECLARE(apt_bool_t) rtsp_header_generate(rtsp_header_t *header, apt_text_stream_t *text_stream) +/** Parse RTSP header fields */ +RTSP_DECLARE(apt_bool_t) rtsp_header_fields_parse(rtsp_header_t *header, apr_pool_t *pool) { - const apt_str_t *name; - apr_size_t i; - rtsp_header_property_t property_set; - - property_set = header->property_set; - for(i=0; iheader_section.ring); + header_field != APR_RING_SENTINEL(&header->header_section.ring, apt_header_field_t, link); + header_field = APR_RING_NEXT(header_field, link)) { + + header_field->id = apt_string_table_id_find( + rtsp_header_string_table, + RTSP_HEADER_FIELD_COUNT, + &header_field->name); + if(apt_string_is_empty(&header_field->value) == FALSE) { + rtsp_header_field_value_parse(header,header_field->id,&header_field->value,pool); } + apt_header_section_field_set(&header->header_section,header_field); } - - apt_text_eol_insert(text_stream); return TRUE; } + +/** Add RTSP header field property */ +RTSP_DECLARE(apt_bool_t) rtsp_header_property_add(rtsp_header_t *header, rtsp_header_field_id id, apr_pool_t *pool) +{ + apt_header_field_t *header_field; + header_field = apt_header_section_field_get(&header->header_section,id); + if(header_field) { + /* such header field already exists, just (re)generate value */ + return rtsp_header_field_value_generate(header,id,&header_field->value,pool); + } + + header_field = apt_header_field_alloc(pool); + if(rtsp_header_field_value_generate(header,id,&header_field->value,pool) == TRUE) { + const apt_str_t *name = apt_string_table_str_get(rtsp_header_string_table,RTSP_HEADER_FIELD_COUNT,id); + if(name) { + header_field->name = *name; + header_field->id = id; + return apt_header_section_field_insert(&header->header_section,header_field); + } + } + return FALSE; +} diff --git a/libs/unimrcp/libs/uni-rtsp/src/rtsp_message.c b/libs/unimrcp/libs/uni-rtsp/src/rtsp_message.c index 2bb2ee60d0..4a8eb2a31d 100644 --- a/libs/unimrcp/libs/uni-rtsp/src/rtsp_message.c +++ b/libs/unimrcp/libs/uni-rtsp/src/rtsp_message.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: rtsp_message.c 1648 2010-04-12 20:03:59Z achaloyan $ */ #include "rtsp_message.h" @@ -21,7 +23,7 @@ static APR_INLINE void rtsp_message_init(rtsp_message_t *message, rtsp_message_t { message->pool = pool; rtsp_start_line_init(&message->start_line,message_type); - rtsp_header_init(&message->header); + rtsp_header_init(&message->header,pool); apt_string_reset(&message->body); } @@ -55,17 +57,16 @@ RTSP_DECLARE(rtsp_message_t*) rtsp_response_create(const rtsp_message_t *request apt_string_copy(&status_line->reason,reason_str,pool); } - if(rtsp_header_property_check(&request->header.property_set,RTSP_HEADER_FIELD_CSEQ) == TRUE) { + if(rtsp_header_property_check(&request->header,RTSP_HEADER_FIELD_CSEQ) == TRUE) { response->header.cseq = request->header.cseq; - rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_CSEQ); + rtsp_header_property_add(&response->header,RTSP_HEADER_FIELD_CSEQ,response->pool); } - if(rtsp_header_property_check(&request->header.property_set,RTSP_HEADER_FIELD_TRANSPORT) == TRUE) { + if(rtsp_header_property_check(&request->header,RTSP_HEADER_FIELD_TRANSPORT) == TRUE) { const rtsp_transport_t *req_transport = &request->header.transport; rtsp_transport_t *res_transport = &response->header.transport; if(req_transport->mode.length) { apt_string_copy(&res_transport->mode,&req_transport->mode,pool); - rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_TRANSPORT); } } diff --git a/libs/unimrcp/libs/uni-rtsp/src/rtsp_server.c b/libs/unimrcp/libs/uni-rtsp/src/rtsp_server.c index c9f6c8c2b3..e025358388 100644 --- a/libs/unimrcp/libs/uni-rtsp/src/rtsp_server.c +++ b/libs/unimrcp/libs/uni-rtsp/src/rtsp_server.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,12 +12,14 @@ * 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. + * + * $Id: rtsp_server.c 1710 2010-05-24 17:36:19Z achaloyan $ */ #include #include "rtsp_server.h" #include "rtsp_stream.h" -#include "apt_net_server_task.h" +#include "apt_poller_task.h" #include "apt_text_stream.h" #include "apt_pool.h" #include "apt_obj_list.h" @@ -31,35 +33,48 @@ 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; + apt_poller_task_t *task; apr_pool_t *sub_pool; apt_obj_list_t *connection_list; + /* Listening socket descriptor */ + apr_sockaddr_t *sockaddr; + apr_socket_t *listen_sock; + apr_pollfd_t listen_sock_pfd; + void *obj; const rtsp_server_vtable_t *vtable; }; /** RTSP connection */ struct rtsp_server_connection_t { - /** Connection base */ - apt_net_server_connection_t *base; + /** Memory pool */ + apr_pool_t *pool; + /** 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; /** RTSP server, connection belongs to */ - rtsp_server_t *server; + rtsp_server_t *server; /** Element of the connection list in agent */ - apt_list_elem_t *it; + apt_list_elem_t *it; /** Session table (rtsp_server_session_t*) */ - apr_hash_t *session_table; + apr_hash_t *session_table; - char rx_buffer[RTSP_STREAM_BUFFER_SIZE]; - apt_text_stream_t rx_stream; - rtsp_parser_t *parser; + 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; + char tx_buffer[RTSP_STREAM_BUFFER_SIZE]; + apt_text_stream_t tx_stream; + rtsp_generator_t *generator; }; /** RTSP session */ @@ -100,19 +115,14 @@ struct task_msg_data_t { rtsp_message_t *message; }; +static apt_bool_t rtsp_server_on_destroy(apt_task_t *task); static apt_bool_t rtsp_server_task_msg_process(apt_task_t *task, apt_task_msg_t *msg); +static apt_bool_t rtsp_server_poller_signal_process(void *obj, const apr_pollfd_t *descriptor); +static apt_bool_t rtsp_server_message_send(rtsp_server_t *server, rtsp_server_connection_t *connection, rtsp_message_t *message); -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_listening_socket_create(rtsp_server_t *server); +static void rtsp_server_listening_socket_destroy(rtsp_server_t *server); -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( @@ -132,58 +142,83 @@ RTSP_DECLARE(rtsp_server_t*) rtsp_server_create( } apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Create RTSP Server %s:%hu [%"APR_SIZE_T_FMT"]", - listen_ip,listen_port,max_connection_count); + listen_ip, + listen_port, + max_connection_count); server = apr_palloc(pool,sizeof(rtsp_server_t)); server->pool = pool; server->obj = obj; server->vtable = handler; + server->listen_sock = NULL; + server->sockaddr = NULL; + apr_sockaddr_info_get(&server->sockaddr,listen_ip,APR_INET,listen_port,0,pool); + if(!server->sockaddr) { + return NULL; + } + 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); + server->task = apt_poller_task_create( + max_connection_count + 1, + rtsp_server_poller_signal_process, + server, + msg_pool, + pool); if(!server->task) { return NULL; } - - vtable = apt_net_server_task_vtable_get(server->task); + + vtable = apt_poller_task_vtable_get(server->task); if(vtable) { + vtable->destroy = rtsp_server_on_destroy; vtable->process_msg = rtsp_server_task_msg_process; } server->sub_pool = apt_subpool_create(pool); server->connection_list = NULL; + + rtsp_server_listening_socket_create(server); return server; } +static apt_bool_t rtsp_server_on_destroy(apt_task_t *task) +{ + apt_poller_task_t *poller_task = apt_task_object_get(task); + rtsp_server_t *server = apt_poller_task_object_get(poller_task); + + rtsp_server_listening_socket_destroy(server); + apt_poller_task_cleanup(poller_task); + return TRUE; +} + /** 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); + return apt_poller_task_destroy(server->task); } -/** Start connection agent. */ +/** Start connection agent */ RTSP_DECLARE(apt_bool_t) rtsp_server_start(rtsp_server_t *server) { - return apt_net_server_task_start(server->task); + return apt_poller_task_start(server->task); } -/** Terminate connection agent. */ +/** Terminate connection agent */ RTSP_DECLARE(apt_bool_t) rtsp_server_terminate(rtsp_server_t *server) { - return apt_net_server_task_terminate(server->task); + return apt_poller_task_terminate(server->task); } /** Get task */ -RTSP_DECLARE(apt_task_t*) rtsp_server_task_get(rtsp_server_t *server) +RTSP_DECLARE(apt_task_t*) rtsp_server_task_get(const rtsp_server_t *server) { - return apt_net_server_task_base_get(server->task); + return apt_poller_task_base_get(server->task); } /** Get external object */ -RTSP_DECLARE(void*) rtsp_server_object_get(rtsp_server_t *server) +RTSP_DECLARE(void*) rtsp_server_object_get(const rtsp_server_t *server) { return server->obj; } @@ -216,7 +251,7 @@ RTSP_DECLARE(const rtsp_message_t*) rtsp_server_session_request_get(const rtsp_s 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 session->connection->client_ip; } return NULL; } @@ -228,7 +263,7 @@ static apt_bool_t rtsp_server_control_message_signal( rtsp_server_session_t *session, rtsp_message_t *message) { - apt_task_t *task = apt_net_server_task_base_get(server->task); + apt_task_t *task = apt_poller_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; @@ -285,6 +320,13 @@ static void rtsp_server_session_destroy(rtsp_server_session_t *session) } } +/** Destroy RTSP connection */ +static void rtsp_server_connection_destroy(rtsp_server_connection_t *rtsp_connection) +{ + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy RTSP Connection %s",rtsp_connection->id); + apr_pool_destroy(rtsp_connection->pool); +} + /* Finally terminate RTSP session */ static apt_bool_t rtsp_server_session_do_terminate(rtsp_server_t *server, rtsp_server_session_t *session) { @@ -296,11 +338,11 @@ static apt_bool_t rtsp_server_session_do_terminate(rtsp_server_t *server, rtsp_s 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); + rtsp_header_property_add(&response->header,RTSP_HEADER_FIELD_SESSION_ID,response->pool); } if(rtsp_connection) { - rtsp_server_message_send(server,rtsp_connection->base,response); + rtsp_server_message_send(server,rtsp_connection,response); } } } @@ -311,7 +353,7 @@ static apt_bool_t rtsp_server_session_do_terminate(rtsp_server_t *server, rtsp_s if(rtsp_connection && !rtsp_connection->it) { if(apr_hash_count(rtsp_connection->session_table) == 0) { - apt_net_server_connection_destroy(rtsp_connection->base); + rtsp_server_connection_destroy(rtsp_connection); } } return TRUE; @@ -322,7 +364,7 @@ static apt_bool_t rtsp_server_error_respond(rtsp_server_t *server, rtsp_server_c { /* 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) { + if(rtsp_server_message_send(server,rtsp_connection,response) == FALSE) { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Send RTSP Response"); return FALSE; } @@ -365,6 +407,9 @@ static rtsp_server_session_t* rtsp_server_session_setup_process(rtsp_server_t *s if(message->start_line.common.request_line.method_id == RTSP_METHOD_SETUP) { /* create new session */ session = rtsp_server_session_create(server); + if(!session) { + return NULL; + } 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); @@ -372,6 +417,9 @@ static rtsp_server_session_t* rtsp_server_session_setup_process(rtsp_server_t *s 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); + if(!session) { + return NULL; + } 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); @@ -395,7 +443,7 @@ static apt_bool_t rtsp_server_session_request_process(rtsp_server_t *server, rts return TRUE; } - if(rtsp_header_property_check(&message->header.property_set,RTSP_HEADER_FIELD_SESSION_ID) != TRUE) { + if(rtsp_header_property_check(&message->header,RTSP_HEADER_FIELD_SESSION_ID) != TRUE) { /* no session-id specified */ session = rtsp_server_session_setup_process(server,rtsp_connection,message); if(session) { @@ -404,6 +452,13 @@ static apt_bool_t rtsp_server_session_request_process(rtsp_server_t *server, rts rtsp_server_session_destroy(session); } } + else { + /* error case, failed to create a session */ + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create RTSP Session"); + return rtsp_server_error_respond(server,rtsp_connection,message, + RTSP_STATUS_CODE_NOT_ACCEPTABLE, + RTSP_REASON_PHRASE_NOT_ACCEPTABLE); + } return TRUE; } @@ -419,7 +474,7 @@ static apt_bool_t rtsp_server_session_request_process(rtsp_server_t *server, rts RTSP_STATUS_CODE_NOT_FOUND, RTSP_REASON_PHRASE_NOT_FOUND); } - + if(session->terminating == TRUE) { /* error case, session is being terminated */ apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Not Acceptable Request "APT_SID_FMT,message->header.session_id.buf); @@ -456,13 +511,13 @@ static apt_bool_t rtsp_server_session_response_process(rtsp_server_t *server, rt } message->start_line.common.request_line.url = request->start_line.common.request_line.url; message->header.cseq = session->last_cseq; - rtsp_header_property_add(&message->header.property_set,RTSP_HEADER_FIELD_CSEQ); + rtsp_header_property_add(&message->header,RTSP_HEADER_FIELD_CSEQ,message->pool); if(session->id.buf) { message->header.session_id = session->id; - rtsp_header_property_add(&message->header.property_set,RTSP_HEADER_FIELD_SESSION_ID); + rtsp_header_property_add(&message->header,RTSP_HEADER_FIELD_SESSION_ID,message->pool); } - rtsp_server_message_send(server,session->connection->base,message); + rtsp_server_message_send(server,session->connection,message); return TRUE; } @@ -478,7 +533,7 @@ static apt_bool_t rtsp_server_session_response_process(rtsp_server_t *server, rt else { if(session->id.buf) { message->header.session_id = session->id; - rtsp_header_property_add(&message->header.property_set,RTSP_HEADER_FIELD_SESSION_ID); + rtsp_header_property_add(&message->header,RTSP_HEADER_FIELD_SESSION_ID,message->pool); } 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) { @@ -493,7 +548,7 @@ static apt_bool_t rtsp_server_session_response_process(rtsp_server_t *server, rt } session->last_cseq = message->header.cseq; - rtsp_server_message_send(server,session->connection->base,message); + rtsp_server_message_send(server,session->connection,message); if(terminate == TRUE) { session->active_request = NULL; @@ -509,34 +564,31 @@ static apt_bool_t rtsp_server_session_response_process(rtsp_server_t *server, rt } /* 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) +static apt_bool_t rtsp_server_message_send(rtsp_server_t *server, rtsp_server_connection_t *rtsp_connection, rtsp_message_t *message) { apt_bool_t status = FALSE; - rtsp_server_connection_t *rtsp_connection; apt_text_stream_t *stream; - rtsp_stream_status_e result; + apt_message_status_e result; - if(!connection || !connection->sock) { + if(!rtsp_connection || !rtsp_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; apt_text_stream_reset(stream); - result = rtsp_generator_run(rtsp_connection->generator,stream); - if(result != RTSP_STREAM_STATUS_INVALID) { + result = rtsp_generator_run(rtsp_connection->generator,message,stream); + if(result != APT_MESSAGE_STATUS_INVALID) { 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, + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Send RTSP Stream %s [%"APR_SIZE_T_FMT" bytes]\n%s", + rtsp_connection->id, stream->text.length, stream->text.buf); - if(apr_socket_send(connection->sock,stream->text.buf,&stream->text.length) == APR_SUCCESS) { + if(apr_socket_send(rtsp_connection->sock,stream->text.buf,&stream->text.length) == APR_SUCCESS) { status = TRUE; } else { @@ -547,32 +599,30 @@ static apt_bool_t rtsp_server_message_send(rtsp_server_t *server, apt_net_server apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Generate RTSP Stream"); } } - while(result == RTSP_STREAM_STATUS_INCOMPLETE); + while(result == APT_MESSAGE_STATUS_INCOMPLETE); return status; } -static apt_bool_t rtsp_server_message_handler(void *obj, rtsp_message_t *message, rtsp_stream_status_e status) +static apt_bool_t rtsp_server_message_handler(rtsp_server_connection_t *rtsp_connection, rtsp_message_t *message, apt_message_status_e status) { - rtsp_server_connection_t *rtsp_connection = obj; - if(status == RTSP_STREAM_STATUS_COMPLETE) { + if(status == APT_MESSAGE_STATUS_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); + if(!destination->buf && rtsp_connection->client_ip) { + apt_string_assign(destination,rtsp_connection->client_ip,rtsp_connection->pool); } rtsp_server_session_request_process(rtsp_connection->server,rtsp_connection,message); } - else if(status == RTSP_STREAM_STATUS_INVALID) { + else if(status == APT_MESSAGE_STATUS_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) { + if(rtsp_server_message_send(rtsp_connection->server,rtsp_connection,response) == FALSE) { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Send RTSP Response"); } } @@ -580,72 +630,143 @@ static apt_bool_t rtsp_server_message_handler(void *obj, rtsp_message_t *message 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) +/** Create listening socket and add to pollset */ +static apt_bool_t rtsp_server_listening_socket_create(rtsp_server_t *server) { - rtsp_server_connection_t *rtsp_connection; apr_status_t status; - apr_size_t offset; - apr_size_t length; - apt_text_stream_t *stream; + apt_pollset_t *pollset = apt_poller_task_pollset_get(server->task); + + if(!server->sockaddr || !pollset) { + return FALSE; + } - if(!connection || !connection->sock) { + /* create listening socket */ + status = apr_socket_create(&server->listen_sock, server->sockaddr->family, SOCK_STREAM, APR_PROTO_TCP, server->pool); + if(status != APR_SUCCESS) { 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); + apr_socket_opt_set(server->listen_sock, APR_SO_NONBLOCK, 0); + apr_socket_timeout_set(server->listen_sock, -1); + apr_socket_opt_set(server->listen_sock, APR_SO_REUSEADDR, 1); + + status = apr_socket_bind(server->listen_sock, server->sockaddr); + if(status != APR_SUCCESS) { + apr_socket_close(server->listen_sock); + server->listen_sock = NULL; + return FALSE; + } + status = apr_socket_listen(server->listen_sock, SOMAXCONN); + if(status != APR_SUCCESS) { + apr_socket_close(server->listen_sock); + server->listen_sock = NULL; + return FALSE; } - /* 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 */ - apt_text_stream_reset(stream); - /* walk through the stream parsing RTSP messages */ - return rtsp_stream_walk(rtsp_connection->parser,stream,rtsp_server_message_handler,rtsp_connection); + memset(&server->listen_sock_pfd,0,sizeof(apr_pollfd_t)); + server->listen_sock_pfd.desc_type = APR_POLL_SOCKET; + server->listen_sock_pfd.reqevents = APR_POLLIN; + server->listen_sock_pfd.desc.s = server->listen_sock; + server->listen_sock_pfd.client_data = server->listen_sock; + if(apt_pollset_add(pollset, &server->listen_sock_pfd) != TRUE) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Add Listening Socket to Pollset"); + apr_socket_close(server->listen_sock); + server->listen_sock = NULL; + } + + return TRUE; +} + +/** Remove from pollset and destroy listening socket */ +static void rtsp_server_listening_socket_destroy(rtsp_server_t *server) +{ + apt_pollset_t *pollset = apt_poller_task_pollset_get(server->task); + if(pollset) { + apt_pollset_remove(pollset,&server->listen_sock_pfd); + } + + if(server->listen_sock) { + apr_socket_close(server->listen_sock); + server->listen_sock = NULL; + } } -/* New RTSP connection accepted */ -static apt_bool_t rtsp_server_on_connect(apt_net_server_task_t *task, apt_net_server_connection_t *connection) +/* Accept RTSP connection */ +static apt_bool_t rtsp_server_connection_accept(rtsp_server_t *server) { - 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); + rtsp_server_connection_t *rtsp_connection; + char *local_ip = NULL; + char *remote_ip = NULL; + apr_sockaddr_t *l_sockaddr = NULL; + apr_sockaddr_t *r_sockaddr = NULL; + apt_pollset_t *pollset = apt_poller_task_pollset_get(server->task); + apr_pool_t *pool = apt_pool_create(); + if(!pool) { + return FALSE; + } + + rtsp_connection = apr_palloc(pool,sizeof(rtsp_server_connection_t)); + rtsp_connection->pool = pool; + rtsp_connection->sock = NULL; + rtsp_connection->client_ip = NULL; + + if(apr_socket_accept(&rtsp_connection->sock,server->listen_sock,rtsp_connection->pool) != APR_SUCCESS) { + apr_pool_destroy(pool); + return FALSE; + } + + if(apr_socket_addr_get(&l_sockaddr,APR_LOCAL,rtsp_connection->sock) != APR_SUCCESS || + apr_socket_addr_get(&r_sockaddr,APR_REMOTE,rtsp_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); + rtsp_connection->client_ip = remote_ip; + rtsp_connection->id = apr_psprintf(pool,"%s:%hu <-> %s:%hu", + local_ip,l_sockaddr->port, + remote_ip,r_sockaddr->port); + + memset(&rtsp_connection->sock_pfd,0,sizeof(apr_pollfd_t)); + rtsp_connection->sock_pfd.desc_type = APR_POLL_SOCKET; + rtsp_connection->sock_pfd.reqevents = APR_POLLIN; + rtsp_connection->sock_pfd.desc.s = rtsp_connection->sock; + rtsp_connection->sock_pfd.client_data = rtsp_connection; + if(apt_pollset_add(pollset,&rtsp_connection->sock_pfd) != TRUE) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Add to Pollset %s",rtsp_connection->id); + apr_socket_close(rtsp_connection->sock); + apr_pool_destroy(pool); + return FALSE; + } + + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Accepted TCP Connection %s",rtsp_connection->id); + rtsp_connection->session_table = apr_hash_make(rtsp_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; + rtsp_connection->parser = rtsp_parser_create(rtsp_connection->pool); + rtsp_connection->generator = rtsp_generator_create(rtsp_connection->pool); 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); + rtsp_connection->it = apt_list_push_back(server->connection_list,rtsp_connection,rtsp_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) +/** Close connection */ +static apt_bool_t rtsp_server_connection_close(rtsp_server_t *server, rtsp_server_connection_t *rtsp_connection) { + apt_pollset_t *pollset = apt_poller_task_pollset_get(server->task); 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; + if(!rtsp_connection || !rtsp_connection->sock) { + return FALSE; + } + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close RTSP Connection %s",rtsp_connection->id); + apt_pollset_remove(pollset,&rtsp_connection->sock_pfd); + apr_socket_close(rtsp_connection->sock); + rtsp_connection->sock = NULL; + apt_list_elem_remove(server->connection_list,rtsp_connection->it); rtsp_connection->it = NULL; if(apt_list_is_empty(server->connection_list) == TRUE) { @@ -660,7 +781,7 @@ static apt_bool_t rtsp_server_on_disconnect(apt_net_server_task_t *task, apt_net apr_hash_index_t *it; apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Terminate Remaining RTSP Sessions [%"APR_SIZE_T_FMT"]", remaining_sessions); - it = apr_hash_first(connection->pool,rtsp_connection->session_table); + it = apr_hash_first(rtsp_connection->pool,rtsp_connection->session_table); for(; it; it = apr_hash_next(it)) { apr_hash_this(it,NULL,NULL,&val); session = val; @@ -670,16 +791,72 @@ static apt_bool_t rtsp_server_on_disconnect(apt_net_server_task_t *task, apt_net } } else { - apt_net_server_connection_destroy(connection); + rtsp_server_connection_destroy(rtsp_connection); } return TRUE; } + +/* Receive RTSP message through RTSP connection */ +static apt_bool_t rtsp_server_poller_signal_process(void *obj, const apr_pollfd_t *descriptor) +{ + rtsp_server_t *server = obj; + rtsp_server_connection_t *rtsp_connection = descriptor->client_data; + apr_status_t status; + apr_size_t offset; + apr_size_t length; + apt_text_stream_t *stream; + rtsp_message_t *message; + apt_message_status_e msg_status; + + if(descriptor->desc.s == server->listen_sock) { + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Accept Connection"); + return rtsp_server_connection_accept(server); + } + + if(!rtsp_connection || !rtsp_connection->sock) { + return FALSE; + } + stream = &rtsp_connection->rx_stream; + + /* calculate offset remaining from the previous receive / if any */ + offset = stream->pos - stream->text.buf; + /* calculate available length */ + length = sizeof(rtsp_connection->rx_buffer) - 1 - offset; + + status = apr_socket_recv(rtsp_connection->sock,stream->pos,&length); + if(status == APR_EOF || length == 0) { + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"RTSP Peer Disconnected %s",rtsp_connection->id); + return rtsp_server_connection_close(server,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 [%"APR_SIZE_T_FMT" bytes]\n%s", + rtsp_connection->id, + length, + stream->pos); + + /* reset pos */ + apt_text_stream_reset(stream); + + do { + msg_status = rtsp_parser_run(rtsp_connection->parser,stream,&message); + rtsp_server_message_handler(rtsp_connection,message,msg_status); + } + while(apt_text_is_eos(stream) == FALSE); + + /* scroll remaining stream */ + apt_text_stream_scroll(stream); + 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); + apt_poller_task_t *poller_task = apt_task_object_get(task); + rtsp_server_t *server = apt_poller_task_object_get(poller_task); task_msg_data_t *data = (task_msg_data_t*) task_msg->data; switch(data->type) { diff --git a/libs/unimrcp/libs/uni-rtsp/src/rtsp_start_line.c b/libs/unimrcp/libs/uni-rtsp/src/rtsp_start_line.c index 24449a8976..7e06a2e541 100644 --- a/libs/unimrcp/libs/uni-rtsp/src/rtsp_start_line.c +++ b/libs/unimrcp/libs/uni-rtsp/src/rtsp_start_line.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: rtsp_start_line.c 1671 2010-04-28 19:50:29Z achaloyan $ */ #include "rtsp_start_line.h" @@ -43,6 +45,8 @@ static const apt_str_table_item_t rtsp_reason_string_table[] = { {{"Not Found", 9},4}, {{"Method Not Allowed", 18},0}, {{"Not Acceptable", 14},4}, + {{"Proxy Auth Required", 19},0}, + {{"Request Timeout", 15},0}, {{"Session Not Found", 17},0}, {{"Internal Server Error", 21},0}, {{"Not Implemented", 15},4} @@ -95,10 +99,20 @@ static rtsp_version_e rtsp_version_parse(const apt_str_t *field) /** Generate RTSP version */ static apt_bool_t rtsp_version_generate(rtsp_version_e version, apt_text_stream_t *stream) { + if(stream->pos + RTSP_NAME_LENGTH + 1 >= stream->end) { + return FALSE; + } 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); + + if(apt_text_size_value_insert(stream,version) == FALSE) { + return FALSE; + } + + if(stream->pos + 2 >= stream->end) { + return FALSE; + } *stream->pos++ = RTSP_VERSION_MAJOR_MINOR_SEPARATOR; *stream->pos++ = '0'; return TRUE; @@ -113,7 +127,7 @@ static APR_INLINE rtsp_status_code_e rtsp_status_code_parse(const apt_str_t *fie /** 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); + return apt_text_size_value_insert(stream,status_code); } /** Generate RTSP request-line */ @@ -124,40 +138,50 @@ static apt_bool_t rtsp_request_line_generate(rtsp_request_line_t *start_line, ap return FALSE; } start_line->method_name = *method_name; - apt_string_value_generate(&start_line->method_name,stream); - apt_text_space_insert(stream); + if(apt_text_string_insert(stream,&start_line->method_name) == FALSE) { + return FALSE; + } + if(apt_text_space_insert(stream) == FALSE) { + return FALSE; + } - apt_string_value_generate(&start_line->url,stream); - apt_text_space_insert(stream); + if(apt_text_string_insert(stream,&start_line->url) == FALSE) { + return FALSE; + } + if(apt_text_space_insert(stream) == FALSE) { + return FALSE; + } - rtsp_version_generate(start_line->version,stream); - return TRUE; + return rtsp_version_generate(start_line->version,stream); } /** 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); + if(rtsp_version_generate(start_line->version,stream) == FALSE) { + return FALSE; + } + if(apt_text_space_insert(stream) == FALSE) { + return FALSE; + } - rtsp_status_code_generate(start_line->status_code,stream); - apt_text_space_insert(stream); + if(rtsp_status_code_generate(start_line->status_code,stream) == FALSE) { + return FALSE; + } + if(apt_text_space_insert(stream) == FALSE) { + return FALSE; + } - apt_string_value_generate(&start_line->reason,stream); - return TRUE; + return apt_text_string_insert(stream,&start_line->reason); } /** 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) +RTSP_DECLARE(apt_bool_t) rtsp_start_line_parse(rtsp_start_line_t *start_line, apt_str_t *str, 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; - } - apt_text_stream_reset(&line); + apt_text_stream_init(&line,str->buf,str->length); 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; @@ -223,11 +247,11 @@ RTSP_DECLARE(apt_bool_t) rtsp_start_line_generate(rtsp_start_line_t *start_line, break; } - if(status == TRUE) { - apt_text_eol_insert(stream); + if(status == FALSE) { + return FALSE; } - - return status; + + return apt_text_eol_insert(stream); } /** Get reason phrase by status code */ diff --git a/libs/unimrcp/libs/uni-rtsp/src/rtsp_stream.c b/libs/unimrcp/libs/uni-rtsp/src/rtsp_stream.c index bb8633fb70..845c17503b 100644 --- a/libs/unimrcp/libs/uni-rtsp/src/rtsp_stream.c +++ b/libs/unimrcp/libs/uni-rtsp/src/rtsp_stream.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,280 +12,113 @@ * 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. + * + * $Id: rtsp_stream.c 1648 2010-04-12 20:03:59Z achaloyan $ */ #include "rtsp_stream.h" #include "apt_log.h" -/** Stage of RTSP stream processing (parse/generate) */ -typedef enum { - RTSP_STREAM_STAGE_NONE, - RTSP_STREAM_STAGE_START_LINE, - RTSP_STREAM_STAGE_HEADER, - RTSP_STREAM_STAGE_BODY -} rtsp_stream_stage_e; - /** RTSP parser */ struct rtsp_parser_t { - rtsp_stream_stage_e stage; - apt_bool_t skip_lf; - rtsp_message_t *message; - apr_pool_t *pool; + apt_message_parser_t *base; }; /** RTSP generator */ struct rtsp_generator_t { - rtsp_stream_status_e stage; - rtsp_message_t *message; - apr_pool_t *pool; + apt_message_generator_t *base; }; -/** Read RTSP message-body */ -static apt_bool_t rtsp_message_body_read(rtsp_message_t *message, apt_text_stream_t *stream) -{ - apt_bool_t status = TRUE; - 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 */ - status = FALSE; - } - 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'; - } +/** Create message and read start line */ +static apt_bool_t rtsp_parser_on_start(apt_message_parser_t *parser, apt_message_context_t *context, apt_text_stream_t *stream, apr_pool_t *pool); +/** Header section handler */ +static apt_bool_t rtsp_parser_on_header_complete(apt_message_parser_t *parser, apt_message_context_t *context); - return status; -} +static const apt_message_parser_vtable_t parser_vtable = { + rtsp_parser_on_start, + rtsp_parser_on_header_complete, + NULL +}; -/** Write RTSP message-body */ -static apt_bool_t rtsp_message_body_write(rtsp_message_t *message, apt_text_stream_t *stream) -{ - apt_bool_t status = TRUE; - 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 */ - status = FALSE; - } - memcpy(stream->pos,message->body.buf+message->body.length,required_length); - message->body.length += required_length; - stream->pos += required_length; - } +/** Initialize by generating message start line and return header section and body */ +apt_bool_t rtsp_generator_on_start(apt_message_generator_t *generator, apt_message_context_t *context, apt_text_stream_t *stream); + +static const apt_message_generator_vtable_t generator_vtable = { + rtsp_generator_on_start, + NULL, + NULL +}; - return status; -} /** 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->stage = RTSP_STREAM_STAGE_NONE; - parser->skip_lf = FALSE; - parser->message = NULL; - parser->pool = pool; + parser->base = apt_message_parser_create(parser,&parser_vtable,pool); return parser; } -static rtsp_stream_status_e rtsp_parser_break(rtsp_parser_t *parser, apt_text_stream_t *stream) +/** Parse RTSP stream */ +RTSP_DECLARE(apt_message_status_e) rtsp_parser_run(rtsp_parser_t *parser, apt_text_stream_t *stream, rtsp_message_t **message) { - /* failed to parse message */ - if(apt_text_is_eos(stream) == TRUE) { - /* end of stream reached */ - return RTSP_STREAM_STATUS_INCOMPLETE; - } - - /* error case */ - parser->stage = RTSP_STREAM_STAGE_NONE; - return RTSP_STREAM_STATUS_INVALID; + return apt_message_parser_run(parser->base,stream,(void**)message); } -/** Parse RTSP stream */ -RTSP_DECLARE(rtsp_stream_status_e) rtsp_parser_run(rtsp_parser_t *parser, apt_text_stream_t *stream) +/** Create message and read start line */ +static apt_bool_t rtsp_parser_on_start(apt_message_parser_t *parser, apt_message_context_t *context, apt_text_stream_t *stream, apr_pool_t *pool) { - rtsp_message_t *message = parser->message; - if(parser->stage == RTSP_STREAM_STAGE_NONE || !message) { - /* create new RTSP message */ - message = rtsp_message_create(RTSP_MESSAGE_TYPE_UNKNOWN,parser->pool); - parser->message = message; - parser->stage = RTSP_STREAM_STAGE_START_LINE; - } - - if(parser->stage == RTSP_STREAM_STAGE_START_LINE) { - /* parse start-line */ - if(rtsp_start_line_parse(&message->start_line,stream,message->pool) == FALSE) { - return rtsp_parser_break(parser,stream); - } - parser->stage = RTSP_STREAM_STAGE_HEADER; + rtsp_message_t *message; + apt_str_t start_line; + /* read start line */ + if(apt_text_line_read(stream,&start_line) == FALSE) { + return FALSE; } - - if(parser->stage == RTSP_STREAM_STAGE_HEADER) { - /* parse header */ - if(rtsp_header_parse(&message->header,stream,message->pool) == FALSE) { - return rtsp_parser_break(parser,stream); - } - - parser->stage = RTSP_STREAM_STAGE_NONE; - 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(message->pool,message->header.content_length+1); - body->length = 0; - parser->stage = RTSP_STREAM_STAGE_BODY; - } - } + + message = rtsp_message_create(RTSP_MESSAGE_TYPE_UNKNOWN,pool); + if(rtsp_start_line_parse(&message->start_line,&start_line,message->pool) == FALSE) { + return FALSE; } + + context->message = message; + context->header = &message->header.header_section; + context->body = &message->body; + return TRUE; +} - if(parser->stage == RTSP_STREAM_STAGE_BODY) { - if(rtsp_message_body_read(message,stream) == FALSE) { - return rtsp_parser_break(parser,stream); - } - parser->stage = RTSP_STREAM_STAGE_NONE; - } +/** Header section handler */ +static apt_bool_t rtsp_parser_on_header_complete(apt_message_parser_t *parser, apt_message_context_t *context) +{ + rtsp_message_t *rtsp_message = context->message; + rtsp_header_fields_parse(&rtsp_message->header,rtsp_message->pool); - /* in the worst case message segmentation may occur between and - of the final empty header */ - if(!message->body.length && *(stream->pos-1)== APT_TOKEN_CR) { - /* if this is the case be prepared to skip */ - parser->skip_lf = TRUE; + if(context->body && rtsp_header_property_check(&rtsp_message->header,RTSP_HEADER_FIELD_CONTENT_LENGTH) == TRUE) { + context->body->length = rtsp_message->header.content_length; } - return RTSP_STREAM_STATUS_COMPLETE; -} - -/** Get parsed RTSP message */ -RTSP_DECLARE(rtsp_message_t*) rtsp_parser_message_get(const rtsp_parser_t *parser) -{ - return parser->message; + return TRUE; } - /** 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->stage = RTSP_STREAM_STAGE_NONE; - generator->message = NULL; - generator->pool = pool; + generator->base = apt_message_generator_create(generator,&generator_vtable,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_status_e rtsp_generator_break(rtsp_generator_t *generator, apt_text_stream_t *stream) -{ - /* failed to generate message */ - if(apt_text_is_eos(stream) == TRUE) { - /* end of stream reached */ - return RTSP_STREAM_STATUS_INCOMPLETE; - } - - /* error case */ - generator->stage = RTSP_STREAM_STAGE_NONE; - return RTSP_STREAM_STATUS_INVALID; -} /** Generate RTSP stream */ -RTSP_DECLARE(rtsp_stream_status_e) rtsp_generator_run(rtsp_generator_t *generator, apt_text_stream_t *stream) +RTSP_DECLARE(apt_message_status_e) rtsp_generator_run(rtsp_generator_t *generator, rtsp_message_t *message, apt_text_stream_t *stream) { - rtsp_message_t *message = generator->message; - if(!message) { - return RTSP_STREAM_STATUS_INVALID; - } - - if(generator->stage == RTSP_STREAM_STAGE_NONE) { - /* 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); - } - - generator->stage = RTSP_STREAM_STAGE_NONE; - 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; - generator->stage = RTSP_STREAM_STAGE_BODY; - } - } - } - - if(generator->stage == RTSP_STREAM_STAGE_BODY) { - if(rtsp_message_body_write(message,stream) == FALSE) { - return rtsp_generator_break(generator,stream); - } - - generator->stage = RTSP_STREAM_STAGE_NONE; - } - - return RTSP_STREAM_STATUS_COMPLETE; + return apt_message_generator_run(generator->base,message,stream); } - -/** 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) +/** Initialize by generating message start line and return header section and body */ +apt_bool_t rtsp_generator_on_start(apt_message_generator_t *generator, apt_message_context_t *context, apt_text_stream_t *stream) { - rtsp_stream_status_e status; - if(parser->skip_lf == TRUE) { - /* skip occurred as a result of message segmentation between and */ - apt_text_char_skip(stream,APT_TOKEN_LF); - parser->skip_lf = FALSE; - } - do { - status = rtsp_parser_run(parser,stream); - if(status == RTSP_STREAM_STATUS_COMPLETE) { - /* message is completely parsed */ - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Parsed RTSP Message [%lu]", stream->pos - stream->text.buf); - /* connection has already been destroyed, if handler return FALSE */ - if(handler(obj,parser->message,status) == FALSE) { - return TRUE; - } - } - else if(status == RTSP_STREAM_STATUS_INCOMPLETE) { - /* 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(status == RTSP_STREAM_STATUS_INVALID){ - /* error case */ - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse RTSP Message"); - /* invoke message handler */ - if(handler(obj,parser->message,status) == TRUE) { - /* reset stream pos */ - stream->pos = stream->text.buf; - } - return FALSE; - } - } - while(apt_text_is_eos(stream) == FALSE); - - /* reset stream pos */ - apt_text_stream_reset(stream); - return TRUE; + rtsp_message_t *rtsp_message = context->message; + context->header = &rtsp_message->header.header_section; + context->body = &rtsp_message->body; + return rtsp_start_line_generate(&rtsp_message->start_line,stream); } diff --git a/libs/unimrcp/libs/uni-rtsp/unirtsp.2008.vcproj b/libs/unimrcp/libs/uni-rtsp/unirtsp.2008.vcproj deleted file mode 100644 index 4189ab121e..0000000000 --- a/libs/unimrcp/libs/uni-rtsp/unirtsp.2008.vcproj +++ /dev/null @@ -1,321 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/unimrcp/libs/uni-rtsp/unirtsp.2010.vcxproj b/libs/unimrcp/libs/uni-rtsp/unirtsp.2010.vcxproj deleted file mode 100644 index 9fad4f7787..0000000000 --- a/libs/unimrcp/libs/uni-rtsp/unirtsp.2010.vcxproj +++ /dev/null @@ -1,132 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - unirtsp - {504B3154-7A4F-459D-9877-B951021C3F1F} - unirtsp - Win32Proj - - - - StaticLibrary - Unicode - true - - - StaticLibrary - Unicode - - - StaticLibrary - Unicode - true - - - StaticLibrary - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - - - - codecs;%(AdditionalIncludeDirectories) - APT_STATIC_LIB;%(PreprocessorDefinitions) - - - - - X64 - - - codecs;%(AdditionalIncludeDirectories) - APT_STATIC_LIB;%(PreprocessorDefinitions) - ProgramDatabase - - - - - codecs;%(AdditionalIncludeDirectories) - APT_STATIC_LIB;%(PreprocessorDefinitions) - - - - - X64 - - - codecs;%(AdditionalIncludeDirectories) - APT_STATIC_LIB;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/libs/unimrcp/libs/uni-rtsp/unirtsp.2010.vcxproj.filters b/libs/unimrcp/libs/uni-rtsp/unirtsp.2010.vcxproj.filters deleted file mode 100644 index 5a1581a2c3..0000000000 --- a/libs/unimrcp/libs/uni-rtsp/unirtsp.2010.vcxproj.filters +++ /dev/null @@ -1,56 +0,0 @@ - - - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {fd4564ef-9f34-4f23-992d-37f127e289a2} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - - - include - - - include - - - include - - - include - - - include - - - include - - - include - - - - - src - - - src - - - src - - - src - - - src - - - src - - - \ No newline at end of file diff --git a/libs/unimrcp/modules/mrcp-sofiasip/include/mrcp_sdp.h b/libs/unimrcp/modules/mrcp-sofiasip/include/mrcp_sdp.h index a7938c841a..8061119c58 100644 --- a/libs/unimrcp/modules/mrcp-sofiasip/include/mrcp_sdp.h +++ b/libs/unimrcp/modules/mrcp-sofiasip/include/mrcp_sdp.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_sdp.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MRCP_SDP_H__ -#define __MRCP_SDP_H__ +#ifndef MRCP_SDP_H +#define MRCP_SDP_H /** * @file mrcp_sdp.h @@ -37,4 +39,4 @@ MRCP_DECLARE(apr_size_t) sdp_resource_discovery_string_generate(const char *ip, APT_END_EXTERN_C -#endif /*__MRCP_SDP_H__*/ +#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 index 6505c7695e..da9cfdd6eb 100644 --- a/libs/unimrcp/modules/mrcp-sofiasip/include/mrcp_sofiasip_client_agent.h +++ b/libs/unimrcp/modules/mrcp-sofiasip/include/mrcp_sofiasip_client_agent.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_sofiasip_client_agent.h 1700 2010-05-21 18:56:06Z achaloyan $ */ -#ifndef __MRCP_SOFIASIP_CLIENT_AGENT_H__ -#define __MRCP_SOFIASIP_CLIENT_AGENT_H__ +#ifndef MRCP_SOFIASIP_CLIENT_AGENT_H +#define MRCP_SOFIASIP_CLIENT_AGENT_H /** * @file mrcp_sofiasip_client_agent.h @@ -40,30 +42,26 @@ struct mrcp_sofia_client_config_t { 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; + /** SIP T1 timer */ + apr_size_t sip_t1; + /** SIP T2 timer */ + apr_size_t sip_t2; + /** SIP T4 timer */ + apr_size_t sip_t4; + /** SIP T1x64 timer */ + apr_size_t sip_t1x64; }; /** * 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); +MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_sofiasip_client_agent_create(const char *id, mrcp_sofia_client_config_t *config, apr_pool_t *pool); /** * Allocate Sofia-SIP config. @@ -72,4 +70,4 @@ MRCP_DECLARE(mrcp_sofia_client_config_t*) mrcp_sofiasip_client_config_alloc(apr_ APT_END_EXTERN_C -#endif /*__MRCP_SOFIASIP_CLIENT_AGENT_H__*/ +#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 index 85bdea45f4..7876d59f68 100644 --- a/libs/unimrcp/modules/mrcp-sofiasip/include/mrcp_sofiasip_server_agent.h +++ b/libs/unimrcp/modules/mrcp-sofiasip/include/mrcp_sofiasip_server_agent.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_sofiasip_server_agent.h 1700 2010-05-21 18:56:06Z achaloyan $ */ -#ifndef __MRCP_SOFIASIP_SERVER_AGENT_H__ -#define __MRCP_SOFIASIP_SERVER_AGENT_H__ +#ifndef MRCP_SOFIASIP_SERVER_AGENT_H +#define MRCP_SOFIASIP_SERVER_AGENT_H /** * @file mrcp_sofiasip_server_agent.h @@ -38,7 +40,6 @@ struct mrcp_sofia_server_config_t { char *ext_ip; /** Local port to bind to */ apr_port_t local_port; - /** SIP user name */ char *user_name; /** User agent name */ @@ -47,16 +48,23 @@ struct mrcp_sofia_server_config_t { 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; + /** SIP T1 timer */ + apr_size_t sip_t1; + /** SIP T2 timer */ + apr_size_t sip_t2; + /** SIP T4 timer */ + apr_size_t sip_t4; + /** SIP T1x64 timer */ + apr_size_t sip_t1x64; }; /** * 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); +MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_sofiasip_server_agent_create(const char *id, mrcp_sofia_server_config_t *config, apr_pool_t *pool); /** * Allocate Sofia-SIP config. @@ -65,4 +73,4 @@ MRCP_DECLARE(mrcp_sofia_server_config_t*) mrcp_sofiasip_server_config_alloc(apr_ APT_END_EXTERN_C -#endif /*__MRCP_SOFIASIP_SERVER_AGENT_H__*/ +#endif /* MRCP_SOFIASIP_SERVER_AGENT_H */ diff --git a/libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.2008.vcproj b/libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.2008.vcproj deleted file mode 100644 index 5b10a418b3..0000000000 --- a/libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.2008.vcproj +++ /dev/null @@ -1,293 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.2010.vcxproj b/libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.2010.vcxproj deleted file mode 100644 index b3931497c7..0000000000 --- a/libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.2010.vcxproj +++ /dev/null @@ -1,138 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - mrcpsofiasip - {746F3632-5BB2-4570-9453-31D6D58A7D8E} - mrcpsofiasip - Win32Proj - - - - StaticLibrary - Unicode - true - - - StaticLibrary - Unicode - - - StaticLibrary - Unicode - true - - - StaticLibrary - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - - - - include;%(AdditionalIncludeDirectories) - APT_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;LIBSOFIA_SIP_UA_STATIC;%(PreprocessorDefinitions) - - - - - X64 - - - include;%(AdditionalIncludeDirectories) - APT_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;LIBSOFIA_SIP_UA_STATIC;%(PreprocessorDefinitions) - ProgramDatabase - - - - - include;%(AdditionalIncludeDirectories) - APT_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;LIBSOFIA_SIP_UA_STATIC;%(PreprocessorDefinitions) - - - - - X64 - - - include;%(AdditionalIncludeDirectories) - APT_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;LIBSOFIA_SIP_UA_STATIC;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - {70a49bc2-7500-41d0-b75d-edcc5be987a0} - - - - - - \ No newline at end of file diff --git a/libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.2010.vcxproj.filters b/libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.2010.vcxproj.filters deleted file mode 100644 index d2157eea88..0000000000 --- a/libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.2010.vcxproj.filters +++ /dev/null @@ -1,35 +0,0 @@ - - - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {6e92b598-880e-4fe5-88fb-f69df8e06a57} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - - - include - - - include - - - include - - - - - src - - - src - - - src - - - \ No newline at end of file diff --git a/libs/unimrcp/modules/mrcp-sofiasip/src/mrcp_sdp.c b/libs/unimrcp/modules/mrcp-sofiasip/src/mrcp_sdp.c index 7af406ff1c..23a1efe8d9 100644 --- a/libs/unimrcp/modules/mrcp-sofiasip/src/mrcp_sdp.c +++ b/libs/unimrcp/modules/mrcp-sofiasip/src/mrcp_sdp.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_sdp.c 1647 2010-04-12 19:34:53Z achaloyan $ */ #include @@ -331,7 +333,7 @@ static apt_bool_t mrcp_control_media_generate(mrcp_control_descriptor_t *control 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)); + 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)->buf); return FALSE; } 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 index aa7a5fb753..6ef4199fbe 100644 --- a/libs/unimrcp/modules/mrcp-sofiasip/src/mrcp_sofiasip_client_agent.c +++ b/libs/unimrcp/modules/mrcp-sofiasip/src/mrcp_sofiasip_client_agent.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_sofiasip_client_agent.c 1799 2011-05-12 02:32:32Z achaloyan $ */ typedef struct mrcp_sofia_agent_t mrcp_sofia_agent_t; @@ -35,14 +37,11 @@ typedef struct mrcp_sofia_session_t mrcp_sofia_session_t; #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; @@ -51,12 +50,16 @@ struct mrcp_sofia_agent_t { }; struct mrcp_sofia_session_t { - mrcp_session_t *session; - su_home_t *home; - nua_handle_t *nh; + mrcp_session_t *session; + mrcp_sig_settings_t *sip_settings; + char *sip_to_str; + + su_home_t *home; + nua_handle_t *nh; - apt_bool_t terminate_requested; - apr_thread_mutex_t *mutex; + apt_bool_t terminate_requested; + mrcp_session_descriptor_t *descriptor; + apr_thread_mutex_t *mutex; }; /* Task Interface */ @@ -77,7 +80,7 @@ static const mrcp_session_request_vtable_t session_request_vtable = { }; 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 apt_bool_t mrcp_sofia_session_create(mrcp_session_t *session, mrcp_sig_settings_t *settings); static void mrcp_sofia_event_callback( nua_event_t nua_event, int status, @@ -91,13 +94,13 @@ static void mrcp_sofia_event_callback( nua_event_t nua_event, /** 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) +MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_sofiasip_client_agent_create(const char *id, 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 = mrcp_signaling_agent_create(id,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; @@ -110,7 +113,7 @@ MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_sofiasip_client_agent_create(mrcp_sofia_cli if(!task) { return NULL; } - apt_task_name_set(task,SOFIA_TASK_NAME); + apt_task_name_set(task,id); vtable = apt_task_vtable_get(task); if(vtable) { vtable->on_pre_run = mrcp_sofia_task_initialize; @@ -118,10 +121,8 @@ MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_sofiasip_client_agent_create(mrcp_sofia_cli 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 : ""); + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create SofiaSIP Agent [%s] ["SOFIA_SIP_VERSION"] %s", + id,sofia_agent->sip_bind_str); return sofia_agent->sig_agent; } @@ -133,48 +134,37 @@ MRCP_DECLARE(mrcp_sofia_client_config_t*) mrcp_sofiasip_client_config_alloc(apr_ 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; + + config->sip_t1 = 0; + config->sip_t2 = 0; + config->sip_t4 = 0; + config->sip_t1x64 = 0; 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) { + if(!config->local_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); + sofia_agent->sip_contact_str = apr_psprintf(pool,"sip:%s:%hu", local_ip, config->local_port); + sofia_agent->sip_from_str = apr_psprintf(pool,"sip:%s:%hu", 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", + sofia_agent->sip_bind_str = apr_psprintf(pool,"sip:%s:%hu;transport=%s", config->local_ip, config->local_port, config->transport); } else { - sofia_agent->sip_bind_str = apr_psprintf(pool,"sip:%s:%d", + sofia_agent->sip_bind_str = apr_psprintf(pool,"sip:%s:%hu", config->local_ip, config->local_port); } @@ -184,6 +174,7 @@ static apt_bool_t mrcp_sofia_config_validate(mrcp_sofia_agent_t *sofia_agent, mr static void mrcp_sofia_task_initialize(apt_task_t *task) { mrcp_sofia_agent_t *sofia_agent = apt_task_object_get(task); + mrcp_sofia_client_config_t *sofia_config = sofia_agent->config; /* Initialize Sofia-SIP library and create event loop */ su_init(); @@ -204,7 +195,11 @@ static void mrcp_sofia_task_initialize(apt_task_t *task) sofia_agent->nua, NUTAG_AUTOANSWER(0), NUTAG_APPL_METHOD("OPTIONS"), - SIPTAG_USER_AGENT_STR(sofia_agent->config->user_agent_name), + TAG_IF(sofia_config->sip_t1,NTATAG_SIP_T1(sofia_config->sip_t1)), + TAG_IF(sofia_config->sip_t2,NTATAG_SIP_T2(sofia_config->sip_t2)), + TAG_IF(sofia_config->sip_t4,NTATAG_SIP_T4(sofia_config->sip_t4)), + TAG_IF(sofia_config->sip_t1x64,NTATAG_SIP_T1X64(sofia_config->sip_t1x64)), + SIPTAG_USER_AGENT_STR(sofia_config->user_agent_name), TAG_END()); } } @@ -244,7 +239,7 @@ static APR_INLINE mrcp_sofia_agent_t* mrcp_sofia_agent_get(mrcp_session_t *sessi return session->signaling_agent->obj; } -static apt_bool_t mrcp_sofia_session_create(mrcp_session_t *session) +static apt_bool_t mrcp_sofia_session_create(mrcp_session_t *session, mrcp_sig_settings_t *settings) { mrcp_sofia_agent_t *sofia_agent = mrcp_sofia_agent_get(session); mrcp_sofia_session_t *sofia_session; @@ -254,15 +249,30 @@ static apt_bool_t mrcp_sofia_session_create(mrcp_session_t *session) sofia_session->mutex = NULL; sofia_session->home = su_home_new(sizeof(*sofia_session->home)); sofia_session->session = session; + sofia_session->sip_settings = settings; sofia_session->terminate_requested = FALSE; + sofia_session->descriptor = NULL; session->obj = sofia_session; - + + if(settings->user_name && settings->user_name != '\0') { + sofia_session->sip_to_str = apr_psprintf(session->pool,"sip:%s@%s:%hu", + settings->user_name, + settings->server_ip, + settings->server_port); + } + else { + sofia_session->sip_to_str = apr_psprintf(session->pool,"sip:%s:%hu", + settings->server_ip, + settings->server_port); + } + sofia_session->nh = nua_handle( sofia_agent->nua, sofia_session, - SIPTAG_TO_STR(sofia_agent->sip_to_str), + SIPTAG_TO_STR(sofia_session->sip_to_str), SIPTAG_FROM_STR(sofia_agent->sip_from_str), SIPTAG_CONTACT_STR(sofia_agent->sip_contact_str), + TAG_IF(settings->feature_tags,SIPTAG_ACCEPT_CONTACT_STR(settings->feature_tags)), TAG_END()); apr_thread_mutex_create(&sofia_session->mutex,APR_THREAD_MUTEX_DEFAULT,session->pool); @@ -313,8 +323,10 @@ static apt_bool_t mrcp_sofia_session_offer(mrcp_session_t *session, mrcp_session } 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), + sofia_session->descriptor = descriptor; + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->log_obj,"Local SDP "APT_NAMESID_FMT"\n%s", + session->name, + MRCP_SESSION_SID(session), local_sdp_str); } @@ -392,14 +404,15 @@ static void mrcp_sofia_on_session_ready( 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), + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->log_obj,"Remote SDP "APT_NAMESID_FMT"\n%s", + session->name, + MRCP_SESSION_SID(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; + if(sofia_session->sip_settings->force_destination == TRUE) { + force_destination_ip = sofia_session->sip_settings->server_ip; } descriptor = mrcp_descriptor_generate_by_sdp_session(sdp,force_destination_ip,session->pool); sdp_parser_free(parser); @@ -409,6 +422,62 @@ static void mrcp_sofia_on_session_ready( } } +static void mrcp_sofia_on_session_redirect( + 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; + sip_contact_t *sip_contact; + if(!sip) { + return; + } + sip_contact = sip->sip_contact; + if(!sip_contact || !sip_contact->m_url) { + return; + } + + if(sip_contact->m_url->url_user && sip_contact->m_url->url_user != '\0') { + sofia_session->sip_to_str = apr_psprintf(session->pool,"sip:%s@%s:%s", + sip_contact->m_url->url_user, + sip_contact->m_url->url_host, + sip_contact->m_url->url_port); + } + else { + sofia_session->sip_to_str = apr_psprintf(session->pool,"sip:%s:%s", + sip_contact->m_url->url_host, + sip_contact->m_url->url_port); + } + + apr_thread_mutex_lock(sofia_session->mutex); + + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->log_obj,"Redirect "APT_NAMESID_FMT" to %s", + session->name, + MRCP_SESSION_SID(session), + sofia_session->sip_to_str); + + if(sofia_session->nh) { + nua_handle_bind(sofia_session->nh, NULL); + nua_handle_destroy(sofia_session->nh); + sofia_session->nh = NULL; + } + + sofia_session->nh = nua_handle( + sofia_agent->nua, + sofia_session, + SIPTAG_TO_STR(sofia_session->sip_to_str), + SIPTAG_FROM_STR(sofia_agent->sip_from_str), + SIPTAG_CONTACT_STR(sofia_agent->sip_contact_str), + TAG_END()); + + apr_thread_mutex_unlock(sofia_session->mutex); + + mrcp_sofia_session_offer(sofia_session->session,sofia_session->descriptor); +} + static void mrcp_sofia_on_session_terminate( int status, mrcp_sofia_agent_t *sofia_agent, @@ -450,8 +519,8 @@ static void mrcp_sofia_on_state_change( 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, + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"SIP Call State %s [%s]", + sofia_session ? sofia_session->session->name : "", nua_callstate_name(ss_state)); switch(ss_state) { @@ -477,15 +546,15 @@ static void mrcp_sofia_on_resource_discover( 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(sip->sip_payload) { + remote_sdp_str = sip->sip_payload->pl_data; + } + 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), + apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->obj,"Resource Discovery SDP %s\n%s", + session->name, remote_sdp_str); parser = sdp_parse(sofia_session->home,remote_sdp_str,(int)strlen(remote_sdp_str),0); @@ -517,6 +586,11 @@ static void mrcp_sofia_event_callback( case nua_i_state: mrcp_sofia_on_state_change(status,sofia_agent,nh,sofia_session,sip,tags); break; + case nua_r_invite: + if(status >= 300 && status < 400) { + mrcp_sofia_on_session_redirect(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; 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 index c5f81a22b5..e094078a24 100644 --- a/libs/unimrcp/modules/mrcp-sofiasip/src/mrcp_sofiasip_server_agent.c +++ b/libs/unimrcp/modules/mrcp-sofiasip/src/mrcp_sofiasip_server_agent.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_sofiasip_server_agent.c 1700 2010-05-21 18:56:06Z achaloyan $ */ typedef struct mrcp_sofia_agent_t mrcp_sofia_agent_t; @@ -35,8 +37,6 @@ typedef struct mrcp_sofia_session_t mrcp_sofia_session_t; #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; @@ -82,13 +82,13 @@ static void mrcp_sofia_event_callback( nua_event_t nua_event, /** 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) +MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_sofiasip_server_agent_create(const char *id, 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->sig_agent = mrcp_signaling_agent_create(id,sofia_agent,MRCP_VERSION_2,pool); sofia_agent->config = config; sofia_agent->root = NULL; sofia_agent->nua = NULL; @@ -101,7 +101,7 @@ MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_sofiasip_server_agent_create(mrcp_sofia_ser if(!task) { return NULL; } - apt_task_name_set(task,SOFIA_TASK_NAME); + apt_task_name_set(task,id); vtable = apt_task_vtable_get(task); if(vtable) { vtable->on_pre_run = mrcp_sofia_task_initialize; @@ -109,10 +109,8 @@ MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_sofiasip_server_agent_create(mrcp_sofia_ser 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 : ""); + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create SofiaSIP Agent [%s] ["SOFIA_SIP_VERSION"] %s", + id,sofia_agent->sip_bind_str); return sofia_agent->sig_agent; } @@ -128,6 +126,10 @@ MRCP_DECLARE(mrcp_sofia_server_config_t*) mrcp_sofiasip_server_config_alloc(apr_ config->origin = NULL; config->transport = NULL; config->force_destination = FALSE; + config->sip_t1 = 0; + config->sip_t2 = 0; + config->sip_t4 = 0; + config->sip_t1x64 = 0; return config; } @@ -135,15 +137,15 @@ static apt_bool_t mrcp_sofia_config_validate(mrcp_sofia_agent_t *sofia_agent, mr { 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); + sofia_agent->sip_contact_str = apr_psprintf(pool,"sip:%s:%hu",local_ip,config->local_port); if(config->transport) { - sofia_agent->sip_bind_str = apr_psprintf(pool,"sip:%s:%d;transport=%s", + sofia_agent->sip_bind_str = apr_psprintf(pool,"sip:%s:%hu;transport=%s", config->local_ip, config->local_port, config->transport); } else { - sofia_agent->sip_bind_str = apr_psprintf(pool,"sip:%s:%d", + sofia_agent->sip_bind_str = apr_psprintf(pool,"sip:%s:%hu", config->local_ip, config->local_port); } @@ -153,6 +155,7 @@ static apt_bool_t mrcp_sofia_config_validate(mrcp_sofia_agent_t *sofia_agent, mr static void mrcp_sofia_task_initialize(apt_task_t *task) { mrcp_sofia_agent_t *sofia_agent = apt_task_object_get(task); + mrcp_sofia_server_config_t *sofia_config = sofia_agent->config; /* Initialize Sofia-SIP library and create event loop */ su_init(); @@ -173,7 +176,11 @@ static void mrcp_sofia_task_initialize(apt_task_t *task) sofia_agent->nua, NUTAG_AUTOANSWER(0), NUTAG_APPL_METHOD("OPTIONS"), - SIPTAG_USER_AGENT_STR(sofia_agent->config->user_agent_name), + TAG_IF(sofia_config->sip_t1,NTATAG_SIP_T1(sofia_config->sip_t1)), + TAG_IF(sofia_config->sip_t2,NTATAG_SIP_T2(sofia_config->sip_t2)), + TAG_IF(sofia_config->sip_t4,NTATAG_SIP_T4(sofia_config->sip_t4)), + TAG_IF(sofia_config->sip_t1x64,NTATAG_SIP_T1X64(sofia_config->sip_t1x64)), + SIPTAG_USER_AGENT_STR(sofia_config->user_agent_name), TAG_END()); } } @@ -270,7 +277,10 @@ static apt_bool_t mrcp_sofia_on_session_answer(mrcp_session_t *session, mrcp_ses 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); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Local SDP "APT_NAMESID_FMT"\n%s", + session->name, + MRCP_SESSION_SID(session), + local_sdp_str); } nua_respond(sofia_session->nh, SIP_200_OK, @@ -333,7 +343,10 @@ static void mrcp_sofia_on_call_receive(mrcp_sofia_agent_t *sofia_agent, 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); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remote SDP "APT_NAMESID_FMT"\n%s", + sofia_session->session->name, + MRCP_SESSION_SID(sofia_session->session), + remote_sdp_str); parser = sdp_parse(sofia_session->home,remote_sdp_str,(int)strlen(remote_sdp_str),0); sdp = sdp_session(parser); @@ -371,7 +384,9 @@ static void mrcp_sofia_on_state_change(mrcp_sofia_agent_t *sofia_agent, NUTAG_CALLSTATE_REF(ss_state), TAG_END()); - apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"SIP Call State [%s]", nua_callstate_name(ss_state)); + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"SIP Call State %s [%s]", + sofia_session ? sofia_session->session->name : "", + nua_callstate_name(ss_state)); switch(ss_state) { case nua_callstate_received: @@ -397,7 +412,8 @@ static void mrcp_sofia_on_resource_discover(mrcp_sofia_agent_t *sofia_agent, 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); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Resource Discovery SDP\n[%s]\n", + local_sdp_str); } nua_respond(nh, SIP_200_OK, 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 index fc26929cbe..e455e4476e 100644 --- a/libs/unimrcp/modules/mrcp-unirtsp/include/mrcp_unirtsp_client_agent.h +++ b/libs/unimrcp/modules/mrcp-unirtsp/include/mrcp_unirtsp_client_agent.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_unirtsp_client_agent.h 1700 2010-05-21 18:56:06Z achaloyan $ */ -#ifndef __MRCP_UNIRTSP_CLIENT_AGENT_H__ -#define __MRCP_UNIRTSP_CLIENT_AGENT_H__ +#ifndef MRCP_UNIRTSP_CLIENT_AGENT_H +#define MRCP_UNIRTSP_CLIENT_AGENT_H /** * @file mrcp_unirtsp_client_agent.h @@ -28,41 +30,30 @@ APT_BEGIN_EXTERN_C -/** UniRTSP config declaration */ +/** Declaration of UniRTSP agent config */ typedef struct rtsp_client_config_t rtsp_client_config_t; -/** UniRTSP config */ +/** Configuration of UniRTSP agent */ 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; + /** Request timeout */ + apr_size_t request_timeout; }; /** * Create UniRTSP signaling agent. */ -MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_unirtsp_client_agent_create(rtsp_client_config_t *config, apr_pool_t *pool); +MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_unirtsp_client_agent_create(const char *id, 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__*/ +#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 index 58d35347d0..74de717a48 100644 --- a/libs/unimrcp/modules/mrcp-unirtsp/include/mrcp_unirtsp_sdp.h +++ b/libs/unimrcp/modules/mrcp-unirtsp/include/mrcp_unirtsp_sdp.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_unirtsp_sdp.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __MRCP_UNIRTSP_SDP_H__ -#define __MRCP_UNIRTSP_SDP_H__ +#ifndef MRCP_UNIRTSP_SDP_H +#define MRCP_UNIRTSP_SDP_H /** * @file mrcp_unirtsp_sdp.h @@ -84,4 +86,4 @@ MRCP_DECLARE(const char*) rtsp_name_get_by_mrcp_name(const apr_table_t *resource APT_END_EXTERN_C -#endif /*__MRCP_UNIRTSP_SDP_H__*/ +#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 index e117f2a672..e93f692c5b 100644 --- a/libs/unimrcp/modules/mrcp-unirtsp/include/mrcp_unirtsp_server_agent.h +++ b/libs/unimrcp/modules/mrcp-unirtsp/include/mrcp_unirtsp_server_agent.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: mrcp_unirtsp_server_agent.h 1700 2010-05-21 18:56:06Z achaloyan $ */ -#ifndef __MRCP_UNIRTSP_SERVER_AGENT_H__ -#define __MRCP_UNIRTSP_SERVER_AGENT_H__ +#ifndef MRCP_UNIRTSP_SERVER_AGENT_H +#define MRCP_UNIRTSP_SERVER_AGENT_H /** * @file mrcp_unirtsp_server_agent.h @@ -56,7 +58,7 @@ struct rtsp_server_config_t { /** * Create UniRTSP signaling agent. */ -MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_unirtsp_server_agent_create(rtsp_server_config_t *config, apr_pool_t *pool); +MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_unirtsp_server_agent_create(const char *id, rtsp_server_config_t *config, apr_pool_t *pool); /** * Allocate UniRTSP config. @@ -65,4 +67,4 @@ MRCP_DECLARE(rtsp_server_config_t*) mrcp_unirtsp_server_config_alloc(apr_pool_t APT_END_EXTERN_C -#endif /*__MRCP_UNIRTSP_SERVER_AGENT_H__*/ +#endif /* MRCP_UNIRTSP_SERVER_AGENT_H */ diff --git a/libs/unimrcp/modules/mrcp-unirtsp/mrcpunirtsp.2008.vcproj b/libs/unimrcp/modules/mrcp-unirtsp/mrcpunirtsp.2008.vcproj deleted file mode 100644 index d0d90c646d..0000000000 --- a/libs/unimrcp/modules/mrcp-unirtsp/mrcpunirtsp.2008.vcproj +++ /dev/null @@ -1,293 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/unimrcp/modules/mrcp-unirtsp/mrcpunirtsp.2010.vcxproj b/libs/unimrcp/modules/mrcp-unirtsp/mrcpunirtsp.2010.vcxproj deleted file mode 100644 index f8a573d857..0000000000 --- a/libs/unimrcp/modules/mrcp-unirtsp/mrcpunirtsp.2010.vcxproj +++ /dev/null @@ -1,133 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - mrcpunirtsp - {DEB01ACB-D65F-4A62-AED9-58C1054499E9} - mrcpunirtsp - Win32Proj - - - - StaticLibrary - Unicode - true - - - StaticLibrary - Unicode - - - StaticLibrary - Unicode - true - - - StaticLibrary - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - - - - include;%(AdditionalIncludeDirectories) - APT_STATIC_LIB;RTSP_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;LIBSOFIA_SIP_UA_STATIC;%(PreprocessorDefinitions) - - - - - X64 - - - include;%(AdditionalIncludeDirectories) - APT_STATIC_LIB;RTSP_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;LIBSOFIA_SIP_UA_STATIC;%(PreprocessorDefinitions) - ProgramDatabase - - - - - include;%(AdditionalIncludeDirectories) - APT_STATIC_LIB;RTSP_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;LIBSOFIA_SIP_UA_STATIC;%(PreprocessorDefinitions) - - - - - X64 - - - include;%(AdditionalIncludeDirectories) - APT_STATIC_LIB;RTSP_STATIC_LIB;MPF_STATIC_LIB;MRCP_STATIC_LIB;LIBSOFIA_SIP_UA_STATIC;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/libs/unimrcp/modules/mrcp-unirtsp/mrcpunirtsp.2010.vcxproj.filters b/libs/unimrcp/modules/mrcp-unirtsp/mrcpunirtsp.2010.vcxproj.filters deleted file mode 100644 index a990550f29..0000000000 --- a/libs/unimrcp/modules/mrcp-unirtsp/mrcpunirtsp.2010.vcxproj.filters +++ /dev/null @@ -1,35 +0,0 @@ - - - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {f87f8ada-12d1-412b-bd14-7e62df3f92a0} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - - - include - - - include - - - include - - - - - src - - - src - - - src - - - \ No newline at end of file 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 index 0b0840b1d7..6997c47004 100644 --- a/libs/unimrcp/modules/mrcp-unirtsp/src/mrcp_unirtsp_client_agent.c +++ b/libs/unimrcp/modules/mrcp-unirtsp/src/mrcp_unirtsp_client_agent.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_unirtsp_client_agent.c 1700 2010-05-21 18:56:06Z achaloyan $ */ #include @@ -28,7 +30,6 @@ #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; @@ -41,10 +42,11 @@ struct mrcp_unirtsp_agent_t { }; 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; + mrcp_message_t *mrcp_message; + mrcp_session_t *mrcp_session; + rtsp_client_session_t *rtsp_session; + mrcp_sig_settings_t *rtsp_settings; + su_home_t *home; }; @@ -72,18 +74,18 @@ static const rtsp_client_vtable_t session_response_vtable = { mrcp_unirtsp_on_session_event }; -static apt_bool_t mrcp_unirtsp_session_create(mrcp_session_t *session); +static apt_bool_t mrcp_unirtsp_session_create(mrcp_session_t *session, mrcp_sig_settings_t *settings); 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) +MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_unirtsp_client_agent_create(const char *id, 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 = mrcp_signaling_agent_create(id,agent,MRCP_VERSION_1,pool); agent->sig_agent->create_client_session = mrcp_unirtsp_session_create; agent->config = config; @@ -91,20 +93,22 @@ MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_unirtsp_client_agent_create(rtsp_client_con return NULL; } - agent->rtsp_client = rtsp_client_create(config->max_connection_count, - agent,&session_response_vtable,pool); + agent->rtsp_client = rtsp_client_create( + config->max_connection_count, + config->request_timeout, + 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); + apt_task_name_set(task,id); agent->sig_agent->task = task; - apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create "UNIRTSP_TASK_NAME" %s:%hu [%"APR_SIZE_T_FMT"]", - config->server_ip, - config->server_port, - config->max_connection_count); + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create UniRTSP Agent [%s] [%"APR_SIZE_T_FMT"]", + id,config->max_connection_count); return agent->sig_agent; } @@ -112,22 +116,14 @@ MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_unirtsp_client_agent_create(rtsp_client_con 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; + config->request_timeout = 0; 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; } @@ -139,7 +135,7 @@ static APR_INLINE mrcp_unirtsp_agent_t* client_agent_get(apt_task_t *task) return agent; } -static apt_bool_t mrcp_unirtsp_session_create(mrcp_session_t *mrcp_session) +static apt_bool_t mrcp_unirtsp_session_create(mrcp_session_t *mrcp_session, mrcp_sig_settings_t *settings) { mrcp_unirtsp_agent_t *agent = mrcp_session->signaling_agent->obj; mrcp_unirtsp_session_t *session; @@ -147,15 +143,16 @@ static apt_bool_t mrcp_unirtsp_session_create(mrcp_session_t *mrcp_session) session = apr_palloc(mrcp_session->pool,sizeof(mrcp_unirtsp_session_t)); session->home = su_home_new(sizeof(*session->home)); + session->rtsp_settings = settings; 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); + session->rtsp_settings->server_ip, + session->rtsp_settings->server_port, + session->rtsp_settings->resource_location); if(!session->rtsp_session) { su_home_unref(session->home); return FALSE; @@ -198,9 +195,9 @@ static apt_bool_t mrcp_unirtsp_on_announce_response(mrcp_unirtsp_agent_t *agent, return FALSE; } - if(rtsp_header_property_check(&message->header.property_set,RTSP_HEADER_FIELD_CONTENT_TYPE) == TRUE && + if(rtsp_header_property_check(&message->header,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 && + rtsp_header_property_check(&message->header,RTSP_HEADER_FIELD_CONTENT_LENGTH) == TRUE && message->header.content_length > 0) { apt_text_stream_t text_stream; @@ -212,9 +209,8 @@ static apt_bool_t mrcp_unirtsp_on_announce_response(mrcp_unirtsp_agent_t *agent, 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_STATUS_COMPLETE) { - mrcp_message = mrcp_parser_message_get(parser); + mrcp_parser_resource_set(parser,&resource_name_str); + if(mrcp_parser_run(parser,&text_stream,&mrcp_message) == APT_MESSAGE_STATUS_COMPLETE) { mrcp_message->channel_id.session_id = message->header.session_id; } else { @@ -255,15 +251,15 @@ static apt_bool_t mrcp_unirtsp_on_session_response(rtsp_client_t *rtsp_client, r const char *force_destination_ip = NULL; mrcp_session_descriptor_t *descriptor; - if(agent->config->force_destination == TRUE) { - force_destination_ip = agent->config->server_ip; + if(session->rtsp_settings->force_destination == TRUE) { + force_destination_ip = session->rtsp_settings->server_ip; } descriptor = mrcp_descriptor_generate_by_rtsp_response( request, response, force_destination_ip, - agent->config->resource_map, + session->rtsp_settings->resource_map, session->mrcp_session->pool, session->home); if(!descriptor) { @@ -286,7 +282,7 @@ static apt_bool_t mrcp_unirtsp_on_session_response(rtsp_client_t *rtsp_client, r request, response, NULL, - agent->config->resource_map, + session->rtsp_settings->resource_map, session->mrcp_session->pool, session->home); if(!descriptor) { @@ -299,7 +295,7 @@ static apt_bool_t mrcp_unirtsp_on_session_response(rtsp_client_t *rtsp_client, r { 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, + session->rtsp_settings->resource_map, request->start_line.common.request_line.resource_name); mrcp_unirtsp_on_announce_response(agent,session,response,resource_name); break; @@ -322,7 +318,7 @@ static apt_bool_t mrcp_unirtsp_on_session_event(rtsp_client_t *rtsp_client, rtsp 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, + session->rtsp_settings->resource_map, message->start_line.common.request_line.resource_name); if(!session || !resource_name) { return FALSE; @@ -342,7 +338,7 @@ static apt_bool_t mrcp_unirtsp_session_offer(mrcp_session_t *mrcp_session, mrcp_ apt_string_set(&descriptor->origin,agent->config->origin); } - request = rtsp_request_generate_by_mrcp_descriptor(descriptor,agent->config->resource_map,mrcp_session->pool); + request = rtsp_request_generate_by_mrcp_descriptor(descriptor,session->rtsp_settings->resource_map,mrcp_session->pool); return rtsp_client_session_request(agent->rtsp_client,session->rtsp_session,request); } @@ -375,7 +371,7 @@ static apt_bool_t mrcp_unirtsp_session_control(mrcp_session_t *mrcp_session, mrc 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, + session->rtsp_settings->resource_map, mrcp_message->channel_id.resource_name.buf); rtsp_message->start_line.common.request_line.method_id = RTSP_METHOD_ANNOUNCE; @@ -389,9 +385,9 @@ static apt_bool_t mrcp_unirtsp_session_control(mrcp_session_t *mrcp_session, mrc 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_header_property_add(&rtsp_message->header,RTSP_HEADER_FIELD_CONTENT_TYPE,rtsp_message->pool); rtsp_message->header.content_length = body->length; - rtsp_header_property_add(&rtsp_message->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH); + rtsp_header_property_add(&rtsp_message->header,RTSP_HEADER_FIELD_CONTENT_LENGTH,rtsp_message->pool); session->mrcp_message = mrcp_message; rtsp_client_session_request(agent->rtsp_client,session->rtsp_session,rtsp_message); @@ -409,7 +405,7 @@ static apt_bool_t mrcp_unirtsp_resource_discover(mrcp_session_t *mrcp_session, m } request = rtsp_resource_discovery_request_generate( descriptor->resource_name.buf, - agent->config->resource_map, + session->rtsp_settings->resource_map, mrcp_session->pool); if(request) { rtsp_client_session_request(agent->rtsp_client,session->rtsp_session,request); @@ -427,7 +423,7 @@ static apt_bool_t mrcp_unirtsp_on_resource_discover(mrcp_unirtsp_agent_t *agent, descriptor = mrcp_resource_discovery_response_generate( request, response, - agent->config->resource_map, + session->rtsp_settings->resource_map, session->mrcp_session->pool, session->home); if(descriptor) { diff --git a/libs/unimrcp/modules/mrcp-unirtsp/src/mrcp_unirtsp_sdp.c b/libs/unimrcp/modules/mrcp-unirtsp/src/mrcp_unirtsp_sdp.c index e35055fdc9..ebb31fa007 100644 --- a/libs/unimrcp/modules/mrcp-unirtsp/src/mrcp_unirtsp_sdp.c +++ b/libs/unimrcp/modules/mrcp-unirtsp/src/mrcp_unirtsp_sdp.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_unirtsp_sdp.c 1752 2010-08-09 19:05:23Z achaloyan $ */ #include @@ -190,8 +192,8 @@ MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_descriptor_generate_by_rtsp_reques } 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 && + if(rtsp_header_property_check(&request->header,RTSP_HEADER_FIELD_CONTENT_TYPE) == TRUE && + rtsp_header_property_check(&request->header,RTSP_HEADER_FIELD_CONTENT_LENGTH) == TRUE && request->body.buf) { sdp_parser_t *parser; @@ -216,7 +218,7 @@ MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_descriptor_generate_by_rtsp_reques mpf_rtp_media_descriptor_init(media); media->state = MPF_MEDIA_ENABLED; media->id = mrcp_session_audio_media_add(descriptor,media); - if(rtsp_header_property_check(&request->header.property_set,RTSP_HEADER_FIELD_TRANSPORT) == TRUE) { + if(rtsp_header_property_check(&request->header,RTSP_HEADER_FIELD_TRANSPORT) == TRUE) { media->port = request->header.transport.client_port_range.min; media->ip = request->header.transport.destination; } @@ -253,8 +255,8 @@ MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_descriptor_generate_by_rtsp_respon } 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 && + if(rtsp_header_property_check(&response->header,RTSP_HEADER_FIELD_CONTENT_TYPE) == TRUE && + rtsp_header_property_check(&response->header,RTSP_HEADER_FIELD_CONTENT_LENGTH) == TRUE && response->body.buf) { sdp_parser_t *parser; @@ -348,14 +350,14 @@ MRCP_DECLARE(rtsp_message_t*) rtsp_request_generate_by_mrcp_descriptor(const mrc 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); + rtsp_header_property_add(&request->header,RTSP_HEADER_FIELD_TRANSPORT,request->pool); 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); + rtsp_header_property_add(&request->header,RTSP_HEADER_FIELD_CONTENT_TYPE,request->pool); request->header.content_length = offset; - rtsp_header_property_add(&request->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH); + rtsp_header_property_add(&request->header,RTSP_HEADER_FIELD_CONTENT_LENGTH,request->pool); } return request; } @@ -434,14 +436,14 @@ MRCP_DECLARE(rtsp_message_t*) rtsp_response_generate_by_mrcp_descriptor(const rt 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); + rtsp_header_property_add(&response->header,RTSP_HEADER_FIELD_TRANSPORT,response->pool); 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); + rtsp_header_property_add(&response->header,RTSP_HEADER_FIELD_CONTENT_TYPE,response->pool); response->header.content_length = offset; - rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH); + rtsp_header_property_add(&response->header,RTSP_HEADER_FIELD_CONTENT_LENGTH,response->pool); } } return response; @@ -481,8 +483,8 @@ MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_resource_discovery_response_genera 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 && + if(rtsp_header_property_check(&response->header,RTSP_HEADER_FIELD_CONTENT_TYPE) == TRUE && + rtsp_header_property_check(&response->header,RTSP_HEADER_FIELD_CONTENT_LENGTH) == TRUE && response->body.buf) { sdp_parser_t *parser; @@ -546,9 +548,9 @@ MRCP_DECLARE(rtsp_message_t*) rtsp_resource_discovery_response_generate( 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); + rtsp_header_property_add(&response->header,RTSP_HEADER_FIELD_CONTENT_TYPE,response->pool); response->header.content_length = offset; - rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH); + rtsp_header_property_add(&response->header,RTSP_HEADER_FIELD_CONTENT_LENGTH,response->pool); } } @@ -558,18 +560,20 @@ MRCP_DECLARE(rtsp_message_t*) rtsp_resource_discovery_response_generate( /** 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; inelts; i++) { - if(entry[i].val && rtsp_name) { - if(apr_strnatcasecmp(entry[i].val,rtsp_name) == 0) { + if(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; inelts; i++) { + if(!entry[i].val) continue; + + if(strcasecmp(entry[i].val,rtsp_name) == 0) { return entry[i].key; } } + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown RTSP Resource Name [%s]", rtsp_name); } - return rtsp_name; + return "unknown"; } /** Get RTSP resource name by MRCP resource 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 index 1ef05e193e..873b3d216d 100644 --- a/libs/unimrcp/modules/mrcp-unirtsp/src/mrcp_unirtsp_server_agent.c +++ b/libs/unimrcp/modules/mrcp-unirtsp/src/mrcp_unirtsp_server_agent.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_unirtsp_server_agent.c 1700 2010-05-21 18:56:06Z achaloyan $ */ #include @@ -28,8 +30,6 @@ #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; @@ -72,12 +72,12 @@ static apt_bool_t rtsp_config_validate(mrcp_unirtsp_agent_t *agent, rtsp_server_ /** Create UniRTSP Signaling Agent */ -MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_unirtsp_server_agent_create(rtsp_server_config_t *config, apr_pool_t *pool) +MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_unirtsp_server_agent_create(const char *id, 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->sig_agent = mrcp_signaling_agent_create(id,agent,MRCP_VERSION_1,pool); agent->config = config; if(rtsp_config_validate(agent,config,pool) == FALSE) { @@ -96,13 +96,14 @@ MRCP_DECLARE(mrcp_sig_agent_t*) mrcp_unirtsp_server_agent_create(rtsp_server_con } task = rtsp_server_task_get(agent->rtsp_server); - apt_task_name_set(task,UNIRTSP_TASK_NAME); + apt_task_name_set(task,id); agent->sig_agent->task = task; - apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create "UNIRTSP_TASK_NAME" %s:%hu [%"APR_SIZE_T_FMT"]", - config->local_ip, - config->local_port, - config->max_connection_count); + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create UniRTSP Agent [%s] %s:%hu [%"APR_SIZE_T_FMT"]", + id, + config->local_ip, + config->local_port, + config->max_connection_count); return agent->sig_agent; } @@ -192,23 +193,23 @@ static apt_bool_t mrcp_unirtsp_session_announce(mrcp_unirtsp_agent_t *agent, mrc apt_bool_t status = TRUE; if(session && resource_name && - rtsp_header_property_check(&message->header.property_set,RTSP_HEADER_FIELD_CONTENT_TYPE) == TRUE && + rtsp_header_property_check(&message->header,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 && + rtsp_header_property_check(&message->header,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; + mrcp_message_t *mrcp_message; text_stream.text = message->body; apt_text_stream_reset(&text_stream); 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_STATUS_COMPLETE) { - mrcp_message_t *mrcp_message = mrcp_parser_message_get(parser); + mrcp_parser_resource_set(parser,&resource_name_str); + if(mrcp_parser_run(parser,&text_stream,&mrcp_message) == APT_MESSAGE_STATUS_COMPLETE) { mrcp_message->channel_id.session_id = message->header.session_id; status = mrcp_session_control_request(session->mrcp_session,mrcp_message); } @@ -375,9 +376,9 @@ static apt_bool_t mrcp_unirtsp_on_session_control(mrcp_session_t *mrcp_session, 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_header_property_add(&rtsp_message->header,RTSP_HEADER_FIELD_CONTENT_TYPE,rtsp_message->pool); rtsp_message->header.content_length = body->length; - rtsp_header_property_add(&rtsp_message->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH); + rtsp_header_property_add(&rtsp_message->header,RTSP_HEADER_FIELD_CONTENT_LENGTH,rtsp_message->pool); 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 deleted file mode 100644 index 98677b46c9..0000000000 --- a/libs/unimrcp/packages/inno-setup/setup.iss +++ /dev/null @@ -1,14 +0,0 @@ -#define uni_version "0.8.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/setup.txt b/libs/unimrcp/packages/inno-setup/setup.txt index 6dd7582ded..45d6489f83 100644 --- a/libs/unimrcp/packages/inno-setup/setup.txt +++ b/libs/unimrcp/packages/inno-setup/setup.txt @@ -1,4 +1,4 @@ -#define uni_version "0.9.0" +#define uni_version "1.0.0" #define uni_src "..\.." AppName=UniMRCP diff --git a/libs/unimrcp/packages/inno-setup/unimrcp.iss b/libs/unimrcp/packages/inno-setup/unimrcp.iss index 0f17729874..9e65059430 100644 --- a/libs/unimrcp/packages/inno-setup/unimrcp.iss +++ b/libs/unimrcp/packages/inno-setup/unimrcp.iss @@ -31,6 +31,7 @@ Source: {#= uni_outdir}\plugin\demosynth.dll; DestDir: {app}\plugin; Components: Source: {#= uni_outdir}\plugin\demorecog.dll; DestDir: {app}\plugin; Components: server/demorecog Source: {#= uni_outdir}\conf\unimrcpserver.xml; DestDir: {app}\conf; Components: server Source: {#= uni_outdir}\conf\unimrcpclient.xml; DestDir: {app}\conf; Components: client +Source: {#= uni_outdir}\conf\client-profiles\*.xml; DestDir: {app}\conf\client-profiles; Components: client Source: {#= uni_outdir}\conf\umcscenarios.xml; DestDir: {app}\conf; Components: client Source: {#= uni_outdir}\data\*.pcm; DestDir: {app}\data; Components: server client Source: {#= uni_outdir}\data\*.xml; DestDir: {app}\data; Components: server client diff --git a/libs/unimrcp/platforms/asr-client/src/main.c b/libs/unimrcp/platforms/asr-client/src/main.c index 0861bf4200..8a3a1d06de 100644 --- a/libs/unimrcp/platforms/asr-client/src/main.c +++ b/libs/unimrcp/platforms/asr-client/src/main.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: main.c 1541 2010-02-22 20:20:10Z achaloyan $ */ #include @@ -44,7 +46,7 @@ static void* APR_THREAD_FUNC asr_session_run(apr_thread_t *thread, void *data) asr_params_t *params = data; asr_session_t *session = asr_session_create(params->engine,params->profile); if(session) { - const char *result = asr_session_recognize(session,params->grammar_file,params->input_file); + const char *result = asr_session_file_recognize(session,params->grammar_file,params->input_file); if(result) { printf("Recog Result [%s]",result); } @@ -87,7 +89,7 @@ static apt_bool_t asr_session_launch(asr_engine_t *engine, const char *grammar_f params->profile = apr_pstrdup(pool,profile); } else { - params->profile = "MRCPv2-Default"; + params->profile = "uni2"; } /* Launch a thread to run demo ASR session in */ @@ -126,11 +128,11 @@ static apt_bool_t cmdline_process(asr_engine_t *engine, char *cmdline) "\n- run [grammar_file] [audio_input_file] [profile_name] (run demo asr client)\n" " grammar_file is the name of grammar file, (path is relative to data dir)\n" " audio_input_file is the name of audio file, (path is relative to data dir)\n" - " profile_name is one of 'MRCPv2-Default', 'MRCPv1-Default', ...\n" + " profile_name is one of 'uni2', 'uni1', ...\n" "\n examples: \n" " run\n" " run grammar.xml one.pcm\n" - " run grammar.xml one.pcm MRCPv1-Default\n" + " run grammar.xml one.pcm uni1\n" "\n- loglevel [level] (set loglevel, one of 0,1...7)\n" "\n- quit, exit\n"); } diff --git a/libs/unimrcp/platforms/libasr-client/include/asr_engine.h b/libs/unimrcp/platforms/libasr-client/include/asr_engine.h index 6a9e62fbe5..065e7f83f9 100644 --- a/libs/unimrcp/platforms/libasr-client/include/asr_engine.h +++ b/libs/unimrcp/platforms/libasr-client/include/asr_engine.h @@ -1,5 +1,5 @@ /* - * Copyright 2009 Arsen Chaloyan + * Copyright 2009-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: asr_engine.h 1566 2010-03-06 16:45:05Z achaloyan $ */ -#ifndef __ASR_ENGINE_H__ -#define __ASR_ENGINE_H__ +#ifndef ASR_ENGINE_H +#define ASR_ENGINE_H /** * @file asr_engine.h @@ -75,13 +77,42 @@ ASR_CLIENT_DECLARE(apt_bool_t) asr_engine_destroy(asr_engine_t *engine); ASR_CLIENT_DECLARE(asr_session_t*) asr_session_create(asr_engine_t *engine, const char *profile); /** - * Initiate recognition. + * Initiate recognition based on specified grammar and input file. * @param session the session to run recognition in the scope of * @param grammar_file the name of the grammar file to use (path is relative to data dir) * @param input_file the name of the audio input file to use (path is relative to data dir) * @return the recognition result (input element of NLSML content) */ -ASR_CLIENT_DECLARE(const char*) asr_session_recognize(asr_session_t *session, const char *grammar_file, const char *input_file); +ASR_CLIENT_DECLARE(const char*) asr_session_file_recognize( + asr_session_t *session, + const char *grammar_file, + const char *input_file); + +/** + * Initiate recognition based on specified grammar and input stream. + * @param session the session to run recognition in the scope of + * @param grammar_file the name of the grammar file to use (path is relative to data dir) + * @param callback the callback to be called to get input media frames + * @param obj the object to pass to the callback + * @return the recognition result (input element of NLSML content) + * + * @remark Audio data should be streamed through + * asr_session_stream_write() function calls. + */ +ASR_CLIENT_DECLARE(const char*) asr_session_stream_recognize( + asr_session_t *session, + const char *grammar_file); + +/** + * Write audio data to recognize. + * @param session the session to write audio data for + * @param data the audio data + * @param size the size of data + */ +ASR_CLIENT_DECLARE(apt_bool_t) asr_session_stream_write( + asr_session_t *session, + char *data, + int size); /** * Destroy ASR session. @@ -99,4 +130,4 @@ ASR_CLIENT_DECLARE(apt_bool_t) asr_engine_log_priority_set(apt_log_priority_e lo APT_END_EXTERN_C -#endif /*__ASR_ENGINE_H__*/ +#endif /* ASR_ENGINE_H */ diff --git a/libs/unimrcp/platforms/libasr-client/src/asr_engine.c b/libs/unimrcp/platforms/libasr-client/src/asr_engine.c index 0879f4fe98..4048347a05 100644 --- a/libs/unimrcp/platforms/libasr-client/src/asr_engine.c +++ b/libs/unimrcp/platforms/libasr-client/src/asr_engine.c @@ -1,5 +1,5 @@ /* - * Copyright 2009 Arsen Chaloyan + * Copyright 2009-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: asr_engine.c 1785 2010-09-22 06:14:29Z achaloyan $ */ #include @@ -20,14 +22,16 @@ #include #include -/* common includes */ +/* Common includes */ #include "unimrcp_client.h" #include "mrcp_application.h" #include "mrcp_message.h" #include "mrcp_generic_header.h" -/* recognizer includes */ +/* Recognizer includes */ #include "mrcp_recog_header.h" #include "mrcp_recog_resource.h" +/* MPF includes */ +#include /* APT includes */ #include "apt_nlsml_doc.h" #include "apt_log.h" @@ -35,6 +39,11 @@ #include "asr_engine.h" +typedef enum { + INPUT_MODE_NONE, + INPUT_MODE_FILE, + INPUT_MODE_STREAM +} input_mode_e; /** ASR engine on top of UniMRCP client stack */ struct asr_engine_t { @@ -50,23 +59,27 @@ struct asr_engine_t { /** ASR session on top of UniMRCP session/channel */ struct asr_session_t { /** Back pointer to engine */ - asr_engine_t *engine; + asr_engine_t *engine; /** MRCP session */ - mrcp_session_t *mrcp_session; + mrcp_session_t *mrcp_session; /** MRCP channel */ - mrcp_channel_t *mrcp_channel; + mrcp_channel_t *mrcp_channel; /** RECOGNITION-COMPLETE message */ - mrcp_message_t *recog_complete; - - /** File to read audio stream from */ - FILE *audio_in; + mrcp_message_t *recog_complete; + + /** Input mode (either file or stream) */ + input_mode_e input_mode; + /** File to read media frames from */ + FILE *audio_in; + /* Buffer of media frames */ + mpf_frame_buffer_t *media_buffer; /** Streaming is in-progress */ - apt_bool_t streaming; + apt_bool_t streaming; /** Conditional wait object */ - apr_thread_cond_t *wait_object; + apr_thread_cond_t *wait_object; /** Mutex of the wait object */ - apr_thread_mutex_t *mutex; + apr_thread_mutex_t *mutex; /** Message sent from client stack */ const mrcp_app_message_t *app_message; @@ -114,7 +127,7 @@ ASR_CLIENT_DECLARE(asr_engine_t*) asr_engine_create( if((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); + apt_log_file_open(dir_layout->log_dir_path,"unimrcpclient",MAX_LOG_FILE_SIZE,MAX_LOG_FILE_COUNT,FALSE,pool); } engine = apr_palloc(pool,sizeof(asr_engine_t)); @@ -204,12 +217,12 @@ static apt_bool_t asr_session_destroy_ex(asr_session_t *asr_session, apt_bool_t apr_thread_cond_destroy(asr_session->wait_object); asr_session->wait_object = NULL; } - if(asr_session->mrcp_session) { - mrcp_application_session_destroy(asr_session->mrcp_session); - asr_session->mrcp_session = NULL; + if(asr_session->media_buffer) { + mpf_frame_buffer_destroy(asr_session->media_buffer); + asr_session->media_buffer = NULL; } - free(asr_session); - return TRUE; + + return mrcp_application_session_destroy(asr_session->mrcp_session); } /** Open audio input file */ @@ -241,14 +254,21 @@ static apt_bool_t asr_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *frame { asr_session_t *asr_session = stream->obj; if(asr_session && asr_session->streaming == TRUE) { - if(asr_session->audio_in) { - if(fread(frame->codec_frame.buffer,1,frame->codec_frame.size,asr_session->audio_in) == frame->codec_frame.size) { - /* normal read */ - frame->type |= MEDIA_FRAME_TYPE_AUDIO; + if(asr_session->input_mode == INPUT_MODE_FILE) { + if(asr_session->audio_in) { + if(fread(frame->codec_frame.buffer,1,frame->codec_frame.size,asr_session->audio_in) == frame->codec_frame.size) { + /* normal read */ + frame->type |= MEDIA_FRAME_TYPE_AUDIO; + } + else { + /* file is over */ + asr_session->streaming = FALSE; + } } - else { - /* file is over */ - asr_session->streaming = FALSE; + } + if(asr_session->input_mode == INPUT_MODE_STREAM) { + if(asr_session->media_buffer) { + mpf_frame_buffer_read(asr_session->media_buffer,frame); } } } @@ -415,6 +435,11 @@ static apt_bool_t mrcp_response_check(const mrcp_app_message_t *app_message, mrc if(!mrcp_message || mrcp_message->start_line.message_type != MRCP_MESSAGE_TYPE_RESPONSE ) { return FALSE; } + + if(mrcp_message->start_line.status_code != MRCP_STATUS_CODE_SUCCESS && + mrcp_message->start_line.status_code != MRCP_STATUS_CODE_SUCCESS_WITH_IGNORE) { + return FALSE; + } return (mrcp_message->start_line.request_state == state) ? TRUE : FALSE; } @@ -440,23 +465,33 @@ ASR_CLIENT_DECLARE(asr_session_t*) asr_session_create(asr_engine_t *engine, cons mrcp_session_t *session; const mrcp_app_message_t *app_message; apr_pool_t *pool; - - asr_session_t *asr_session = malloc(sizeof(asr_session_t)); + asr_session_t *asr_session; + mpf_stream_capabilities_t *capabilities; /* create session */ - session = mrcp_application_session_create(engine->mrcp_app,profile,asr_session); + session = mrcp_application_session_create(engine->mrcp_app,profile,NULL); if(!session) { - free(asr_session); return NULL; } pool = mrcp_application_session_pool_get(session); + + asr_session = apr_palloc(pool,sizeof(asr_session_t)); + mrcp_application_session_object_set(session,asr_session); - termination = mrcp_application_source_termination_create( + /* create source stream capabilities */ + capabilities = mpf_source_stream_capabilities_create(pool); + /* add codec capabilities (Linear PCM) */ + mpf_codec_capabilities_add( + &capabilities->codecs, + MPF_SAMPLE_RATE_8000, + "LPCM"); + + termination = mrcp_application_audio_termination_create( session, /* session, termination belongs to */ &audio_stream_vtable, /* virtual methods table of audio stream */ - NULL, /* codec descriptor of audio stream (NULL by default) */ - asr_session); /* object to associate */ - + capabilities, /* capabilities of audio stream */ + asr_session); /* object to associate */ + channel = mrcp_application_channel_create( session, /* session, channel belongs to */ MRCP_RECOGNIZER_RESOURCE, /* MRCP resource identifier */ @@ -466,7 +501,6 @@ ASR_CLIENT_DECLARE(asr_session_t*) asr_session_create(asr_engine_t *engine, cons if(!channel) { mrcp_application_session_destroy(session); - free(asr_session); return NULL; } @@ -474,8 +508,10 @@ ASR_CLIENT_DECLARE(asr_session_t*) asr_session_create(asr_engine_t *engine, cons asr_session->mrcp_session = session; asr_session->mrcp_channel = channel; asr_session->recog_complete = NULL; + asr_session->input_mode = INPUT_MODE_NONE; asr_session->streaming = FALSE; asr_session->audio_in = NULL; + asr_session->media_buffer = NULL; asr_session->mutex = NULL; asr_session->wait_object = NULL; asr_session->app_message = NULL; @@ -484,6 +520,9 @@ ASR_CLIENT_DECLARE(asr_session_t*) asr_session_create(asr_engine_t *engine, cons apr_thread_mutex_create(&asr_session->mutex,APR_THREAD_MUTEX_DEFAULT,pool); apr_thread_cond_create(&asr_session->wait_object,pool); + /* Create media buffer */ + asr_session->media_buffer = mpf_frame_buffer_create(160,20,pool); + /* Send add channel request and wait for the response */ apr_thread_mutex_lock(asr_session->mutex); app_message = NULL; @@ -501,8 +540,11 @@ ASR_CLIENT_DECLARE(asr_session_t*) asr_session_create(asr_engine_t *engine, cons return asr_session; } -/** Initiate recognition */ -ASR_CLIENT_DECLARE(const char*) asr_session_recognize(asr_session_t *asr_session, const char *grammar_file, const char *input_file) +/** Initiate recognition based on specified grammar and input file */ +ASR_CLIENT_DECLARE(const char*) asr_session_file_recognize( + asr_session_t *asr_session, + const char *grammar_file, + const char *input_file) { const mrcp_app_message_t *app_message; mrcp_message_t *mrcp_message; @@ -551,6 +593,7 @@ ASR_CLIENT_DECLARE(const char*) asr_session_recognize(asr_session_t *asr_session } /* Open input file and start streaming */ + asr_session->input_mode = INPUT_MODE_FILE; if(asr_input_file_open(asr_session,input_file) == FALSE) { return NULL; } @@ -579,6 +622,106 @@ ASR_CLIENT_DECLARE(const char*) asr_session_recognize(asr_session_t *asr_session return nlsml_input_get(asr_session->recog_complete); } +/** Initiate recognition based on specified grammar and input stream */ +ASR_CLIENT_DECLARE(const char*) asr_session_stream_recognize( + asr_session_t *asr_session, + const char *grammar_file) +{ + const mrcp_app_message_t *app_message; + mrcp_message_t *mrcp_message; + + app_message = NULL; + mrcp_message = define_grammar_message_create(asr_session,grammar_file); + if(!mrcp_message) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create DEFINE-GRAMMAR Request"); + return NULL; + } + + /* Send DEFINE-GRAMMAR request and wait for the response */ + apr_thread_mutex_lock(asr_session->mutex); + if(mrcp_application_message_send(asr_session->mrcp_session,asr_session->mrcp_channel,mrcp_message) == TRUE) { + apr_thread_cond_wait(asr_session->wait_object,asr_session->mutex); + app_message = asr_session->app_message; + asr_session->app_message = NULL; + } + apr_thread_mutex_unlock(asr_session->mutex); + + if(mrcp_response_check(app_message,MRCP_REQUEST_STATE_COMPLETE) == FALSE) { + return NULL; + } + + /* Reset prev recog result (if any) */ + asr_session->recog_complete = NULL; + + app_message = NULL; + mrcp_message = recognize_message_create(asr_session); + if(!mrcp_message) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create RECOGNIZE Request"); + return NULL; + } + + /* Send RECOGNIZE request and wait for the response */ + apr_thread_mutex_lock(asr_session->mutex); + if(mrcp_application_message_send(asr_session->mrcp_session,asr_session->mrcp_channel,mrcp_message) == TRUE) { + apr_thread_cond_wait(asr_session->wait_object,asr_session->mutex); + app_message = asr_session->app_message; + asr_session->app_message = NULL; + } + apr_thread_mutex_unlock(asr_session->mutex); + + if(mrcp_response_check(app_message,MRCP_REQUEST_STATE_INPROGRESS) == FALSE) { + return NULL; + } + + /* Reset media buffer */ + mpf_frame_buffer_restart(asr_session->media_buffer); + + /* Set input mode and start streaming */ + asr_session->input_mode = INPUT_MODE_STREAM; + asr_session->streaming = TRUE; + + /* Wait for events either START-OF-INPUT or RECOGNITION-COMPLETE */ + do { + apr_thread_mutex_lock(asr_session->mutex); + app_message = NULL; + if(apr_thread_cond_timedwait(asr_session->wait_object,asr_session->mutex, 60 * 1000000) != APR_SUCCESS) { + apr_thread_mutex_unlock(asr_session->mutex); + return NULL; + } + app_message = asr_session->app_message; + asr_session->app_message = NULL; + apr_thread_mutex_unlock(asr_session->mutex); + + mrcp_message = mrcp_event_get(app_message); + if(mrcp_message && mrcp_message->start_line.method_id == RECOGNIZER_RECOGNITION_COMPLETE) { + asr_session->recog_complete = mrcp_message; + } + } + while(!asr_session->recog_complete); + + /* Get results */ + return nlsml_input_get(asr_session->recog_complete); +} + +/** Write audio frame to recognize */ +ASR_CLIENT_DECLARE(apt_bool_t) asr_session_stream_write( + asr_session_t *asr_session, + char *data, + int size) +{ + mpf_frame_t frame; + frame.type = MEDIA_FRAME_TYPE_AUDIO; + frame.marker = MPF_MARKER_NONE; + frame.codec_frame.buffer = data; + frame.codec_frame.size = size; + + if(mpf_frame_buffer_write(asr_session->media_buffer,&frame) != TRUE) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Write Audio [%d]",size); + return FALSE; + } + return TRUE; +} + /** Destroy ASR session */ ASR_CLIENT_DECLARE(apt_bool_t) asr_session_destroy(asr_session_t *asr_session) { diff --git a/libs/unimrcp/platforms/libunimrcp-client/include/unimrcp_client.h b/libs/unimrcp/platforms/libunimrcp-client/include/unimrcp_client.h index 152f856374..2efff488c4 100644 --- a/libs/unimrcp/platforms/libunimrcp-client/include/unimrcp_client.h +++ b/libs/unimrcp/platforms/libunimrcp-client/include/unimrcp_client.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: unimrcp_client.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __UNIMRCP_CLIENT_H__ -#define __UNIMRCP_CLIENT_H__ +#ifndef UNIMRCP_CLIENT_H +#define UNIMRCP_CLIENT_H /** * @file unimrcp_client.h @@ -35,4 +37,4 @@ MRCP_DECLARE(mrcp_client_t*) unimrcp_client_create(apt_dir_layout_t *dir_layout) APT_END_EXTERN_C -#endif /*__UNIMRCP_CLIENT_H__*/ +#endif /* UNIMRCP_CLIENT_H */ diff --git a/libs/unimrcp/platforms/libunimrcp-client/libunimrcpclient.2008.vcproj b/libs/unimrcp/platforms/libunimrcp-client/libunimrcpclient.2008.vcproj deleted file mode 100644 index cee4d73515..0000000000 --- a/libs/unimrcp/platforms/libunimrcp-client/libunimrcpclient.2008.vcproj +++ /dev/null @@ -1,156 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/unimrcp/platforms/libunimrcp-client/libunimrcpclient.vcproj b/libs/unimrcp/platforms/libunimrcp-client/libunimrcpclient.vcproj index 1d78a98519..170941bc41 100644 --- a/libs/unimrcp/platforms/libunimrcp-client/libunimrcpclient.vcproj +++ b/libs/unimrcp/platforms/libunimrcp-client/libunimrcpclient.vcproj @@ -244,6 +244,10 @@ Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + diff --git a/libs/unimrcp/platforms/libunimrcp-client/src/unimrcp_client.c b/libs/unimrcp/platforms/libunimrcp-client/src/unimrcp_client.c index b8eda6546d..3ef85f3329 100644 --- a/libs/unimrcp/platforms/libunimrcp-client/src/unimrcp_client.c +++ b/libs/unimrcp/platforms/libunimrcp-client/src/unimrcp_client.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,12 +12,16 @@ * 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. + * + * $Id: unimrcp_client.c 1750 2010-07-23 19:33:34Z achaloyan $ */ #include #include -#include "unimrcp_client.h" +#include +#include #include "uni_version.h" +#include "unimrcp_client.h" #include "mrcp_resource_loader.h" #include "mpf_engine.h" #include "mpf_codec_manager.h" @@ -31,10 +35,8 @@ #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_IP_ADDRESS "127.0.0.1" +#define DEFAULT_SIP_PORT 8062 #define DEFAULT_RTP_PORT_MIN 4000 #define DEFAULT_RTP_PORT_MAX 5000 @@ -42,17 +44,40 @@ #define DEFAULT_SDP_ORIGIN "UniMRCPClient" #define DEFAULT_RESOURCE_LOCATION "media" -#define XML_FILE_BUFFER_LENGTH 2000 +#define XML_FILE_BUFFER_LENGTH 16000 + +/** UniMRCP client loader */ +typedef struct unimrcp_client_loader_t unimrcp_client_loader_t; + +/** UniMRCP client loader */ +struct unimrcp_client_loader_t { + /** MRCP client */ + mrcp_client_t *client; + /** XML document */ + apr_xml_doc *doc; + /** Pool to allocate memory from */ + apr_pool_t *pool; + + /** Default ip address (named property) */ + const char *ip; + /** Default external (NAT) ip address (named property) */ + const char *ext_ip; + /** Default server ip address (named property) */ + const char *server_ip; + + /** Implicitly detected, cached ip address */ + const char *auto_ip; +}; -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); +static apt_bool_t unimrcp_client_load(unimrcp_client_loader_t *loader, const char *dir_path, const char *file_name, apr_pool_t *pool); -/** Start UniMRCP client */ +/** Create and load 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_client_t *client; + const char *dir_path; + unimrcp_client_loader_t *loader; if(!dir_layout) { return NULL; @@ -69,51 +94,94 @@ MRCP_DECLARE(mrcp_client_t*) unimrcp_client_create(apt_dir_layout_t *dir_layout) return NULL; } - doc = unimrcp_client_config_parse(dir_layout->conf_dir_path,pool); - if(doc) { - unimrcp_client_config_load(client,doc,pool); + loader = apr_palloc(pool,sizeof(unimrcp_client_loader_t)); + loader->doc = NULL; + loader->client = client; + loader->pool = pool; + loader->ip = NULL; + loader->ext_ip = NULL; + loader->server_ip = NULL; + loader->auto_ip = NULL; + + dir_path = dir_layout->conf_dir_path; + if(!dir_path) { + dir_path = DEFAULT_CONF_DIR_PATH; + } + + if(unimrcp_client_load(loader,dir_path,CONF_FILE_NAME,pool) == FALSE) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Load UniMRCP Client Document"); } return client; } -/** Parse config file */ -static apr_xml_doc* unimrcp_client_config_parse(const char *dir_path, apr_pool_t *pool) +/** Check whether specified attribute is valid */ +static APR_INLINE apt_bool_t is_attr_valid(const apr_xml_attr *attr) { - apr_xml_parser *parser = NULL; - apr_xml_doc *doc = NULL; - apr_file_t *fd = NULL; - apr_status_t rv; - const char *file_path; + return (attr && attr->value && attr->value != '\0'); +} - 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); +/** Check whether specified attribute is enabled (true) */ +static APR_INLINE apt_bool_t is_attr_enabled(const apr_xml_attr *attr) +{ + if(attr && strcasecmp(attr->value,"false") == 0) { + return FALSE; } + return TRUE; +} - 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; - } +/** Check whether cdata is valid */ +static APR_INLINE apt_bool_t is_cdata_valid(const apr_xml_elem *elem) +{ + return (elem->first_cdata.first && elem->first_cdata.first->text); +} - 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); - doc = NULL; +/** Get text cdata */ +static APR_INLINE const char* cdata_text_get(const apr_xml_elem *elem) +{ + return elem->first_cdata.first->text; +} + +/** Get boolean cdata */ +static APR_INLINE apt_bool_t cdata_bool_get(const apr_xml_elem *elem) +{ + return (strcasecmp(elem->first_cdata.first->text,"true") == 0) ? TRUE : FALSE; +} + +/** Copy cdata */ +static APR_INLINE char* cdata_copy(const apr_xml_elem *elem, apr_pool_t *pool) +{ + return apr_pstrdup(pool,elem->first_cdata.first->text); +} + +/** Get generic "id" and "enable" attributes */ +static apt_bool_t header_attribs_get(const apr_xml_elem *elem, const apr_xml_attr **id, const apr_xml_attr **enable) +{ + const apr_xml_attr *attr; + if(!id || !enable) { + return FALSE; } - apr_file_close(fd); - return doc; + *id = NULL; + *enable = NULL; + for(attr = elem->attr; attr; attr = attr->next) { + if(strcasecmp(attr->name,"id") == 0) { + *id = attr; + } + else if(strcasecmp(attr->name,"enable") == 0) { + *enable = attr; + } + } + + if(is_attr_valid(*id) == FALSE) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Missing Required Attribute in Element <%s>",elem->name); + return FALSE; + } + return TRUE; } -static apt_bool_t param_name_value_get(const apr_xml_elem *elem, const apr_xml_attr **name, const apr_xml_attr **value) +/** Get generic "name" and "value" attributes */ +static apt_bool_t name_value_attribs_get(const apr_xml_elem *elem, const apr_xml_attr **name, const apr_xml_attr **value) { const apr_xml_attr *attr; if(!name || !value) { @@ -133,531 +201,925 @@ static apt_bool_t param_name_value_get(const apr_xml_elem *elem, const apr_xml_a return (*name && *value) ? TRUE : FALSE; } -static char* ip_addr_get(const char *value, apr_pool_t *pool) +static char* unimrcp_client_ip_address_get(unimrcp_client_loader_t *loader, const apr_xml_elem *elem, const char *default_ip) { - if(!value || strcasecmp(value,"auto") == 0) { - char *addr = DEFAULT_LOCAL_IP_ADDRESS; - apt_ip_get(&addr,pool); - return addr; + const apr_xml_attr *attr = NULL; + for(attr = elem->attr; attr; attr = attr->next) { + if(strcasecmp(attr->name,"type") == 0) { + break; + } + } + + if(attr && strcasecmp(attr->value,"auto") == 0) { + /* implicitly detect ip address, if not already detected */ + if(!loader->auto_ip) { + char *auto_addr = DEFAULT_IP_ADDRESS; + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Detecting IP Address"); + apt_ip_get(&auto_addr,loader->pool); + loader->auto_ip = auto_addr; + } + return apr_pstrdup(loader->pool,loader->auto_ip); } - return apr_pstrdup(pool,value); + + if(is_cdata_valid(elem)) { + /* use specified ip address */ + return cdata_copy(elem,loader->pool); + } + + /* use default ip address */ + return apr_pstrdup(loader->pool,loader->ip); } -/** 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) + + +/** Load resource */ +static apt_bool_t unimrcp_client_resource_load(mrcp_resource_loader_t *resource_loader, const apr_xml_elem *root, apr_pool_t *pool) +{ + apt_str_t resource_class; + const apr_xml_attr *id_attr; + const apr_xml_attr *enable_attr; + apt_string_reset(&resource_class); + + if(header_attribs_get(root,&id_attr,&enable_attr) == FALSE) { + return FALSE; + } + + if(is_attr_enabled(enable_attr) == FALSE) { + return TRUE; + } + + apt_string_set(&resource_class,id_attr->value); + return mrcp_resource_load(resource_loader,&resource_class); +} + +/** Load resource factory */ +static apt_bool_t unimrcp_client_resource_factory_load(unimrcp_client_loader_t *loader, const apr_xml_elem *root) { - 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"); + mrcp_resource_factory_t *resource_factory; + mrcp_resource_loader_t *resource_loader = mrcp_resource_loader_create(FALSE,loader->pool); + if(!resource_loader) { + return FALSE; + } + + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Resources"); 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); - } + if(strcasecmp(elem->name,"resource") == 0) { + unimrcp_client_resource_load(resource_loader,elem,loader->pool); } - } - return TRUE; + else { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); + } + } + + resource_factory = mrcp_resource_factory_get(resource_loader); + return mrcp_client_resource_factory_register(loader->client,resource_factory); } /** 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) +static apt_bool_t unimrcp_client_sip_uac_load(unimrcp_client_loader_t *loader, const apr_xml_elem *root, const char *id) { 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; + mrcp_sig_agent_t *agent; + mrcp_sofia_client_config_t *config; + + config = mrcp_sofiasip_client_config_alloc(loader->pool); + config->local_port = DEFAULT_SIP_PORT; config->user_agent_name = DEFAULT_SOFIASIP_UA_NAME; config->origin = DEFAULT_SDP_ORIGIN; - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading SofiaSIP Agent"); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading SofiaSIP Agent <%s>",id); 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); - } + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); + if(strcasecmp(elem->name,"sip-ip") == 0) { + config->local_ip = unimrcp_client_ip_address_get(loader,elem,loader->ip); + } + else if(strcasecmp(elem->name,"sip-ext-ip") == 0) { + config->ext_ip = unimrcp_client_ip_address_get(loader,elem,loader->ext_ip); + } + else if(strcasecmp(elem->name,"sip-port") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->local_port = (apr_port_t)atol(cdata_text_get(elem)); } } - } - return mrcp_sofiasip_client_agent_create(config,pool); + else if(strcasecmp(elem->name,"sip-transport") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->transport = cdata_copy(elem,loader->pool); + } + } + else if(strcasecmp(elem->name,"ua-name") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->user_agent_name = cdata_copy(elem,loader->pool); + } + } + else if(strcasecmp(elem->name,"sdp-origin") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->origin = cdata_copy(elem,loader->pool); + } + } + else if(strcasecmp(elem->name,"sip-t1") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->sip_t1 = atol(cdata_text_get(elem)); + } + } + else if(strcasecmp(elem->name,"sip-t2") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->sip_t2 = atol(cdata_text_get(elem)); + } + } + else if(strcasecmp(elem->name,"sip-t4") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->sip_t4 = atol(cdata_text_get(elem)); + } + } + else if(strcasecmp(elem->name,"sip-t1x64") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->sip_t1x64 = atol(cdata_text_get(elem)); + } + } + else { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); + } + } + + if(!config->local_ip) { + /* use default ip address if not specified */ + config->local_ip = apr_pstrdup(loader->pool,loader->ip); + } + if(!config->ext_ip && loader->ext_ip) { + /* use default ext ip address if not specified */ + config->ext_ip = apr_pstrdup(loader->pool,loader->ext_ip); + } + + agent = mrcp_sofiasip_client_agent_create(id,config,loader->pool); + return mrcp_client_signaling_agent_register(loader->client,agent); } /** 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) +static apt_bool_t unimrcp_client_rtsp_uac_load(unimrcp_client_loader_t *loader, const apr_xml_elem *root, const char *id) { const apr_xml_elem *elem; - rtsp_client_config_t *config = mrcp_unirtsp_client_config_alloc(pool); + mrcp_sig_agent_t *agent; + rtsp_client_config_t *config; + + config = mrcp_unirtsp_client_config_alloc(loader->pool); config->origin = DEFAULT_SDP_ORIGIN; - config->resource_location = DEFAULT_RESOURCE_LOCATION; - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading UniRTSP Agent"); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading UniRTSP Agent <%s>",id); 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); - } + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); + if(strcasecmp(elem->name,"sdp-origin") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->origin = cdata_copy(elem,loader->pool); } } - 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); - } + else if(strcasecmp(elem->name,"max-connection-count") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->max_connection_count = atol(cdata_text_get(elem)); } - if(sig_agent) { - mrcp_client_signaling_agent_register(client,sig_agent,name); + } + else if(strcasecmp(elem->name,"request-timeout") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->request_timeout = atol(cdata_text_get(elem)); } } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } - } - return TRUE; + } + + agent = mrcp_unirtsp_client_agent_create(id,config,loader->pool); + return mrcp_client_signaling_agent_register(loader->client,agent); } /** 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) +static apt_bool_t unimrcp_client_mrcpv2_uac_load(unimrcp_client_loader_t *loader, const apr_xml_elem *root, const char *id) { const apr_xml_elem *elem; + mrcp_connection_agent_t *agent; apr_size_t max_connection_count = 100; apt_bool_t offer_new_connection = FALSE; + const char *rx_buffer_size = NULL; + const char *tx_buffer_size = NULL; + const char *request_timeout = NULL; - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading MRCPv2 Agent"); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading MRCPv2 Agent <%s>",id); 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); - } + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); + if(strcasecmp(elem->name,"max-connection-count") == 0) { + if(is_cdata_valid(elem) == TRUE) { + max_connection_count = atol(cdata_text_get(elem)); } } - } - return mrcp_client_connection_agent_create(max_connection_count,offer_new_connection,pool); + else if(strcasecmp(elem->name,"offer-new-connection") == 0) { + if(is_cdata_valid(elem) == TRUE) { + offer_new_connection = atoi(cdata_text_get(elem)); + } + } + else if(strcasecmp(elem->name,"rx-buffer-size") == 0) { + if(is_cdata_valid(elem) == TRUE) { + rx_buffer_size = cdata_text_get(elem); + } + } + else if(strcasecmp(elem->name,"tx-buffer-size") == 0) { + if(is_cdata_valid(elem) == TRUE) { + tx_buffer_size = cdata_text_get(elem); + } + } + else if(strcasecmp(elem->name,"request-timeout") == 0) { + if(is_cdata_valid(elem) == TRUE) { + request_timeout = cdata_text_get(elem); + } + } + else { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); + } + } + + agent = mrcp_client_connection_agent_create(id,max_connection_count,offer_new_connection,loader->pool); + if(agent) { + if(rx_buffer_size) { + mrcp_client_connection_rx_size_set(agent,atol(rx_buffer_size)); + } + if(tx_buffer_size) { + mrcp_client_connection_tx_size_set(agent,atol(tx_buffer_size)); + } + if(request_timeout) { + mrcp_client_connection_timeout_set(agent,atol(request_timeout)); + } + } + return mrcp_client_connection_agent_register(loader->client,agent); } -/** 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) +/** Load media engine */ +static apt_bool_t unimrcp_client_media_engine_load(unimrcp_client_loader_t *loader, const apr_xml_elem *root, const char *id) { const apr_xml_elem *elem; - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Connection Agents"); + mpf_engine_t *media_engine; + unsigned long realtime_rate = 1; + + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Media Engine <%s>",id); 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); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); + if(strcasecmp(elem->name,"realtime-rate") == 0) { + if(is_cdata_valid(elem) == TRUE) { + realtime_rate = atol(cdata_text_get(elem)); } } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } - } - return TRUE; + } + + media_engine = mpf_engine_create(id,loader->pool); + if(media_engine) { + mpf_engine_scheduler_rate_set(media_engine,realtime_rate); + } + return mrcp_client_media_engine_register(loader->client,media_engine); } -/** 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) +/** Load RTP factory */ +static apt_bool_t unimrcp_client_rtp_factory_load(unimrcp_client_loader_t *loader, const apr_xml_elem *root, const char *id) { const apr_xml_elem *elem; - char *rtp_ip = DEFAULT_LOCAL_IP_ADDRESS; + char *rtp_ip = NULL; char *rtp_ext_ip = NULL; - mpf_rtp_config_t *rtp_config = mpf_rtp_config_create(pool); + mpf_termination_factory_t *rtp_factory; + mpf_rtp_config_t *rtp_config; + + rtp_config = mpf_rtp_config_alloc(loader->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"); + + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading RTP Factory <%s>",id); 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 if(strcasecmp(attr_name->value,"rtcp") == 0) { - rtp_config->rtcp = atoi(attr_value->value); - } - else if(strcasecmp(attr_name->value,"rtcp-bye") == 0) { - rtp_config->rtcp_bye_policy = atoi(attr_value->value); - } - else if(strcasecmp(attr_name->value,"rtcp-tx-interval") == 0) { - rtp_config->rtcp_tx_interval = (apr_uint16_t)atoi(attr_value->value); - } - else if(strcasecmp(attr_name->value,"rtcp-rx-resolution") == 0) { - rtp_config->rtcp_rx_resolution = (apr_uint16_t)atol(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_DEBUG,"Loading Element <%s>",elem->name); + if(strcasecmp(elem->name,"rtp-ip") == 0) { + rtp_ip = unimrcp_client_ip_address_get(loader,elem,loader->ip); + } + else if(strcasecmp(elem->name,"rtp-ext-ip") == 0) { + rtp_ext_ip = unimrcp_client_ip_address_get(loader,elem,loader->ext_ip); + } + else if(strcasecmp(elem->name,"rtp-port-min") == 0) { + if(is_cdata_valid(elem) == TRUE) { + rtp_config->rtp_port_min = (apr_port_t)atol(cdata_text_get(elem)); + } + } + else if(strcasecmp(elem->name,"rtp-port-max") == 0) { + if(is_cdata_valid(elem) == TRUE) { + rtp_config->rtp_port_max = (apr_port_t)atol(cdata_text_get(elem)); } } + else { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); + } } - apt_string_set(&rtp_config->ip,rtp_ip); + + if(rtp_ip) { + apt_string_set(&rtp_config->ip,rtp_ip); + } + else { + apt_string_set(&rtp_config->ip,loader->ip); + } if(rtp_ext_ip) { apt_string_set(&rtp_config->ext_ip,rtp_ext_ip); } - return mpf_rtp_termination_factory_create(rtp_config,pool); + else if(loader->ext_ip){ + apt_string_set(&rtp_config->ext_ip,loader->ext_ip); + } + + rtp_factory = mpf_rtp_termination_factory_create(rtp_config,loader->pool); + return mrcp_client_rtp_factory_register(loader->client,rtp_factory,id); } -/** 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) + +/** Load SIP settings */ +static apt_bool_t unimrcp_client_sip_settings_load(unimrcp_client_loader_t *loader, const apr_xml_elem *root, const char *id) { const apr_xml_elem *elem; + mrcp_sig_settings_t *settings = mrcp_signaling_settings_alloc(loader->pool); - /* create codec manager first */ - mpf_codec_manager_t *codec_manager = mpf_engine_codec_manager_create(pool); - if(codec_manager) { - mrcp_client_codec_manager_register(client,codec_manager); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading SIP Settings <%s>",id); + for(elem = root->first_child; elem; elem = elem->next) { + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); + if(strcasecmp(elem->name,"server-ip") == 0) { + settings->server_ip = unimrcp_client_ip_address_get(loader,elem,loader->server_ip); + } + else if(strcasecmp(elem->name,"server-port") == 0) { + if(is_cdata_valid(elem) == TRUE) { + settings->server_port = (apr_port_t)atol(cdata_text_get(elem)); + } + } + else if(strcasecmp(elem->name,"server-username") == 0) { + if(is_cdata_valid(elem) == TRUE) { + settings->user_name = cdata_copy(elem,loader->pool); + } + } + else if(strcasecmp(elem->name,"force-destination") == 0) { + if(is_cdata_valid(elem) == TRUE) { + settings->force_destination = cdata_bool_get(elem); + } + } + else if(strcasecmp(elem->name,"feature-tags") == 0) { + if(is_cdata_valid(elem) == TRUE) { + settings->feature_tags = cdata_copy(elem,loader->pool); + } + } + else { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); + } } + + if(!settings->server_ip) { + settings->server_ip = apr_pstrdup(loader->pool,loader->server_ip); + } + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create SIP Settings %s:%hu",settings->server_ip,settings->server_port); + return mrcp_client_signaling_settings_register(loader->client,settings,id); +} - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Media Engines"); +/** Load RTSP settings */ +static apt_bool_t unimrcp_client_rtsp_settings_load(unimrcp_client_loader_t *loader, const apr_xml_elem *root, const char *id) +{ + const apr_xml_elem *elem; + mrcp_sig_settings_t *settings = mrcp_signaling_settings_alloc(loader->pool); + settings->resource_location = DEFAULT_RESOURCE_LOCATION; + + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading RTSP Settings <%s>",id); for(elem = root->first_child; elem; elem = elem->next) { - if(strcasecmp(elem->name,"engine") == 0) { - mpf_engine_t *media_engine; - unsigned long realtime_rate = 1; - 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,"realtime-rate") == 0) { - realtime_rate = atol(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 Element <%s>",elem->name); + if(strcasecmp(elem->name,"server-ip") == 0) { + settings->server_ip = unimrcp_client_ip_address_get(loader,elem,loader->server_ip); + } + else if(strcasecmp(elem->name,"server-port") == 0) { + if(is_cdata_valid(elem) == TRUE) { + settings->server_port = (apr_port_t)atol(cdata_text_get(elem)); } - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Media Engine"); - media_engine = mpf_engine_create(pool); - if(media_engine) { - mpf_engine_scheduler_rate_set(media_engine,realtime_rate); - mrcp_client_media_engine_register(client,media_engine,name); + } + else if(strcasecmp(elem->name,"force-destination") == 0) { + if(is_cdata_valid(elem) == TRUE) { + settings->force_destination = cdata_bool_get(elem); } } - 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); - } + else if(strcasecmp(elem->name,"resource-location") == 0) { + if(is_cdata_valid(elem) == TRUE) { + settings->resource_location = cdata_copy(elem,loader->pool); } - rtp_factory = unimrcp_client_rtp_factory_load(client,elem,pool); - if(rtp_factory) { - mrcp_client_rtp_factory_register(client,rtp_factory,name); + else { + settings->resource_location = ""; } } + else if(strcasecmp(elem->name,"resource-map") == 0) { + const apr_xml_attr *name_attr; + const apr_xml_attr *value_attr; + const apr_xml_elem *child_elem; + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Resource Map"); + for(child_elem = elem->first_child; child_elem; child_elem = child_elem->next) { + if(name_value_attribs_get(child_elem,&name_attr,&value_attr) == TRUE) { + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Param %s:%s",name_attr->value,value_attr->value); + apr_table_set(settings->resource_map,name_attr->value,value_attr->value); + } + } + } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } - } - return TRUE; + } + + if(!settings->server_ip) { + settings->server_ip = apr_pstrdup(loader->pool,loader->server_ip); + } + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create RTSP Settings %s:%hu",settings->server_ip,settings->server_port); + return mrcp_client_signaling_settings_register(loader->client,settings,id); } -/** Load resource */ -static apt_bool_t unimrcp_client_resource_load(mrcp_client_t *client, mrcp_resource_loader_t *resource_loader, const apr_xml_elem *root, apr_pool_t *pool) +/** Load jitter buffer settings */ +static apt_bool_t unimrcp_client_jb_settings_load(unimrcp_client_loader_t *loader, mpf_jb_config_t *jb, const apr_xml_elem *root) { - apt_str_t resource_class; - apt_bool_t resource_enabled = TRUE; - const apr_xml_attr *attr; - apt_string_reset(&resource_class); - for(attr = root->attr; attr; attr = attr->next) { - if(strcasecmp(attr->name,"class") == 0) { - apt_string_set(&resource_class,attr->value); + const apr_xml_elem *elem; + + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Jitter Buffer Settings"); + for(elem = root->first_child; elem; elem = elem->next) { + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); + if(strcasecmp(elem->name,"playout-delay") == 0) { + if(is_cdata_valid(elem) == TRUE) { + jb->initial_playout_delay = atol(cdata_text_get(elem)); + } } - else if(strcasecmp(attr->name,"enable") == 0) { - resource_enabled = atoi(attr->value); + else if(strcasecmp(elem->name,"min-playout-delay") == 0) { + if(is_cdata_valid(elem) == TRUE) { + jb->min_playout_delay = atol(cdata_text_get(elem)); + } + } + else if(strcasecmp(elem->name,"max-playout-delay") == 0) { + if(is_cdata_valid(elem) == TRUE) { + jb->max_playout_delay = atol(cdata_text_get(elem)); + } } else { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name); + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } + return TRUE; +} - if(!resource_class.buf || !resource_enabled) { - return FALSE; +/** Load RTCP settings */ +static apt_bool_t unimrcp_client_rtcp_settings_load(unimrcp_client_loader_t *loader, mpf_rtp_settings_t *rtcp_settings, const apr_xml_elem *root) +{ + const apr_xml_elem *elem; + const apr_xml_attr *attr = NULL; + for(attr = root->attr; attr; attr = attr->next) { + if(strcasecmp(attr->name,"enable") == 0) { + break; + } } - return mrcp_resource_load(resource_loader,&resource_class); + if(is_attr_enabled(attr) == FALSE) { + /* RTCP is disabled, skip the rest */ + return TRUE; + } + + rtcp_settings->rtcp = TRUE; + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading RTCP Settings"); + for(elem = root->first_child; elem; elem = elem->next) { + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); + if(strcasecmp(elem->name,"rtcp-bye") == 0) { + if(is_cdata_valid(elem) == TRUE) { + rtcp_settings->rtcp_bye_policy = atoi(cdata_text_get(elem)); + } + } + else if(strcasecmp(elem->name,"tx-interval") == 0) { + if(is_cdata_valid(elem) == TRUE) { + rtcp_settings->rtcp_tx_interval = (apr_uint16_t)atoi(cdata_text_get(elem)); + } + } + else if(strcasecmp(elem->name,"rx-resolution") == 0) { + if(is_cdata_valid(elem) == TRUE) { + rtcp_settings->rtcp_rx_resolution = (apr_uint16_t)atol(cdata_text_get(elem)); + } + } + else { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); + } + } + return TRUE; } -/** Load resources */ -static apt_bool_t unimrcp_client_resources_load(mrcp_client_t *client, const apr_xml_elem *root, apr_pool_t *pool) +/** Load RTP settings */ +static apt_bool_t unimrcp_client_rtp_settings_load(unimrcp_client_loader_t *loader, const apr_xml_elem *root, const char *id) { const apr_xml_elem *elem; - mrcp_resource_factory_t *resource_factory; - mrcp_resource_loader_t *resource_loader = mrcp_resource_loader_create(FALSE,pool); - if(!resource_loader) { - return FALSE; - } + mpf_rtp_settings_t *rtp_settings = mpf_rtp_settings_alloc(loader->pool); - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Resources"); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading RTP Settings <%s>",id); for(elem = root->first_child; elem; elem = elem->next) { - if(strcasecmp(elem->name,"resource") == 0) { - unimrcp_client_resource_load(client,resource_loader,elem,pool); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); + if(strcasecmp(elem->name,"jitter-buffer") == 0) { + unimrcp_client_jb_settings_load(loader,&rtp_settings->jb_config,elem); + } + else if(strcasecmp(elem->name,"ptime") == 0) { + if(is_cdata_valid(elem) == TRUE) { + rtp_settings->ptime = (apr_uint16_t)atol(cdata_text_get(elem)); + } + } + else if(strcasecmp(elem->name,"codecs") == 0) { + const mpf_codec_manager_t *codec_manager = mrcp_client_codec_manager_get(loader->client); + if(is_cdata_valid(elem) == TRUE && codec_manager) { + mpf_codec_manager_codec_list_load( + codec_manager, + &rtp_settings->codec_list, + cdata_text_get(elem), + loader->pool); + } + } + else if(strcasecmp(elem->name,"rtcp") == 0) { + unimrcp_client_rtcp_settings_load(loader,rtp_settings,elem); } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } - - resource_factory = mrcp_resource_factory_get(resource_loader); - mrcp_client_resource_factory_register(client,resource_factory); - return TRUE; + + return mrcp_client_rtp_settings_register(loader->client,rtp_settings,id); } -/** Load settings */ -static apt_bool_t unimrcp_client_settings_load(mrcp_client_t *client, const apr_xml_elem *root, apr_pool_t *pool) +/** Load MRCPv2 profile */ +static apt_bool_t unimrcp_client_mrcpv2_profile_load(unimrcp_client_loader_t *loader, const apr_xml_elem *root, const char *id) { const apr_xml_elem *elem; - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Settings"); + mrcp_profile_t *profile; + mrcp_sig_agent_t *sip_agent = NULL; + mrcp_connection_agent_t *mrcpv2_agent = NULL; + mpf_engine_t *media_engine = NULL; + mpf_termination_factory_t *rtp_factory = NULL; + mpf_rtp_settings_t *rtp_settings = NULL; + mrcp_sig_settings_t *sip_settings = NULL; + + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading MRCPv2 Profile <%s>",id); for(elem = root->first_child; elem; elem = elem->next) { - if(strcasecmp(elem->name,"signaling") == 0) { - unimrcp_client_signaling_agents_load(client,elem,pool); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); + + if(is_cdata_valid(elem) == FALSE) { + continue; + } + + if(strcasecmp(elem->name,"sip-uac") == 0) { + sip_agent = mrcp_client_signaling_agent_get(loader->client,cdata_text_get(elem)); + } + else if(strcasecmp(elem->name,"mrcpv2-uac") == 0) { + mrcpv2_agent = mrcp_client_connection_agent_get(loader->client,cdata_text_get(elem)); + } + else if(strcasecmp(elem->name,"media-engine") == 0) { + media_engine = mrcp_client_media_engine_get(loader->client,cdata_text_get(elem)); + } + else if(strcasecmp(elem->name,"rtp-factory") == 0) { + rtp_factory = mrcp_client_rtp_factory_get(loader->client,cdata_text_get(elem)); } - else if(strcasecmp(elem->name,"connection") == 0) { - unimrcp_client_connection_agents_load(client,elem,pool); + else if(strcasecmp(elem->name,"sip-settings") == 0) { + sip_settings = mrcp_client_signaling_settings_get(loader->client,cdata_text_get(elem)); } - else if(strcasecmp(elem->name,"media") == 0) { - unimrcp_client_media_engines_load(client,elem,pool); + else if(strcasecmp(elem->name,"rtp-settings") == 0) { + rtp_settings = mrcp_client_rtp_settings_get(loader->client,cdata_text_get(elem)); } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } - } - return TRUE; + } + + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create MRCPv2 Profile [%s]",id); + profile = mrcp_client_profile_create( + NULL,sip_agent,mrcpv2_agent, + media_engine,rtp_factory, + rtp_settings,sip_settings, + loader->pool); + return mrcp_client_profile_register(loader->client,profile,id); } -/** Load profile */ -static apt_bool_t unimrcp_client_profile_load(mrcp_client_t *client, const apr_xml_elem *root, apr_pool_t *pool) +/** Load MRCPv1 profile */ +static apt_bool_t unimrcp_client_mrcpv1_profile_load(unimrcp_client_loader_t *loader, const apr_xml_elem *root, const char *id) { - const char *name = NULL; + const apr_xml_elem *elem; mrcp_profile_t *profile; - mrcp_sig_agent_t *sig_agent = NULL; - mrcp_connection_agent_t *cnt_agent = NULL; + mrcp_sig_agent_t *rtsp_agent = NULL; mpf_engine_t *media_engine = NULL; mpf_termination_factory_t *rtp_factory = NULL; + mpf_rtp_settings_t *rtp_settings = NULL; + mrcp_sig_settings_t *rtsp_settings = NULL; + + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading MRCPv1 Profile <%s>",id); + for(elem = root->first_child; elem; elem = elem->next) { + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); + + if(is_cdata_valid(elem) == FALSE) { + continue; + } + + if(strcasecmp(elem->name,"rtsp-uac") == 0) { + rtsp_agent = mrcp_client_signaling_agent_get(loader->client,cdata_text_get(elem)); + } + else if(strcasecmp(elem->name,"media-engine") == 0) { + media_engine = mrcp_client_media_engine_get(loader->client,cdata_text_get(elem)); + } + else if(strcasecmp(elem->name,"rtp-factory") == 0) { + rtp_factory = mrcp_client_rtp_factory_get(loader->client,cdata_text_get(elem)); + } + else if(strcasecmp(elem->name,"rtsp-settings") == 0) { + rtsp_settings = mrcp_client_signaling_settings_get(loader->client,cdata_text_get(elem)); + } + else if(strcasecmp(elem->name,"rtp-settings") == 0) { + rtp_settings = mrcp_client_rtp_settings_get(loader->client,cdata_text_get(elem)); + } + else { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); + } + } + + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create MRCPv1 Profile [%s]",id); + profile = mrcp_client_profile_create( + NULL,rtsp_agent,NULL, + media_engine,rtp_factory, + rtp_settings,rtsp_settings, + loader->pool); + return mrcp_client_profile_register(loader->client,profile,id); +} + + +/** Load properties */ +static apt_bool_t unimrcp_client_properties_load(unimrcp_client_loader_t *loader, const apr_xml_elem *root) +{ 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); + + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Properties"); + for(elem = root->first_child; elem; elem = elem->next) { + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); + if(strcasecmp(elem->name,"ip") == 0) { + loader->ip = unimrcp_client_ip_address_get(loader,elem,DEFAULT_IP_ADDRESS); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set Property ip:%s",loader->ip); + } + else if(strcasecmp(elem->name,"ext-ip") == 0) { + loader->ext_ip = unimrcp_client_ip_address_get(loader,elem,DEFAULT_IP_ADDRESS); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set Property ext-ip:%s",loader->ext_ip); + } + else if(strcasecmp(elem->name,"server-ip") == 0) { + loader->server_ip = unimrcp_client_ip_address_get(loader,elem,DEFAULT_IP_ADDRESS); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set Property server-ip:%s",loader->server_ip); } else { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name); + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } - if(!name) { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Load Profile: no profile name specified"); - return FALSE; + + if(!loader->ip) { + loader->ip = DEFAULT_IP_ADDRESS; + } + if(!loader->server_ip) { + loader->server_ip = loader->ip; + } + return TRUE; +} + +/** Load components */ +static apt_bool_t unimrcp_client_components_load(unimrcp_client_loader_t *loader, const apr_xml_elem *root) +{ + const apr_xml_elem *elem; + const apr_xml_attr *id_attr; + const apr_xml_attr *enable_attr; + const char *id; + + /* Create codec manager first (probably it should be loaded from config either) */ + mpf_codec_manager_t *codec_manager = mpf_engine_codec_manager_create(loader->pool); + if(codec_manager) { + mrcp_client_codec_manager_register(loader->client,codec_manager); } + + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Components"); 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); - } - } + if(strcasecmp(elem->name,"resource-factory") == 0) { + unimrcp_client_resource_factory_load(loader,elem); + continue; } - } + + /* get common "id" and "enable" attributes */ + if(header_attribs_get(elem,&id_attr,&enable_attr) == FALSE) { + /* invalid id */ + continue; + } + if(is_attr_enabled(enable_attr) == FALSE) { + /* disabled element, just skip it */ + continue; + } + id = apr_pstrdup(loader->pool,id_attr->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); + if(strcasecmp(elem->name,"sip-uac") == 0) { + unimrcp_client_sip_uac_load(loader,elem,id); + } + else if(strcasecmp(elem->name,"rtsp-uac") == 0) { + unimrcp_client_rtsp_uac_load(loader,elem,id); + } + else if(strcasecmp(elem->name,"mrcpv2-uac") == 0) { + unimrcp_client_mrcpv2_uac_load(loader,elem,id); + } + else if(strcasecmp(elem->name,"media-engine") == 0) { + unimrcp_client_media_engine_load(loader,elem,id); + } + else if(strcasecmp(elem->name,"rtp-factory") == 0) { + unimrcp_client_rtp_factory_load(loader,elem,id); + } + 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(unimrcp_client_loader_t *loader, const apr_xml_elem *root) +{ + const apr_xml_elem *elem; + const apr_xml_attr *id_attr; + const apr_xml_attr *enable_attr; + const char *id; + + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Settings"); + for(elem = root->first_child; elem; elem = elem->next) { + /* get common "id" and "enable" attributes */ + if(header_attribs_get(elem,&id_attr,&enable_attr) == FALSE) { + /* invalid id */ + continue; + } + if(is_attr_enabled(enable_attr) == FALSE) { + /* disabled element, just skip it */ + continue; + } + id = apr_pstrdup(loader->pool,id_attr->value); + + if(strcasecmp(elem->name,"sip-settings") == 0) { + unimrcp_client_sip_settings_load(loader,elem,id); + } + else if(strcasecmp(elem->name,"rtsp-settings") == 0) { + unimrcp_client_rtsp_settings_load(loader,elem,id); + } + else if(strcasecmp(elem->name,"rtp-settings") == 0) { + unimrcp_client_rtp_settings_load(loader,elem,id); + } + else { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); + } + } + return TRUE; } /** Load profiles */ -static apt_bool_t unimrcp_client_profiles_load(mrcp_client_t *client, const apr_xml_elem *root, apr_pool_t *pool) +static apt_bool_t unimrcp_client_profiles_load(unimrcp_client_loader_t *loader, const apr_xml_elem *root) { const apr_xml_elem *elem; + const apr_xml_attr *id_attr; + const apr_xml_attr *enable_attr; + const char *id; + 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); + /* get common "id" and "enable" attributes */ + if(header_attribs_get(elem,&id_attr,&enable_attr) == FALSE) { + /* invalid id */ + continue; + } + if(is_attr_enabled(enable_attr) == FALSE) { + /* disabled element, just skip it */ + continue; + } + id = apr_pstrdup(loader->pool,id_attr->value); + + if(strcasecmp(elem->name,"mrcpv2-profile") == 0) { + unimrcp_client_mrcpv2_profile_load(loader,elem,id); + } + else if(strcasecmp(elem->name,"mrcpv1-profile") == 0) { + unimrcp_client_mrcpv1_profile_load(loader,elem,id); } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } + } + return TRUE; +} + +/** Parse XML document */ +static apr_xml_doc* unimrcp_client_doc_parse(const char *file_path, apr_pool_t *pool) +{ + apr_xml_parser *parser = NULL; + apr_xml_doc *xml_doc = NULL; + apr_file_t *fd = NULL; + apr_status_t rv; + + 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; } - return TRUE; + + rv = apr_xml_parse_file(pool,&parser,&xml_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); + xml_doc = NULL; + } + + apr_file_close(fd); + return xml_doc; } -/** 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) +/** Load UniMRCP client */ +static apt_bool_t unimrcp_client_load(unimrcp_client_loader_t *loader, const char *dir_path, const char *file_name, apr_pool_t *pool) { + apr_xml_doc *doc; const apr_xml_elem *elem; - const apr_xml_elem *root = doc->root; + const apr_xml_elem *root; + const apr_xml_attr *attr; + const char *file_path; + const char *version = NULL; + const char *subfolder = NULL; + + if(!dir_path || !file_name) { + return FALSE; + } + + if(*dir_path == '\0') { + file_path = file_name; + } + else { + file_path = apr_psprintf(pool,"%s/%s",dir_path,file_name); + } + + /* Parse XML document */ + doc = unimrcp_client_doc_parse(file_path,pool); + if(!doc) { + return FALSE; + } + + root = doc->root; + + /* Match document name */ if(!root || strcasecmp(root->name,"unimrcpclient") != 0) { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Document"); + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Document <%s>",root->name); + return FALSE; + } + + /* Read attributes */ + for(attr = root->attr; attr; attr = attr->next) { + if(strcasecmp(attr->name,"version") == 0) { + version = attr->value; + } + else if(strcasecmp(attr->name,"subfolder") == 0) { + subfolder = attr->value; + } + } + + /* Check version number first */ + if(!version) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Version"); return FALSE; } + + loader->doc = doc; + + /* Navigate through document */ for(elem = root->first_child; elem; elem = elem->next) { - if(strcasecmp(elem->name,"resources") == 0) { - unimrcp_client_resources_load(client,elem,pool); + if(strcasecmp(elem->name,"properties") == 0) { + unimrcp_client_properties_load(loader,elem); + } + else if(strcasecmp(elem->name,"components") == 0) { + unimrcp_client_components_load(loader,elem); } else if(strcasecmp(elem->name,"settings") == 0) { - unimrcp_client_settings_load(client,elem,pool); + unimrcp_client_settings_load(loader,elem); } else if(strcasecmp(elem->name,"profiles") == 0) { - unimrcp_client_profiles_load(client,elem,pool); + unimrcp_client_profiles_load(loader,elem); } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } - + + if(subfolder && subfolder != '\0') { + apr_dir_t *dir; + apr_finfo_t finfo; + apr_status_t rv; + + dir_path = apr_psprintf(pool,"%s/%s",dir_path,subfolder); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Enter Directory [%s]",dir_path); + rv = apr_dir_open(&dir,dir_path,pool); + if(rv == APR_SUCCESS) { + while(apr_dir_read(&finfo, APR_FINFO_NAME, dir) == APR_SUCCESS) { + if(apr_fnmatch("*.xml", finfo.name, 0) == APR_SUCCESS) { + unimrcp_client_load(loader,dir_path,finfo.name,pool); + } + } + apr_dir_close(dir); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Leave Directory [%s]",dir_path); + } + else { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Such Directory %s",dir_path); + } + } return TRUE; } diff --git a/libs/unimrcp/platforms/libunimrcp-server/include/unimrcp_server.h b/libs/unimrcp/platforms/libunimrcp-server/include/unimrcp_server.h index 39f3813048..c66fb74e56 100644 --- a/libs/unimrcp/platforms/libunimrcp-server/include/unimrcp_server.h +++ b/libs/unimrcp/platforms/libunimrcp-server/include/unimrcp_server.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: unimrcp_server.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __UNIMRCP_SERVER_H__ -#define __UNIMRCP_SERVER_H__ +#ifndef UNIMRCP_SERVER_H +#define UNIMRCP_SERVER_H /** * @file unimrcp_server.h @@ -40,4 +42,4 @@ MRCP_DECLARE(apt_bool_t) unimrcp_server_shutdown(mrcp_server_t *server); APT_END_EXTERN_C -#endif /*__UNIMRCP_SERVER_H__*/ +#endif /* UNIMRCP_SERVER_H */ diff --git a/libs/unimrcp/platforms/libunimrcp-server/libunimrcpserver.2008.vcproj b/libs/unimrcp/platforms/libunimrcp-server/libunimrcpserver.2008.vcproj deleted file mode 100644 index d1b51c7929..0000000000 --- a/libs/unimrcp/platforms/libunimrcp-server/libunimrcpserver.2008.vcproj +++ /dev/null @@ -1,156 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/unimrcp/platforms/libunimrcp-server/libunimrcpserver.vcproj b/libs/unimrcp/platforms/libunimrcp-server/libunimrcpserver.vcproj index 877610a9a3..0f5b68f4e9 100644 --- a/libs/unimrcp/platforms/libunimrcp-server/libunimrcpserver.vcproj +++ b/libs/unimrcp/platforms/libunimrcp-server/libunimrcpserver.vcproj @@ -244,6 +244,10 @@ Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + diff --git a/libs/unimrcp/platforms/libunimrcp-server/src/unimrcp_server.c b/libs/unimrcp/platforms/libunimrcp-server/src/unimrcp_server.c index d2532c6ebf..d7b23865c2 100644 --- a/libs/unimrcp/platforms/libunimrcp-server/src/unimrcp_server.c +++ b/libs/unimrcp/platforms/libunimrcp-server/src/unimrcp_server.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,12 +12,15 @@ * 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. + * + * $Id: unimrcp_server.c 1711 2010-05-25 17:54:02Z achaloyan $ */ #include #include -#include "unimrcp_server.h" +#include #include "uni_version.h" +#include "unimrcp_server.h" #include "mrcp_resource_loader.h" #include "mpf_engine.h" #include "mpf_codec_manager.h" @@ -29,7 +32,6 @@ #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" @@ -47,16 +49,37 @@ #define DEFAULT_SOFIASIP_UA_NAME "UniMRCP SofiaSIP" #define DEFAULT_SDP_ORIGIN "UniMRCPServer" -#define XML_FILE_BUFFER_LENGTH 2000 +#define XML_FILE_BUFFER_LENGTH 16000 + +/** UniMRCP server loader */ +typedef struct unimrcp_server_loader_t unimrcp_server_loader_t; + +/** UniMRCP server loader */ +struct unimrcp_server_loader_t { + /** MRCP server */ + mrcp_server_t *server; + /** Directory layout */ + apt_dir_layout_t *dir_layout; + /** XML document */ + apr_xml_doc *doc; + /** Pool to allocate memory from */ + apr_pool_t *pool; -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); + /** Default ip address (named property) */ + const char *ip; + /** Default external (NAT) ip address (named property) */ + const char *ext_ip; + + /** Implicitly detected, cached ip address */ + const char *auto_ip; +}; + +static apt_bool_t unimrcp_server_load(mrcp_server_t *mrcp_server, apt_dir_layout_t *dir_layout, 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_server_t *server; if(!dir_layout) { @@ -74,9 +97,8 @@ MRCP_DECLARE(mrcp_server_t*) unimrcp_server_start(apt_dir_layout_t *dir_layout) return NULL; } - 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); + if(unimrcp_server_load(server,dir_layout,pool) == FALSE) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Load UniMRCP Server Document"); } mrcp_server_start(server); @@ -93,43 +115,73 @@ MRCP_DECLARE(apt_bool_t) unimrcp_server_shutdown(mrcp_server_t *server) } -/** Parse config file */ -static apr_xml_doc* unimrcp_server_config_parse(const char *dir_path, apr_pool_t *pool) +/** Check whether specified attribute is valid */ +static APR_INLINE apt_bool_t is_attr_valid(const apr_xml_attr *attr) { - apr_xml_parser *parser = NULL; - apr_xml_doc *doc = NULL; - apr_file_t *fd = NULL; - apr_status_t rv; - const char *file_path; + return (attr && attr->value && attr->value != '\0'); +} - 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); +/** Check whether specified attribute is enabled (true) */ +static APR_INLINE apt_bool_t is_attr_enabled(const apr_xml_attr *attr) +{ + if(attr && strcasecmp(attr->value,"false") == 0) { + return FALSE; } + return TRUE; +} - 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; - } +/** Check whether cdata is valid */ +static APR_INLINE apt_bool_t is_cdata_valid(const apr_xml_elem *elem) +{ + return (elem->first_cdata.first && elem->first_cdata.first->text); +} - 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); - doc = NULL; +/** Get text cdata */ +static APR_INLINE const char* cdata_text_get(const apr_xml_elem *elem) +{ + return elem->first_cdata.first->text; +} + +/** Get boolean cdata */ +static APR_INLINE apt_bool_t cdata_bool_get(const apr_xml_elem *elem) +{ + return (strcasecmp(elem->first_cdata.first->text,"true") == 0) ? TRUE : FALSE; +} + +/** Copy cdata */ +static APR_INLINE char* cdata_copy(const apr_xml_elem *elem, apr_pool_t *pool) +{ + return apr_pstrdup(pool,elem->first_cdata.first->text); +} + +/** Get generic "id" and "enable" attributes */ +static apt_bool_t header_attribs_get(const apr_xml_elem *elem, const apr_xml_attr **id, const apr_xml_attr **enable) +{ + const apr_xml_attr *attr; + if(!id || !enable) { + return FALSE; } - apr_file_close(fd); - return doc; + *id = NULL; + *enable = NULL; + for(attr = elem->attr; attr; attr = attr->next) { + if(strcasecmp(attr->name,"id") == 0) { + *id = attr; + } + else if(strcasecmp(attr->name,"enable") == 0) { + *enable = attr; + } + } + + if(is_attr_valid(*id) == FALSE) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Missing Required Attribute in Element <%s>",elem->name); + return FALSE; + } + return TRUE; } -static apt_bool_t param_name_value_get(const apr_xml_elem *elem, const apr_xml_attr **name, const apr_xml_attr **value) +/** Get generic "name" and "value" attributes */ +static apt_bool_t name_value_attribs_get(const apr_xml_elem *elem, const apr_xml_attr **name, const apr_xml_attr **value) { const apr_xml_attr *attr; if(!name || !value) { @@ -149,491 +201,440 @@ static apt_bool_t param_name_value_get(const apr_xml_elem *elem, const apr_xml_a return (*name && *value) ? TRUE : FALSE; } -static char* ip_addr_get(const char *value, apr_pool_t *pool) +static char* unimrcp_server_ip_address_get(unimrcp_server_loader_t *loader, const apr_xml_elem *elem) { - if(!value || strcasecmp(value,"auto") == 0) { - char *addr = DEFAULT_IP_ADDRESS; - apt_ip_get(&addr,pool); - return addr; + const apr_xml_attr *attr = NULL; + for(attr = elem->attr; attr; attr = attr->next) { + if(strcasecmp(attr->name,"type") == 0) { + break; + } + } + + if(attr && strcasecmp(attr->value,"auto") == 0) { + /* implicitly detect ip address, if not already detected */ + if(!loader->auto_ip) { + char *auto_addr = DEFAULT_IP_ADDRESS; + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Detecting IP Address"); + apt_ip_get(&auto_addr,loader->pool); + loader->auto_ip = auto_addr; + } + return apr_pstrdup(loader->pool,loader->auto_ip); } - return apr_pstrdup(pool,value); + + if(is_cdata_valid(elem)) { + /* use provided ip address */ + return cdata_copy(elem,loader->pool); + } + + /* use default ip address */ + return apr_pstrdup(loader->pool,loader->ip); } -/** 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) +/** Load resource */ +static apt_bool_t unimrcp_server_resource_load(mrcp_resource_loader_t *resource_loader, 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; + apt_str_t resource_class; + const apr_xml_attr *id_attr; + const apr_xml_attr *enable_attr; + apt_string_reset(&resource_class); + + if(header_attribs_get(root,&id_attr,&enable_attr) == FALSE) { + return FALSE; + } + + if(is_attr_enabled(enable_attr) == FALSE) { + return TRUE; + } + + apt_string_set(&resource_class,id_attr->value); + return mrcp_resource_load(resource_loader,&resource_class); } -/** 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) +/** Load resource factory */ +static apt_bool_t unimrcp_server_resource_factory_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root) { - 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"); + mrcp_resource_factory_t *resource_factory; + mrcp_resource_loader_t *resource_loader = mrcp_resource_loader_create(FALSE,loader->pool); + if(!resource_loader) { + return FALSE; + } + + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Resources"); 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); - } + if(strcasecmp(elem->name,"resource") == 0) { + unimrcp_server_resource_load(resource_loader,elem,loader->pool); } - } - return TRUE; + else { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); + } + } + + resource_factory = mrcp_resource_factory_get(resource_loader); + return mrcp_server_resource_factory_register(loader->server,resource_factory); } /** 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) +static apt_bool_t unimrcp_server_sip_uas_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root, const char *id) { const apr_xml_elem *elem; - mrcp_sofia_server_config_t *config = mrcp_sofiasip_server_config_alloc(pool); - config->local_ip = DEFAULT_IP_ADDRESS; + mrcp_sig_agent_t *agent; + mrcp_sofia_server_config_t *config; + + config = mrcp_sofiasip_server_config_alloc(loader->pool); 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"); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading SofiaSIP Agent <%s>",id); 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); - } + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); + if(strcasecmp(elem->name,"sip-ip") == 0) { + config->local_ip = unimrcp_server_ip_address_get(loader,elem); + } + else if(strcasecmp(elem->name,"sip-ext-ip") == 0) { + config->ext_ip = unimrcp_server_ip_address_get(loader,elem); + } + else if(strcasecmp(elem->name,"sip-port") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->local_port = (apr_port_t)atol(cdata_text_get(elem)); } } - } - return mrcp_sofiasip_server_agent_create(config,pool); + else if(strcasecmp(elem->name,"sip-transport") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->transport = cdata_copy(elem,loader->pool); + } + } + else if(strcasecmp(elem->name,"ua-name") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->user_agent_name = cdata_copy(elem,loader->pool); + } + } + else if(strcasecmp(elem->name,"sdp-origin") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->origin = cdata_copy(elem,loader->pool); + } + } + else if(strcasecmp(elem->name,"force-destination") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->force_destination = cdata_bool_get(elem); + } + } + else if(strcasecmp(elem->name,"sip-t1") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->sip_t1 = atol(cdata_text_get(elem)); + } + } + else if(strcasecmp(elem->name,"sip-t2") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->sip_t2 = atol(cdata_text_get(elem)); + } + } + else if(strcasecmp(elem->name,"sip-t4") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->sip_t4 = atol(cdata_text_get(elem)); + } + } + else if(strcasecmp(elem->name,"sip-t1x64") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->sip_t1x64 = atol(cdata_text_get(elem)); + } + } + else { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); + } + } + + if(!config->local_ip) { + /* use default ip address if not specified */ + config->local_ip = apr_pstrdup(loader->pool,loader->ip); + } + if(!config->ext_ip && loader->ext_ip) { + /* use default ext ip address if not specified */ + config->ext_ip = apr_pstrdup(loader->pool,loader->ext_ip); + } + + agent = mrcp_sofiasip_server_agent_create(id,config,loader->pool); + return mrcp_server_signaling_agent_register(loader->server,agent); } /** 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) +static apt_bool_t unimrcp_server_rtsp_uas_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root, const char *id) { 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; + mrcp_sig_agent_t *agent; + rtsp_server_config_t *config; + config = mrcp_unirtsp_server_config_alloc(loader->pool); + config->origin = DEFAULT_SDP_ORIGIN; - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading UniRTSP Agent"); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading UniRTSP Agent <%s>",id); 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); - } + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); + if(strcasecmp(elem->name,"rtsp-ip") == 0) { + config->local_ip = unimrcp_server_ip_address_get(loader,elem); + } + else if(strcasecmp(elem->name,"rtsp-port") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->local_port = (apr_port_t)atol(cdata_text_get(elem)); } } - else if(strcasecmp(elem->name,"resourcemap") == 0) { - resource_map_load(config->resource_map,elem,pool); + else if(strcasecmp(elem->name,"sdp-origin") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->origin = cdata_copy(elem,loader->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); - } + else if(strcasecmp(elem->name,"max-connection-count") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->max_connection_count = atol(cdata_text_get(elem)); + } + } + else if(strcasecmp(elem->name,"force-destination") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->force_destination = cdata_bool_get(elem); } - if(sig_agent) { - mrcp_server_signaling_agent_register(server,sig_agent,name); + } + else if(strcasecmp(elem->name,"resource-map") == 0) { + const apr_xml_attr *name_attr; + const apr_xml_attr *value_attr; + const apr_xml_elem *child_elem; + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Resource Map"); + for(child_elem = elem->first_child; child_elem; child_elem = child_elem->next) { + if(name_value_attribs_get(child_elem,&name_attr,&value_attr) == TRUE) { + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Param %s:%s",name_attr->value,value_attr->value); + apr_table_set(config->resource_map,name_attr->value,value_attr->value); + } } } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } - } - return TRUE; + } + + if(!config->local_ip) { + /* use default ip address if not specified */ + config->local_ip = apr_pstrdup(loader->pool,loader->ip); + } + + agent = mrcp_unirtsp_server_agent_create(id,config,loader->pool); + return mrcp_server_signaling_agent_register(loader->server,agent); } /** 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) +static apt_bool_t unimrcp_server_mrcpv2_uas_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root, const char *id) { const apr_xml_elem *elem; - char *mrcp_ip = DEFAULT_IP_ADDRESS; + mrcp_connection_agent_t *agent; + char *mrcp_ip = NULL; apr_port_t mrcp_port = DEFAULT_MRCP_PORT; apr_size_t max_connection_count = 100; apt_bool_t force_new_connection = FALSE; + apr_size_t rx_buffer_size = 0; + apr_size_t tx_buffer_size = 0; - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading MRCPv2 Agent"); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading MRCPv2 Agent <%s>",id); 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); - } + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); + if(strcasecmp(elem->name,"mrcp-ip") == 0) { + mrcp_ip = unimrcp_server_ip_address_get(loader,elem); + } + else if(strcasecmp(elem->name,"mrcp-port") == 0) { + if(is_cdata_valid(elem) == TRUE) { + mrcp_port = (apr_port_t)atol(cdata_text_get(elem)); } } - } - 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); - } + else if(strcasecmp(elem->name,"max-connection-count") == 0) { + if(is_cdata_valid(elem) == TRUE) { + max_connection_count = atol(cdata_text_get(elem)); } - connection_agent = unimrcp_server_connection_agent_load(server,elem,pool); - if(connection_agent) { - mrcp_server_connection_agent_register(server,connection_agent,name); + } + else if(strcasecmp(elem->name,"force-new-connection") == 0) { + if(is_cdata_valid(elem) == TRUE) { + force_new_connection = cdata_bool_get(elem); + } + } + else if(strcasecmp(elem->name,"rx-buffer-size") == 0) { + if(is_cdata_valid(elem) == TRUE) { + rx_buffer_size = atol(cdata_text_get(elem)); + } + } + else if(strcasecmp(elem->name,"tx-buffer-size") == 0) { + if(is_cdata_valid(elem) == TRUE) { + tx_buffer_size = atol(cdata_text_get(elem)); } } 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 if(strcasecmp(attr_name->value,"rtcp") == 0) { - rtp_config->rtcp = atoi(attr_value->value); - } - else if(strcasecmp(attr_name->value,"rtcp-bye") == 0) { - rtp_config->rtcp_bye_policy = atoi(attr_value->value); - } - else if(strcasecmp(attr_name->value,"rtcp-tx-interval") == 0) { - rtp_config->rtcp_tx_interval = (apr_uint16_t)atoi(attr_value->value); - } - else if(strcasecmp(attr_name->value,"rtcp-rx-resolution") == 0) { - rtp_config->rtcp_rx_resolution = (apr_uint16_t)atol(attr_value->value); - } - else { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr_name->value); - } - } - } + if(!mrcp_ip) { + /* use default ip address if not specified */ + mrcp_ip = apr_pstrdup(loader->pool,loader->ip); } - apt_string_set(&rtp_config->ip,rtp_ip); - if(rtp_ext_ip) { - apt_string_set(&rtp_config->ext_ip,rtp_ext_ip); + + agent = mrcp_server_connection_agent_create(id,mrcp_ip,mrcp_port,max_connection_count,force_new_connection,loader->pool); + if(agent) { + if(rx_buffer_size) { + mrcp_server_connection_rx_size_set(agent,rx_buffer_size); + } + if(tx_buffer_size) { + mrcp_server_connection_tx_size_set(agent,tx_buffer_size); + } } - return mpf_rtp_termination_factory_create(rtp_config,pool); + return mrcp_server_connection_agent_register(loader->server,agent); } -/** 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) +/** Load media engine */ +static apt_bool_t unimrcp_server_media_engine_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root, const char *id) { const apr_xml_elem *elem; + mpf_engine_t *media_engine; + unsigned long realtime_rate = 1; - /* create codec manager first */ - mpf_codec_manager_t *codec_manager = mpf_engine_codec_manager_create(pool); - if(codec_manager) { - mrcp_server_codec_manager_register(server,codec_manager); - } - - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Media Engines"); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Media Engine <%s>",id); for(elem = root->first_child; elem; elem = elem->next) { - if(strcasecmp(elem->name,"engine") == 0) { - mpf_engine_t *media_engine; - unsigned long realtime_rate = 1; - 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,"realtime-rate") == 0) { - realtime_rate = atol(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) { - mpf_engine_scheduler_rate_set(media_engine,realtime_rate); - 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); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); + if(strcasecmp(elem->name,"realtime-rate") == 0) { + if(is_cdata_valid(elem) == TRUE) { + realtime_rate = atol(cdata_text_get(elem)); } } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } - } - return TRUE; -} - -/** Load resource */ -static apt_bool_t unimrcp_server_resource_load(mrcp_server_t *server, mrcp_resource_loader_t *resource_loader, const apr_xml_elem *root, apr_pool_t *pool) -{ - apt_str_t resource_class; - apt_bool_t resource_enabled = TRUE; - const apr_xml_attr *attr; - apt_string_reset(&resource_class); - for(attr = root->attr; attr; attr = attr->next) { - if(strcasecmp(attr->name,"class") == 0) { - apt_string_set(&resource_class,attr->value); - } - else if(strcasecmp(attr->name,"enable") == 0) { - resource_enabled = atoi(attr->value); - } - else { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name); - } } - - if(!resource_class.buf || !resource_enabled) { - return FALSE; + + media_engine = mpf_engine_create(id,loader->pool); + if(media_engine) { + mpf_engine_scheduler_rate_set(media_engine,realtime_rate); } - - return mrcp_resource_load(resource_loader,&resource_class); + return mrcp_server_media_engine_register(loader->server,media_engine); } -/** Load resources */ -static apt_bool_t unimrcp_server_resources_load(mrcp_server_t *server, const apr_xml_elem *root, apr_pool_t *pool) +/** Load RTP factory */ +static apt_bool_t unimrcp_server_rtp_factory_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root, const char *id) { const apr_xml_elem *elem; - mrcp_resource_factory_t *resource_factory; - mrcp_resource_loader_t *resource_loader = mrcp_resource_loader_create(FALSE,pool); - if(!resource_loader) { - return FALSE; - } + char *rtp_ip = NULL; + char *rtp_ext_ip = NULL; + mpf_termination_factory_t *rtp_factory; + mpf_rtp_config_t *rtp_config; - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Resources"); + rtp_config = mpf_rtp_config_alloc(loader->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 Factory <%s>",id); for(elem = root->first_child; elem; elem = elem->next) { - if(strcasecmp(elem->name,"resource") == 0) { - unimrcp_server_resource_load(server,resource_loader,elem,pool); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); + if(strcasecmp(elem->name,"rtp-ip") == 0) { + rtp_ip = unimrcp_server_ip_address_get(loader,elem); + } + else if(strcasecmp(elem->name,"rtp-ext-ip") == 0) { + rtp_ext_ip = unimrcp_server_ip_address_get(loader,elem); + } + else if(strcasecmp(elem->name,"rtp-port-min") == 0) { + if(is_cdata_valid(elem) == TRUE) { + rtp_config->rtp_port_min = (apr_port_t)atol(cdata_text_get(elem)); + } + } + else if(strcasecmp(elem->name,"rtp-port-max") == 0) { + if(is_cdata_valid(elem) == TRUE) { + rtp_config->rtp_port_max = (apr_port_t)atol(cdata_text_get(elem)); + } } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } - resource_factory = mrcp_resource_factory_get(resource_loader); - mrcp_server_resource_factory_register(server,resource_factory); - return TRUE; + if(rtp_ip) { + apt_string_set(&rtp_config->ip,rtp_ip); + } + else { + apt_string_set(&rtp_config->ip,loader->ip); + } + if(rtp_ext_ip) { + apt_string_set(&rtp_config->ext_ip,rtp_ext_ip); + } + else if(loader->ext_ip){ + apt_string_set(&rtp_config->ext_ip,loader->ext_ip); + } + + rtp_factory = mpf_rtp_termination_factory_create(rtp_config,loader->pool); + return mrcp_server_rtp_factory_register(loader->server,rtp_factory,id); } /** 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) +static apt_bool_t unimrcp_server_plugin_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root) { + mrcp_engine_t *engine; mrcp_engine_config_t *config; - const char *plugin_class = NULL; + const char *plugin_id = NULL; + const char *plugin_name = NULL; const char *plugin_ext = NULL; const char *plugin_path = NULL; apt_bool_t plugin_enabled = TRUE; const apr_xml_attr *attr; - config = mrcp_engine_config_alloc(pool); for(attr = root->attr; attr; attr = attr->next) { - if(strcasecmp(attr->name,"name") == 0) { - config->name = apr_pstrdup(pool,attr->value); + if(strcasecmp(attr->name,"id") == 0) { + plugin_id = apr_pstrdup(loader->pool,attr->value); } - else if(strcasecmp(attr->name,"class") == 0) { - plugin_class = attr->value; + else if(strcasecmp(attr->name,"name") == 0) { + plugin_name = 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 if(strcasecmp(attr->name,"max-channel-count") == 0) { - config->max_channel_count = atol(attr->value); + plugin_enabled = is_attr_enabled(attr); } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name); } } - if(!plugin_class || !plugin_enabled) { + if(!plugin_id || !plugin_name) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Missing plugin id or name"); return FALSE; } - if(!plugin_dir_path) { - plugin_dir_path = DEFAULT_PLUGIN_DIR_PATH; + + if(!plugin_enabled) { + /* disabled plugin, just skip it */ + return TRUE; } + if(!plugin_ext) { plugin_ext = DEFAULT_PLUGIN_EXT; } - if(*plugin_dir_path == '\0') { - plugin_path = apr_psprintf(pool,"%s.%s",plugin_class,plugin_ext); + if(*loader->dir_layout->plugin_dir_path == '\0') { + plugin_path = apr_psprintf(loader->pool,"%s.%s", + plugin_name,plugin_ext); } else { - plugin_path = apr_psprintf(pool,"%s/%s.%s",plugin_dir_path,plugin_class,plugin_ext); + plugin_path = apr_psprintf(loader->pool,"%s/%s.%s", + loader->dir_layout->plugin_dir_path,plugin_name,plugin_ext); } - /* load optional name/value params */ + config = mrcp_engine_config_alloc(loader->pool); + + /* load optional named and generic name/value params */ if(root->first_child){ 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 Engine Params"); - config->params = apr_table_make(pool,1); + config->params = apr_table_make(loader->pool,1); 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) { + if(strcasecmp(elem->name,"max-channel-count") == 0) { + if(is_cdata_valid(elem) == TRUE) { + config->max_channel_count = atol(cdata_text_get(elem)); + } + } + else if(strcasecmp(elem->name,"param") == 0) { + if(name_value_attribs_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(config->params,attr_name->value,attr_value->value); } @@ -641,149 +642,520 @@ static apt_bool_t unimrcp_server_plugin_load(mrcp_server_t *server, const char * } } - return mrcp_server_plugin_register(server,plugin_path,config); + engine = mrcp_server_engine_load(loader->server,plugin_id,plugin_path,config); + return mrcp_server_engine_register(loader->server,engine); } -/** 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) +/** Load plugin (engine) factory */ +static apt_bool_t unimrcp_server_plugin_factory_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root) { const apr_xml_elem *elem; - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Engine Plugins"); + + if(!loader->dir_layout->plugin_dir_path) { + loader->dir_layout->plugin_dir_path = DEFAULT_PLUGIN_DIR_PATH; + } + + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Plugin Factory"); for(elem = root->first_child; elem; elem = elem->next) { + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); if(strcasecmp(elem->name,"engine") == 0) { - unimrcp_server_plugin_load(server,plugin_dir_path,elem,pool); + unimrcp_server_plugin_load(loader,elem); } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } - } + } return TRUE; } +/** Load jitter buffer settings */ +static apt_bool_t unimrcp_server_jb_settings_load(unimrcp_server_loader_t *loader, mpf_jb_config_t *jb, const apr_xml_elem *root) +{ + const apr_xml_elem *elem; -/** 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) + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Jitter Buffer Settings"); + for(elem = root->first_child; elem; elem = elem->next) { + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); + if(strcasecmp(elem->name,"playout-delay") == 0) { + if(is_cdata_valid(elem) == TRUE) { + jb->initial_playout_delay = atol(cdata_text_get(elem)); + } + } + else if(strcasecmp(elem->name,"min-playout-delay") == 0) { + if(is_cdata_valid(elem) == TRUE) { + jb->min_playout_delay = atol(cdata_text_get(elem)); + } + } + else if(strcasecmp(elem->name,"max-playout-delay") == 0) { + if(is_cdata_valid(elem) == TRUE) { + jb->max_playout_delay = atol(cdata_text_get(elem)); + } + } + else { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); + } + } + return TRUE; +} + +/** Load RTCP settings */ +static apt_bool_t unimrcp_server_rtcp_settings_load(unimrcp_server_loader_t *loader, mpf_rtp_settings_t *rtcp_settings, const apr_xml_elem *root) { const apr_xml_elem *elem; - apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Settings"); + const apr_xml_attr *attr = NULL; + for(attr = root->attr; attr; attr = attr->next) { + if(strcasecmp(attr->name,"enable") == 0) { + break; + } + } + + if(is_attr_enabled(attr) == FALSE) { + /* RTCP is disabled, skip the rest */ + return TRUE; + } + + rtcp_settings->rtcp = TRUE; + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading RTCP Settings"); + for(elem = root->first_child; elem; elem = elem->next) { + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); + if(strcasecmp(elem->name,"rtcp-bye") == 0) { + if(is_cdata_valid(elem) == TRUE) { + rtcp_settings->rtcp_bye_policy = atoi(cdata_text_get(elem)); + } + } + else if(strcasecmp(elem->name,"tx-interval") == 0) { + if(is_cdata_valid(elem) == TRUE) { + rtcp_settings->rtcp_tx_interval = (apr_uint16_t)atoi(cdata_text_get(elem)); + } + } + else if(strcasecmp(elem->name,"rx-resolution") == 0) { + if(is_cdata_valid(elem) == TRUE) { + rtcp_settings->rtcp_rx_resolution = (apr_uint16_t)atol(cdata_text_get(elem)); + } + } + else { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); + } + } + return TRUE; +} + +/** Load RTP settings */ +static apt_bool_t unimrcp_server_rtp_settings_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root, const char *id) +{ + const apr_xml_elem *elem; + mpf_rtp_settings_t *rtp_settings = mpf_rtp_settings_alloc(loader->pool); + + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading RTP Settings <%s>",id); for(elem = root->first_child; elem; elem = elem->next) { - if(strcasecmp(elem->name,"signaling") == 0) { - unimrcp_server_signaling_agents_load(server,elem,pool); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); + if(strcasecmp(elem->name,"jitter-buffer") == 0) { + unimrcp_server_jb_settings_load(loader,&rtp_settings->jb_config,elem); } - else if(strcasecmp(elem->name,"connection") == 0) { - unimrcp_server_connection_agents_load(server,elem,pool); + else if(strcasecmp(elem->name,"ptime") == 0) { + if(is_cdata_valid(elem) == TRUE) { + rtp_settings->ptime = (apr_uint16_t)atol(cdata_text_get(elem)); + } } - else if(strcasecmp(elem->name,"media") == 0) { - unimrcp_server_media_engines_load(server,elem,pool); + else if(strcasecmp(elem->name,"codecs") == 0) { + const apr_xml_attr *attr; + const mpf_codec_manager_t *codec_manager = mrcp_server_codec_manager_get(loader->server); + if(is_cdata_valid(elem) == TRUE && codec_manager) { + mpf_codec_manager_codec_list_load( + codec_manager, + &rtp_settings->codec_list, + cdata_text_get(elem), + loader->pool); + } + for(attr = elem->attr; attr; attr = attr->next) { + if(strcasecmp(attr->name,"own-preference") == 0) { + rtp_settings->own_preferrence = is_attr_enabled(attr); + break; + } + } } - else if(strcasecmp(elem->name,"plugin") == 0) { - unimrcp_server_plugins_load(server,plugin_dir_path,elem,pool); + else if(strcasecmp(elem->name,"rtcp") == 0) { + unimrcp_server_rtcp_settings_load(loader,rtp_settings,elem); } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } - return TRUE; + + return mrcp_server_rtp_settings_register(loader->server,rtp_settings,id); +} + +/** Load map of resources and engines */ +static apr_table_t* resource_engine_map_load(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; + apr_table_t *plugin_map = apr_table_make(pool,2); + 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(name_value_attribs_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 plugin_map; +} + +/** Load MRCPv2 profile */ +static apt_bool_t unimrcp_server_mrcpv2_profile_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root, const char *id) +{ + const apr_xml_elem *elem; + mrcp_profile_t *profile; + mrcp_sig_agent_t *sip_agent = NULL; + mrcp_connection_agent_t *mrcpv2_agent = NULL; + mpf_engine_t *media_engine = NULL; + mpf_termination_factory_t *rtp_factory = NULL; + mpf_rtp_settings_t *rtp_settings = NULL; + apr_table_t *resource_engine_map = NULL; + + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading MRCPv2 Profile <%s>",id); + for(elem = root->first_child; elem; elem = elem->next) { + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); + + if(is_cdata_valid(elem) == FALSE) { + continue; + } + + if(strcasecmp(elem->name,"sip-uas") == 0) { + sip_agent = mrcp_server_signaling_agent_get(loader->server,cdata_text_get(elem)); + } + else if(strcasecmp(elem->name,"mrcpv2-uas") == 0) { + mrcpv2_agent = mrcp_server_connection_agent_get(loader->server,cdata_text_get(elem)); + } + else if(strcasecmp(elem->name,"media-engine") == 0) { + media_engine = mrcp_server_media_engine_get(loader->server,cdata_text_get(elem)); + } + else if(strcasecmp(elem->name,"rtp-factory") == 0) { + rtp_factory = mrcp_server_rtp_factory_get(loader->server,cdata_text_get(elem)); + } + else if(strcasecmp(elem->name,"rtp-settings") == 0) { + rtp_settings = mrcp_server_rtp_settings_get(loader->server,cdata_text_get(elem)); + } + else if(strcasecmp(elem->name,"resource-engine-map") == 0) { + resource_engine_map = resource_engine_map_load(elem,loader->pool); + } + else { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); + } + } + + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create MRCPv2 Profile [%s]",id); + profile = mrcp_server_profile_create( + id, + NULL, + sip_agent, + mrcpv2_agent, + media_engine, + rtp_factory, + rtp_settings, + loader->pool); + return mrcp_server_profile_register(loader->server,profile,resource_engine_map); } -/** Load profile */ -static apt_bool_t unimrcp_server_profile_load(mrcp_server_t *server, const apr_xml_elem *root, apr_pool_t *pool) +/** Load MRCPv1 profile */ +static apt_bool_t unimrcp_server_mrcpv1_profile_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root, const char *id) { - const char *name = NULL; + const apr_xml_elem *elem; mrcp_profile_t *profile; - mrcp_sig_agent_t *sig_agent = NULL; - mrcp_connection_agent_t *cnt_agent = NULL; + mrcp_sig_agent_t *rtsp_agent = NULL; mpf_engine_t *media_engine = NULL; mpf_termination_factory_t *rtp_factory = NULL; - apr_table_t *plugin_map = NULL; + mpf_rtp_settings_t *rtp_settings = NULL; + apr_table_t *resource_engine_map = NULL; + + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading MRCPv1 Profile <%s>",id); + for(elem = root->first_child; elem; elem = elem->next) { + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); + + if(is_cdata_valid(elem) == FALSE) { + continue; + } + + if(strcasecmp(elem->name,"rtsp-uas") == 0) { + rtsp_agent = mrcp_server_signaling_agent_get(loader->server,cdata_text_get(elem)); + } + else if(strcasecmp(elem->name,"media-engine") == 0) { + media_engine = mrcp_server_media_engine_get(loader->server,cdata_text_get(elem)); + } + else if(strcasecmp(elem->name,"rtp-factory") == 0) { + rtp_factory = mrcp_server_rtp_factory_get(loader->server,cdata_text_get(elem)); + } + else if(strcasecmp(elem->name,"rtp-settings") == 0) { + rtp_settings = mrcp_server_rtp_settings_get(loader->server,cdata_text_get(elem)); + } + else if(strcasecmp(elem->name,"resource-engine-map") == 0) { + resource_engine_map = resource_engine_map_load(elem,loader->pool); + } + else { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); + } + } + + apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create MRCPv1 Profile [%s]",id); + profile = mrcp_server_profile_create( + id, + NULL, + rtsp_agent, + NULL, + media_engine, + rtp_factory, + rtp_settings, + loader->pool); + return mrcp_server_profile_register(loader->server,profile,resource_engine_map); +} + + +/** Load properties */ +static apt_bool_t unimrcp_server_properties_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root) +{ 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); + + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Properties"); + for(elem = root->first_child; elem; elem = elem->next) { + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); + if(strcasecmp(elem->name,"ip") == 0) { + loader->ip = unimrcp_server_ip_address_get(loader,elem); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set Property ip:%s",loader->ip); + } + else if(strcasecmp(elem->name,"ext-ip") == 0) { + loader->ext_ip = unimrcp_server_ip_address_get(loader,elem); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set Property ext-ip:%s",loader->ext_ip); } else { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name); + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } - if(!name) { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Load Profile: no profile name specified"); - return FALSE; + return TRUE; +} + +/** Load components */ +static apt_bool_t unimrcp_server_components_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root) +{ + const apr_xml_elem *elem; + const apr_xml_attr *id_attr; + const apr_xml_attr *enable_attr; + const char *id; + + /* Create codec manager first (probably it should be loaded from config either) */ + mpf_codec_manager_t *codec_manager = mpf_engine_codec_manager_create(loader->pool); + if(codec_manager) { + mrcp_server_codec_manager_register(loader->server,codec_manager); } + + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Components"); 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); - } - } + if(strcasecmp(elem->name,"resource-factory") == 0) { + unimrcp_server_resource_factory_load(loader,elem); + continue; + } + if(strcasecmp(elem->name,"plugin-factory") == 0) { + unimrcp_server_plugin_factory_load(loader,elem); + continue; + } + + /* get common "id" and "enable" attributes */ + if(header_attribs_get(elem,&id_attr,&enable_attr) == FALSE) { + /* invalid id */ + continue; + } + if(is_attr_enabled(enable_attr) == FALSE) { + /* disabled element, just skip it */ + continue; + } + id = apr_pstrdup(loader->pool,id_attr->value); + + if(strcasecmp(elem->name,"sip-uas") == 0) { + unimrcp_server_sip_uas_load(loader,elem,id); + } + else if(strcasecmp(elem->name,"rtsp-uas") == 0) { + unimrcp_server_rtsp_uas_load(loader,elem,id); + } + else if(strcasecmp(elem->name,"mrcpv2-uas") == 0) { + unimrcp_server_mrcpv2_uas_load(loader,elem,id); + } + else if(strcasecmp(elem->name,"media-engine") == 0) { + unimrcp_server_media_engine_load(loader,elem,id); } - else if(strcasecmp(elem->name,"pluginmap") == 0) { - plugin_map = apr_table_make(pool,2); - plugin_map_load(plugin_map,elem,pool); + else if(strcasecmp(elem->name,"rtp-factory") == 0) { + unimrcp_server_rtp_factory_load(loader,elem,id); + } + else if(strcasecmp(elem->name,"plugin-factory") == 0) { + unimrcp_server_plugin_factory_load(loader,elem); + } + 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(unimrcp_server_loader_t *loader, const apr_xml_elem *root) +{ + const apr_xml_elem *elem; + const apr_xml_attr *id_attr; + const apr_xml_attr *enable_attr; + const char *id; + + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Settings"); + for(elem = root->first_child; elem; elem = elem->next) { + /* get common "id" and "enable" attributes */ + if(header_attribs_get(elem,&id_attr,&enable_attr) == FALSE) { + /* invalid id */ + continue; + } + if(is_attr_enabled(enable_attr) == FALSE) { + /* disabled element, just skip it */ + continue; + } + id = apr_pstrdup(loader->pool,id_attr->value); - 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); + if(strcasecmp(elem->name,"rtp-settings") == 0) { + unimrcp_server_rtp_settings_load(loader,elem,id); + } + else { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); + } + } + return TRUE; } /** Load profiles */ -static apt_bool_t unimrcp_server_profiles_load(mrcp_server_t *server, const apr_xml_elem *root, apr_pool_t *pool) +static apt_bool_t unimrcp_server_profiles_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root) { const apr_xml_elem *elem; + const apr_xml_attr *id_attr; + const apr_xml_attr *enable_attr; + const char *id; + 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); + /* get common "id" and "enable" attributes */ + if(header_attribs_get(elem,&id_attr,&enable_attr) == FALSE) { + /* invalid id */ + continue; + } + if(is_attr_enabled(enable_attr) == FALSE) { + /* disabled element, just skip it */ + continue; + } + id = apr_pstrdup(loader->pool,id_attr->value); + + if(strcasecmp(elem->name,"mrcpv2-profile") == 0) { + unimrcp_server_mrcpv2_profile_load(loader,elem,id); + } + else if(strcasecmp(elem->name,"mrcpv1-profile") == 0) { + unimrcp_server_mrcpv1_profile_load(loader,elem,id); } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } + } + return TRUE; +} + +/** Parse XML document */ +static apr_xml_doc* unimrcp_server_doc_parse(const char *file_path, apr_pool_t *pool) +{ + apr_xml_parser *parser = NULL; + apr_xml_doc *xml_doc = NULL; + apr_file_t *fd = NULL; + apr_status_t rv; + + 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,&xml_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); + xml_doc = NULL; } - return TRUE; + + apr_file_close(fd); + return xml_doc; } -/** 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) +static apt_bool_t unimrcp_server_load(mrcp_server_t *mrcp_server, apt_dir_layout_t *dir_layout, apr_pool_t *pool) { + const char *file_path; + apr_xml_doc *doc; const apr_xml_elem *elem; - const apr_xml_elem *root = doc->root; + const apr_xml_elem *root; + const apr_xml_attr *attr; + unimrcp_server_loader_t *loader; + const char *version = NULL; + + file_path = apt_confdir_filepath_get(dir_layout,CONF_FILE_NAME,pool); + if(!file_path) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Get Path to Conf File [%s]",CONF_FILE_NAME); + return FALSE; + } + + /* Parse XML document */ + doc = unimrcp_server_doc_parse(file_path,pool); + if(!doc) { + return FALSE; + } + + root = doc->root; + + /* Match document name */ if(!root || strcasecmp(root->name,"unimrcpserver") != 0) { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Document"); + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Document <%s>",root->name); return FALSE; } + + /* Read attributes */ + for(attr = root->attr; attr; attr = attr->next) { + if(strcasecmp(attr->name,"version") == 0) { + version = attr->value; + } + } + + /* Check version number first */ + if(!version) { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Version"); + return FALSE; + } + + loader = apr_palloc(pool,sizeof(unimrcp_server_loader_t)); + loader->doc = doc; + loader->server = mrcp_server; + loader->dir_layout = dir_layout; + loader->pool = pool; + loader->ip = DEFAULT_IP_ADDRESS; + loader->ext_ip = NULL; + loader->auto_ip = NULL; + + /* Navigate through document */ for(elem = root->first_child; elem; elem = elem->next) { - if(strcasecmp(elem->name,"resources") == 0) { - unimrcp_server_resources_load(server,elem,pool); + if(strcasecmp(elem->name,"properties") == 0) { + unimrcp_server_properties_load(loader,elem); + } + else if(strcasecmp(elem->name,"components") == 0) { + unimrcp_server_components_load(loader,elem); } else if(strcasecmp(elem->name,"settings") == 0) { - unimrcp_server_settings_load(server,plugin_dir_path,elem,pool); + unimrcp_server_settings_load(loader,elem); } else if(strcasecmp(elem->name,"profiles") == 0) { - unimrcp_server_profiles_load(server,elem,pool); + unimrcp_server_profiles_load(loader,elem); } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } - return TRUE; } diff --git a/libs/unimrcp/platforms/umc/Makefile.am b/libs/unimrcp/platforms/umc/Makefile.am index 9e450119c8..a33ddfdd0f 100644 --- a/libs/unimrcp/platforms/umc/Makefile.am +++ b/libs/unimrcp/platforms/umc/Makefile.am @@ -28,7 +28,10 @@ umc_SOURCES = src/main.cpp \ src/dtmfscenario.cpp \ src/dtmfsession.cpp \ src/setparamscenario.cpp \ - src/setparamsession.cpp + src/setparamsession.cpp \ + src/verifierscenario.cpp \ + src/verifiersession.cpp + umc_LDADD = $(top_builddir)/platforms/libunimrcp-client/libunimrcpclient.la if ISMAC diff --git a/libs/unimrcp/platforms/umc/include/dtmfscenario.h b/libs/unimrcp/platforms/umc/include/dtmfscenario.h index 63aab623c4..45a5430cf7 100644 --- a/libs/unimrcp/platforms/umc/include/dtmfscenario.h +++ b/libs/unimrcp/platforms/umc/include/dtmfscenario.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: dtmfscenario.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __DTMF_SCENARIO_H__ -#define __DTMF_SCENARIO_H__ +#ifndef DTMF_SCENARIO_H +#define DTMF_SCENARIO_H /** * @file dtmfscenario.h @@ -72,4 +74,4 @@ inline const char* DtmfScenario::GetDigits() const } -#endif /*__DTMF_SCENARIO_H__*/ +#endif /* DTMF_SCENARIO_H */ diff --git a/libs/unimrcp/platforms/umc/include/dtmfsession.h b/libs/unimrcp/platforms/umc/include/dtmfsession.h index 2bf21bc50c..e0a3f7ccd0 100644 --- a/libs/unimrcp/platforms/umc/include/dtmfsession.h +++ b/libs/unimrcp/platforms/umc/include/dtmfsession.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: dtmfsession.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __DTMF_SESSION_H__ -#define __DTMF_SESSION_H__ +#ifndef DTMF_SESSION_H +#define DTMF_SESSION_H /** * @file dtmfsession.h @@ -65,4 +67,4 @@ inline const DtmfScenario* DtmfSession::GetScenario() const return (DtmfScenario*)m_pScenario; } -#endif /*__DTMF_SESSION_H__*/ +#endif /* DTMF_SESSION_H */ diff --git a/libs/unimrcp/platforms/umc/include/recogscenario.h b/libs/unimrcp/platforms/umc/include/recogscenario.h index 1be4d739a9..fc20c10757 100644 --- a/libs/unimrcp/platforms/umc/include/recogscenario.h +++ b/libs/unimrcp/platforms/umc/include/recogscenario.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: recogscenario.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __RECOG_SCENARIO_H__ -#define __RECOG_SCENARIO_H__ +#ifndef RECOG_SCENARIO_H +#define RECOG_SCENARIO_H /** * @file recogscenario.h @@ -85,4 +87,4 @@ inline bool RecogScenario::IsRecognizeEnabled() const return m_Recognize; } -#endif /*__RECOG_SCENARIO_H__*/ +#endif /* RECOG_SCENARIO_H */ diff --git a/libs/unimrcp/platforms/umc/include/recogsession.h b/libs/unimrcp/platforms/umc/include/recogsession.h index bca9f553e9..5cc44404e0 100644 --- a/libs/unimrcp/platforms/umc/include/recogsession.h +++ b/libs/unimrcp/platforms/umc/include/recogsession.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: recogsession.h 1587 2010-03-12 19:40:02Z achaloyan $ */ -#ifndef __RECOG_SESSION_H__ -#define __RECOG_SESSION_H__ +#ifndef RECOG_SESSION_H +#define RECOG_SESSION_H /** * @file recogsession.h @@ -37,6 +39,7 @@ public: protected: /* ============================ MANIPULATORS =============================== */ virtual bool Start(); + virtual bool Stop(); RecogChannel* CreateRecogChannel(); bool StartRecognition(mrcp_channel_t* pMrcpChannel); @@ -69,4 +72,4 @@ inline const RecogScenario* RecogSession::GetScenario() const return (RecogScenario*)m_pScenario; } -#endif /*__RECOG_SESSION_H__*/ +#endif /* RECOG_SESSION_H */ diff --git a/libs/unimrcp/platforms/umc/include/recorderscenario.h b/libs/unimrcp/platforms/umc/include/recorderscenario.h index 9648fd3f2b..cc27b0a1e7 100644 --- a/libs/unimrcp/platforms/umc/include/recorderscenario.h +++ b/libs/unimrcp/platforms/umc/include/recorderscenario.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: recorderscenario.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __RECORDER_SCENARIO_H__ -#define __RECORDER_SCENARIO_H__ +#ifndef RECORDER_SCENARIO_H +#define RECORDER_SCENARIO_H /** * @file recorderscenario.h @@ -63,4 +65,4 @@ inline bool RecorderScenario::IsRecordEnabled() const return m_Record; } -#endif /*__RECORDER_SCENARIO_H__*/ +#endif /* RECORDER_SCENARIO_H */ diff --git a/libs/unimrcp/platforms/umc/include/recordersession.h b/libs/unimrcp/platforms/umc/include/recordersession.h index d2497cd3e1..4f4200ef1c 100644 --- a/libs/unimrcp/platforms/umc/include/recordersession.h +++ b/libs/unimrcp/platforms/umc/include/recordersession.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: recordersession.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __RECORDER_SESSION_H__ -#define __RECORDER_SESSION_H__ +#ifndef RECORDER_SESSION_H +#define RECORDER_SESSION_H /** * @file recordersession.h @@ -65,4 +67,4 @@ inline const RecorderScenario* RecorderSession::GetScenario() const return (RecorderScenario*)m_pScenario; } -#endif /*__RECORDER_SESSION_H__*/ +#endif /* RECORDER_SESSION_H */ diff --git a/libs/unimrcp/platforms/umc/include/setparamscenario.h b/libs/unimrcp/platforms/umc/include/setparamscenario.h index 3cbdf6a43f..75df62c6b2 100644 --- a/libs/unimrcp/platforms/umc/include/setparamscenario.h +++ b/libs/unimrcp/platforms/umc/include/setparamscenario.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: setparamscenario.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __SETPARAM_SCENARIO_H__ -#define __SETPARAM_SCENARIO_H__ +#ifndef SETPARAM_SCENARIO_H +#define SETPARAM_SCENARIO_H /** * @file setaparamscenario.h @@ -44,4 +46,4 @@ protected: /* ============================ INLINE METHODS ============================= */ -#endif /*__SETPARAM_SCENARIO_H__*/ +#endif /* SETPARAM_SCENARIO_H */ diff --git a/libs/unimrcp/platforms/umc/include/setparamsession.h b/libs/unimrcp/platforms/umc/include/setparamsession.h index e7fb24bb33..916a86ee40 100644 --- a/libs/unimrcp/platforms/umc/include/setparamsession.h +++ b/libs/unimrcp/platforms/umc/include/setparamsession.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: setparamsession.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __SETPARAM_SESSION_H__ -#define __SETPARAM_SESSION_H__ +#ifndef SETPARAM_SESSION_H +#define SETPARAM_SESSION_H /** * @file setparamsession.h @@ -73,4 +75,4 @@ inline const SetParamScenario* SetParamSession::GetScenario() const return (SetParamScenario*)m_pScenario; } -#endif /*__SETPARAM_SESSION_H__*/ +#endif /* SETPARAM_SESSION_H */ diff --git a/libs/unimrcp/platforms/umc/include/synthscenario.h b/libs/unimrcp/platforms/umc/include/synthscenario.h index fd5aa9557e..921a857905 100644 --- a/libs/unimrcp/platforms/umc/include/synthscenario.h +++ b/libs/unimrcp/platforms/umc/include/synthscenario.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: synthscenario.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __SYNTH_SCENARIO_H__ -#define __SYNTH_SCENARIO_H__ +#ifndef SYNTH_SCENARIO_H +#define SYNTH_SCENARIO_H /** * @file synthscenario.h @@ -71,4 +73,4 @@ inline bool SynthScenario::IsSpeakEnabled() const return m_Speak; } -#endif /*__SYNTH_SCENARIO_H__*/ +#endif /* SYNTH_SCENARIO_H */ diff --git a/libs/unimrcp/platforms/umc/include/synthsession.h b/libs/unimrcp/platforms/umc/include/synthsession.h index 59f88711c6..94a592c86d 100644 --- a/libs/unimrcp/platforms/umc/include/synthsession.h +++ b/libs/unimrcp/platforms/umc/include/synthsession.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: synthsession.h 1586 2010-03-12 19:39:02Z achaloyan $ */ -#ifndef __SYNTH_SESSION_H__ -#define __SYNTH_SESSION_H__ +#ifndef SYNTH_SESSION_H +#define SYNTH_SESSION_H /** * @file synthsession.h @@ -37,6 +39,7 @@ public: protected: /* ============================ MANIPULATORS =============================== */ virtual bool Start(); + virtual bool Stop(); SynthChannel* CreateSynthChannel(); @@ -50,7 +53,7 @@ protected: /* ============================ ACCESSORS ================================== */ const SynthScenario* GetScenario() const; - + private: /* ============================ DATA ======================================= */ SynthChannel* m_pSynthChannel; @@ -63,4 +66,4 @@ inline const SynthScenario* SynthSession::GetScenario() const return (SynthScenario*)m_pScenario; } -#endif /*__SYNTH_SESSION_H__*/ +#endif /* SYNTH_SESSION_H */ diff --git a/libs/unimrcp/platforms/umc/include/umcconsole.h b/libs/unimrcp/platforms/umc/include/umcconsole.h index c8bd7c6d64..23bf6b1882 100644 --- a/libs/unimrcp/platforms/umc/include/umcconsole.h +++ b/libs/unimrcp/platforms/umc/include/umcconsole.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: umcconsole.h 1525 2010-02-16 14:58:56Z achaloyan $ */ -#ifndef __UMC_CONSOLE_H__ -#define __UMC_CONSOLE_H__ +#ifndef UMC_CONSOLE_H +#define UMC_CONSOLE_H /** * @file umcconsole.h @@ -47,12 +49,12 @@ private: struct UmcOptions { const char* m_RootDirPath; - apt_log_priority_e m_LogPriority; - apt_log_output_e m_LogOutput; + const char* m_LogPriority; + const char* m_LogOutput; }; UmcOptions m_Options; UmcFramework* m_pFramework; }; -#endif /*__UMC_CONSOLE_H__*/ +#endif /* UMC_CONSOLE_H */ diff --git a/libs/unimrcp/platforms/umc/include/umcframework.h b/libs/unimrcp/platforms/umc/include/umcframework.h index 34b3dcc933..ef803cb184 100644 --- a/libs/unimrcp/platforms/umc/include/umcframework.h +++ b/libs/unimrcp/platforms/umc/include/umcframework.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: umcframework.h 1585 2010-03-12 19:12:05Z achaloyan $ */ -#ifndef __UMC_FRAMEWORK_H__ -#define __UMC_FRAMEWORK_H__ +#ifndef UMC_FRAMEWORK_H +#define UMC_FRAMEWORK_H /** * @file umcframework.h @@ -42,6 +44,7 @@ public: void Destroy(); void RunSession(const char* pScenarioName, const char* pProfileName); + void StopSession(const char* id); void KillSession(const char* id); void ShowScenarios(); @@ -61,6 +64,7 @@ protected: void DestroyScenarios(); bool ProcessRunRequest(const char* pScenarioName, const char* pProfileName); + void ProcessStopRequest(const char* id); void ProcessKillRequest(const char* id); void ProcessShowScenarios(); void ProcessShowSessions(); @@ -89,4 +93,4 @@ private: apr_hash_t* m_pSessionTable; }; -#endif /*__UMC_FRAMEWORK_H__*/ +#endif /* UMC_FRAMEWORK_H */ diff --git a/libs/unimrcp/platforms/umc/include/umcscenario.h b/libs/unimrcp/platforms/umc/include/umcscenario.h index 712eb666cc..2425fc968e 100644 --- a/libs/unimrcp/platforms/umc/include/umcscenario.h +++ b/libs/unimrcp/platforms/umc/include/umcscenario.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: umcscenario.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __UMC_SCENARIO_H__ -#define __UMC_SCENARIO_H__ +#ifndef UMC_SCENARIO_H +#define UMC_SCENARIO_H /** * @file umcscenario.h @@ -117,4 +119,4 @@ inline bool UmcScenario::IsDiscoveryEnabled() const } -#endif /*__UMC_SCENARIO_H__*/ +#endif /* UMC_SCENARIO_H */ diff --git a/libs/unimrcp/platforms/umc/include/umcsession.h b/libs/unimrcp/platforms/umc/include/umcsession.h index 2c2f729aec..308e1704ff 100644 --- a/libs/unimrcp/platforms/umc/include/umcsession.h +++ b/libs/unimrcp/platforms/umc/include/umcsession.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: umcsession.h 1585 2010-03-12 19:12:05Z achaloyan $ */ -#ifndef __UMC_SESSION_H__ -#define __UMC_SESSION_H__ +#ifndef UMC_SESSION_H +#define UMC_SESSION_H /** * @file umcsession.h @@ -35,6 +37,7 @@ public: /* ============================ MANIPULATORS =============================== */ virtual bool Run(); + virtual bool Stop(); virtual bool Terminate(); void SetMrcpProfile(const char* pMrcpProfile); @@ -82,6 +85,7 @@ protected: /* ============================ ACCESSORS ================================== */ apr_pool_t* GetSessionPool() const; const char* GetMrcpSessionId() const; + mrcp_message_t* GetMrcpMessage() const; /* ============================ DATA ======================================= */ const UmcScenario* m_pScenario; @@ -92,6 +96,7 @@ private: /* ============================ DATA ======================================= */ mrcp_application_t* m_pMrcpApplication; mrcp_session_t* m_pMrcpSession; + mrcp_message_t* m_pMrcpMessage; /* last message sent */ bool m_Running; bool m_Terminating; }; @@ -118,4 +123,9 @@ inline void UmcSession::SetMrcpProfile(const char* pMrcpProfile) m_pMrcpProfile = pMrcpProfile; } -#endif /*__UMC_SESSION_H__*/ +inline mrcp_message_t* UmcSession::GetMrcpMessage() const +{ + return m_pMrcpMessage; +} + +#endif /* UMC_SESSION_H */ diff --git a/libs/unimrcp/platforms/umc/include/verifierscenario.h b/libs/unimrcp/platforms/umc/include/verifierscenario.h new file mode 100644 index 0000000000..52856b077a --- /dev/null +++ b/libs/unimrcp/platforms/umc/include/verifierscenario.h @@ -0,0 +1,75 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: verifierscenario.h 1775 2010-08-26 18:23:38Z achaloyan $ + */ + +#ifndef VERIFIER_SCENARIO_H +#define VERIFIER_SCENARIO_H + +/** + * @file verifierscenario.h + * @brief Verifier Scenario + */ + +#include "umcscenario.h" + +class VerifierScenario : public UmcScenario +{ +public: +/* ============================ CREATORS =================================== */ + VerifierScenario(); + virtual ~VerifierScenario(); + +/* ============================ MANIPULATORS =============================== */ + virtual void Destroy(); + + virtual UmcSession* CreateSession(); + +/* ============================ ACCESSORS ================================== */ + const char* GetRepositoryURI() const; + const char* GetVerificationMode() const; + const char* GetVoiceprintIdentifier() const; + +/* ============================ INQUIRIES ================================== */ +protected: +/* ============================ MANIPULATORS =============================== */ + virtual bool LoadElement(const apr_xml_elem* pElem, apr_pool_t* pool); + + bool LoadVerify(const apr_xml_elem* pElem, apr_pool_t* pool); + +/* ============================ DATA ======================================= */ + const char* m_RepositoryURI; + const char* m_VerificationMode; + const char* m_VoiceprintIdentifier; +}; + +/* ============================ INLINE METHODS ============================= */ +inline const char* VerifierScenario::GetRepositoryURI() const +{ + return m_RepositoryURI; +} + +inline const char* VerifierScenario::GetVerificationMode() const +{ + return m_VerificationMode; +} + +inline const char* VerifierScenario::GetVoiceprintIdentifier() const +{ + return m_VoiceprintIdentifier; +} + +#endif /* VERIFIER_SCENARIO_H */ diff --git a/libs/unimrcp/platforms/umc/include/verifiersession.h b/libs/unimrcp/platforms/umc/include/verifiersession.h new file mode 100644 index 0000000000..856a889f91 --- /dev/null +++ b/libs/unimrcp/platforms/umc/include/verifiersession.h @@ -0,0 +1,74 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: verifiersession.h 1776 2010-08-27 16:36:38Z achaloyan $ + */ + +#ifndef VERIFIER_SESSION_H +#define VERIFIER_SESSION_H + +/** + * @file verifiersession.h + * @brief Verifier Session + */ + +#include "umcsession.h" + +class VerifierScenario; +struct VerifierChannel; + +class VerifierSession : public UmcSession +{ +public: +/* ============================ CREATORS =================================== */ + VerifierSession(const VerifierScenario* pScenario); + virtual ~VerifierSession(); + +protected: +/* ============================ MANIPULATORS =============================== */ + virtual bool Start(); + virtual bool Stop(); + + VerifierChannel* CreateVerifierChannel(); + bool StartVerification(mrcp_channel_t* pMrcpChannel); + + mrcp_message_t* CreateStartSessionRequest(mrcp_channel_t* pMrcpChannel); + mrcp_message_t* CreateEndSessionRequest(mrcp_channel_t* pMrcpChannel); + mrcp_message_t* CreateVerificationRequest(mrcp_channel_t* pMrcpChannel); + + FILE* GetAudioIn(const mpf_codec_descriptor_t* pDescriptor, apr_pool_t* pool) const; + +/* ============================ HANDLERS =================================== */ + virtual bool OnSessionTerminate(mrcp_sig_status_code_e status); + virtual bool OnChannelAdd(mrcp_channel_t* channel, mrcp_sig_status_code_e status); + virtual bool OnMessageReceive(mrcp_channel_t* channel, mrcp_message_t* message); + +/* ============================ ACCESSORS ================================== */ + const VerifierScenario* GetScenario() const; + +private: +/* ============================ DATA ======================================= */ + VerifierChannel* m_pVerifierChannel; + const char* m_ContentId; +}; + + +/* ============================ INLINE METHODS ============================= */ +inline const VerifierScenario* VerifierSession::GetScenario() const +{ + return (VerifierScenario*)m_pScenario; +} + +#endif /* VERIFIER_SESSION_H */ diff --git a/libs/unimrcp/platforms/umc/src/dtmfscenario.cpp b/libs/unimrcp/platforms/umc/src/dtmfscenario.cpp index ca644b382c..d61b528071 100644 --- a/libs/unimrcp/platforms/umc/src/dtmfscenario.cpp +++ b/libs/unimrcp/platforms/umc/src/dtmfscenario.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: dtmfscenario.cpp 1474 2010-02-07 20:51:47Z achaloyan $ */ #include diff --git a/libs/unimrcp/platforms/umc/src/dtmfsession.cpp b/libs/unimrcp/platforms/umc/src/dtmfsession.cpp index 83a2ee5ec2..8ce8f9767f 100644 --- a/libs/unimrcp/platforms/umc/src/dtmfsession.cpp +++ b/libs/unimrcp/platforms/umc/src/dtmfsession.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: dtmfsession.cpp 1780 2010-09-01 05:59:32Z achaloyan $ */ #include "dtmfsession.h" @@ -30,8 +32,6 @@ struct RecogChannel mrcp_channel_t* m_pMrcpChannel; /** DTMF generator */ mpf_dtmf_generator_t* m_pDtmfGenerator; - /** Audio stream */ - mpf_audio_stream_t* m_pStream; /** Streaming is in-progress */ bool m_Streaming; }; @@ -79,13 +79,6 @@ bool DtmfSession::OnSessionTerminate(mrcp_sig_status_code_e status) return UmcSession::OnSessionTerminate(status); } -static apt_bool_t OpenStream(mpf_audio_stream_t* pStream, mpf_codec_t *codec) -{ - RecogChannel* pRecogChannel = (RecogChannel*) pStream->obj; - pRecogChannel->m_pStream = pStream; - return TRUE; -} - static apt_bool_t ReadStream(mpf_audio_stream_t* pStream, mpf_frame_t* pFrame) { RecogChannel* pRecogChannel = (RecogChannel*) pStream->obj; @@ -110,7 +103,6 @@ RecogChannel* DtmfSession::CreateRecogChannel() RecogChannel *pRecogChannel = new RecogChannel; pRecogChannel->m_pMrcpChannel = NULL; pRecogChannel->m_pDtmfGenerator = NULL; - pRecogChannel->m_pStream = NULL; pRecogChannel->m_Streaming = false; /* create source stream capabilities */ @@ -120,7 +112,7 @@ RecogChannel* DtmfSession::CreateRecogChannel() static const mpf_audio_stream_vtable_t audio_stream_vtable = { NULL, - OpenStream, + NULL, NULL, ReadStream, NULL, @@ -162,7 +154,11 @@ bool DtmfSession::OnChannelAdd(mrcp_channel_t* pMrcpChannel, mrcp_sig_status_cod RecogChannel* pRecogChannel = (RecogChannel*) mrcp_application_channel_object_get(pMrcpChannel); if(pRecogChannel) { - pRecogChannel->m_pDtmfGenerator = mpf_dtmf_generator_create(pRecogChannel->m_pStream,GetSessionPool()); + const mpf_audio_stream_t* pStream = mrcp_application_audio_stream_get(pMrcpChannel); + if(pStream) + { + pRecogChannel->m_pDtmfGenerator = mpf_dtmf_generator_create(pStream,GetSessionPool()); + } } return StartRecognition(pMrcpChannel); diff --git a/libs/unimrcp/platforms/umc/src/main.cpp b/libs/unimrcp/platforms/umc/src/main.cpp index 089dee3cd5..08983a20ae 100644 --- a/libs/unimrcp/platforms/umc/src/main.cpp +++ b/libs/unimrcp/platforms/umc/src/main.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: main.cpp 1474 2010-02-07 20:51:47Z achaloyan $ */ #include "umcconsole.h" diff --git a/libs/unimrcp/platforms/umc/src/recogscenario.cpp b/libs/unimrcp/platforms/umc/src/recogscenario.cpp index c7cfbcbc26..eb13a9a81d 100644 --- a/libs/unimrcp/platforms/umc/src/recogscenario.cpp +++ b/libs/unimrcp/platforms/umc/src/recogscenario.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: recogscenario.cpp 1474 2010-02-07 20:51:47Z achaloyan $ */ #include diff --git a/libs/unimrcp/platforms/umc/src/recogsession.cpp b/libs/unimrcp/platforms/umc/src/recogsession.cpp index 6fd6adbe1d..c9a418d923 100644 --- a/libs/unimrcp/platforms/umc/src/recogsession.cpp +++ b/libs/unimrcp/platforms/umc/src/recogsession.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: recogsession.cpp 1587 2010-03-12 19:40:02Z achaloyan $ */ #include "recogsession.h" @@ -27,12 +29,21 @@ struct RecogChannel { /** MRCP control channel */ mrcp_channel_t* m_pMrcpChannel; + /** IN-PROGRESS RECOGNIZE request */ + mrcp_message_t* m_pRecogRequest; /** Streaming is in-progress */ bool m_Streaming; /** File to read audio stream from */ FILE* m_pAudioIn; /** Estimated time to complete (used if no audio_in available) */ apr_size_t m_TimeToComplete; + + RecogChannel() : + m_pMrcpChannel(NULL), + m_pRecogRequest(NULL), + m_Streaming(false), + m_pAudioIn(NULL), + m_TimeToComplete(0) {} }; RecogSession::RecogSession(const RecogScenario* pScenario) : @@ -67,6 +78,37 @@ bool RecogSession::Start() return true; } +bool RecogSession::Stop() +{ + if(!UmcSession::Stop()) + return false; + + if(!m_pRecogChannel) + return false; + + mrcp_message_t* pStopMessage = CreateMrcpMessage(m_pRecogChannel->m_pMrcpChannel,RECOGNIZER_STOP); + if(!pStopMessage) + return false; + + if(m_pRecogChannel->m_pRecogRequest) + { + mrcp_generic_header_t* pGenericHeader; + /* get/allocate generic header */ + pGenericHeader = (mrcp_generic_header_t*) mrcp_generic_header_prepare(pStopMessage); + if(pGenericHeader) + { + pGenericHeader->active_request_id_list.count = 1; + pGenericHeader->active_request_id_list.ids[0] = + m_pRecogChannel->m_pRecogRequest->start_line.request_id; + mrcp_generic_header_property_add(pStopMessage,GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST); + } + + m_pRecogChannel->m_pRecogRequest = NULL; + } + + return SendMrcpRequest(m_pRecogChannel->m_pMrcpChannel,pStopMessage); +} + bool RecogSession::OnSessionTerminate(mrcp_sig_status_code_e status) { if(m_pRecogChannel) @@ -128,11 +170,7 @@ RecogChannel* RecogSession::CreateRecogChannel() apr_pool_t* pool = GetSessionPool(); /* create channel */ - RecogChannel *pRecogChannel = new RecogChannel; - pRecogChannel->m_pMrcpChannel = NULL; - pRecogChannel->m_Streaming = false; - pRecogChannel->m_pAudioIn = NULL; - pRecogChannel->m_TimeToComplete = 0; + RecogChannel* pRecogChannel = new RecogChannel; /* create source stream capabilities */ pCapabilities = mpf_source_stream_capabilities_create(pool); @@ -218,11 +256,13 @@ bool RecogSession::OnMessageReceive(mrcp_channel_t* pMrcpChannel, mrcp_message_t /* received the response to RECOGNIZE request */ if(pMrcpMessage->start_line.request_state == MRCP_REQUEST_STATE_INPROGRESS) { + RecogChannel* pRecogChannel = (RecogChannel*) mrcp_application_channel_object_get(pMrcpChannel); + if(pRecogChannel) + pRecogChannel->m_pRecogRequest = GetMrcpMessage(); + /* start to stream the speech to recognize */ if(pRecogChannel) - { pRecogChannel->m_Streaming = true; - } } else { @@ -241,9 +281,12 @@ bool RecogSession::OnMessageReceive(mrcp_channel_t* pMrcpChannel, mrcp_message_t { ParseNLSMLResult(pMrcpMessage); if(pRecogChannel) - { pRecogChannel->m_Streaming = false; - } + + RecogChannel* pRecogChannel = (RecogChannel*) mrcp_application_channel_object_get(pMrcpChannel); + if(pRecogChannel) + pRecogChannel->m_pRecogRequest = NULL; + Terminate(); } else if(pMrcpMessage->start_line.method_id == RECOGNIZER_START_OF_INPUT) diff --git a/libs/unimrcp/platforms/umc/src/recorderscenario.cpp b/libs/unimrcp/platforms/umc/src/recorderscenario.cpp index 398fc57c56..dd0ee2b1a9 100644 --- a/libs/unimrcp/platforms/umc/src/recorderscenario.cpp +++ b/libs/unimrcp/platforms/umc/src/recorderscenario.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: recorderscenario.cpp 1474 2010-02-07 20:51:47Z achaloyan $ */ #include diff --git a/libs/unimrcp/platforms/umc/src/recordersession.cpp b/libs/unimrcp/platforms/umc/src/recordersession.cpp index 28a7138e80..e10369eeb5 100644 --- a/libs/unimrcp/platforms/umc/src/recordersession.cpp +++ b/libs/unimrcp/platforms/umc/src/recordersession.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: recordersession.cpp 1474 2010-02-07 20:51:47Z achaloyan $ */ #include "recordersession.h" diff --git a/libs/unimrcp/platforms/umc/src/setparamscenario.cpp b/libs/unimrcp/platforms/umc/src/setparamscenario.cpp index 60e889297d..c2b62b1934 100644 --- a/libs/unimrcp/platforms/umc/src/setparamscenario.cpp +++ b/libs/unimrcp/platforms/umc/src/setparamscenario.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: setparamscenario.cpp 1474 2010-02-07 20:51:47Z achaloyan $ */ #include "setparamscenario.h" diff --git a/libs/unimrcp/platforms/umc/src/setparamsession.cpp b/libs/unimrcp/platforms/umc/src/setparamsession.cpp index 403629bfb4..cc60a020a7 100644 --- a/libs/unimrcp/platforms/umc/src/setparamsession.cpp +++ b/libs/unimrcp/platforms/umc/src/setparamsession.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: setparamsession.cpp 1474 2010-02-07 20:51:47Z achaloyan $ */ #include "setparamsession.h" diff --git a/libs/unimrcp/platforms/umc/src/synthscenario.cpp b/libs/unimrcp/platforms/umc/src/synthscenario.cpp index 37c9d66f30..b104ef20a6 100644 --- a/libs/unimrcp/platforms/umc/src/synthscenario.cpp +++ b/libs/unimrcp/platforms/umc/src/synthscenario.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: synthscenario.cpp 1474 2010-02-07 20:51:47Z achaloyan $ */ #include diff --git a/libs/unimrcp/platforms/umc/src/synthsession.cpp b/libs/unimrcp/platforms/umc/src/synthsession.cpp index a0cb5082a5..003d2f6b62 100644 --- a/libs/unimrcp/platforms/umc/src/synthsession.cpp +++ b/libs/unimrcp/platforms/umc/src/synthsession.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: synthsession.cpp 1586 2010-03-12 19:39:02Z achaloyan $ */ #include "synthsession.h" @@ -23,9 +25,14 @@ struct SynthChannel { + /** MRCP channel */ mrcp_channel_t* m_pMrcpChannel; + /** IN-PROGRESS SPEAK request */ + mrcp_message_t* m_pSpeakRequest; /** File to write audio stream to */ FILE* m_pAudioOut; + + SynthChannel() : m_pMrcpChannel(NULL), m_pSpeakRequest(NULL), m_pAudioOut(NULL) {} }; SynthSession::SynthSession(const SynthScenario* pScenario) : @@ -58,6 +65,37 @@ bool SynthSession::Start() return true; } +bool SynthSession::Stop() +{ + if(!UmcSession::Stop()) + return false; + + if(!m_pSynthChannel) + return false; + + mrcp_message_t* pStopMessage = CreateMrcpMessage(m_pSynthChannel->m_pMrcpChannel,SYNTHESIZER_STOP); + if(!pStopMessage) + return false; + + if(m_pSynthChannel->m_pSpeakRequest) + { + mrcp_generic_header_t* pGenericHeader; + /* get/allocate generic header */ + pGenericHeader = (mrcp_generic_header_t*) mrcp_generic_header_prepare(pStopMessage); + if(pGenericHeader) + { + pGenericHeader->active_request_id_list.count = 1; + pGenericHeader->active_request_id_list.ids[0] = + m_pSynthChannel->m_pSpeakRequest->start_line.request_id; + mrcp_generic_header_property_add(pStopMessage,GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST); + } + + m_pSynthChannel->m_pSpeakRequest = NULL; + } + + return SendMrcpRequest(m_pSynthChannel->m_pMrcpChannel,pStopMessage); +} + bool SynthSession::OnSessionTerminate(mrcp_sig_status_code_e status) { if(m_pSynthChannel) @@ -93,8 +131,7 @@ SynthChannel* SynthSession::CreateSynthChannel() apr_pool_t* pool = GetSessionPool(); /* create channel */ - SynthChannel *pSynthChannel = new SynthChannel; - pSynthChannel->m_pMrcpChannel = NULL; + SynthChannel* pSynthChannel = new SynthChannel; /* create sink stream capabilities */ pCapabilities = mpf_sink_stream_capabilities_create(pool); @@ -128,7 +165,6 @@ SynthChannel* SynthSession::CreateSynthChannel() } pSynthChannel->m_pMrcpChannel = pChannel; - pSynthChannel->m_pAudioOut = NULL; return pSynthChannel; } @@ -169,6 +205,10 @@ bool SynthSession::OnMessageReceive(mrcp_channel_t* pMrcpChannel, mrcp_message_t /* received the response to SPEAK request */ if(pMrcpMessage->start_line.request_state == MRCP_REQUEST_STATE_INPROGRESS) { + SynthChannel* pSynthChannel = (SynthChannel*) mrcp_application_channel_object_get(pMrcpChannel); + if(pSynthChannel) + pSynthChannel->m_pSpeakRequest = GetMrcpMessage(); + /* waiting for SPEAK-COMPLETE event */ } else @@ -187,6 +227,9 @@ bool SynthSession::OnMessageReceive(mrcp_channel_t* pMrcpChannel, mrcp_message_t /* received MRCP event */ if(pMrcpMessage->start_line.method_id == SYNTHESIZER_SPEAK_COMPLETE) { + SynthChannel* pSynthChannel = (SynthChannel*) mrcp_application_channel_object_get(pMrcpChannel); + if(pSynthChannel) + pSynthChannel->m_pSpeakRequest = NULL; /* received SPEAK-COMPLETE event, terminate the session */ Terminate(); } diff --git a/libs/unimrcp/platforms/umc/src/umcconsole.cpp b/libs/unimrcp/platforms/umc/src/umcconsole.cpp index 203bc442ef..feff85c6b2 100644 --- a/libs/unimrcp/platforms/umc/src/umcconsole.cpp +++ b/libs/unimrcp/platforms/umc/src/umcconsole.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: umcconsole.cpp 1785 2010-09-22 06:14:29Z achaloyan $ */ #include @@ -37,6 +39,7 @@ bool UmcConsole::Run(int argc, const char * const *argv) { apr_pool_t* pool = NULL; apt_dir_layout_t* pDirLayout = NULL; + const char *logConfPath; /* APR global initialization */ if(apr_initialize() != APR_SUCCESS) @@ -63,13 +66,27 @@ bool UmcConsole::Run(int argc, const char * const *argv) /* create the structure of default directories layout */ pDirLayout = apt_default_dir_layout_create(m_Options.m_RootDirPath,pool); - /* create singleton logger */ - apt_log_instance_create(m_Options.m_LogOutput,m_Options.m_LogPriority,pool); - if((m_Options.m_LogOutput & APT_LOG_OUTPUT_FILE) == APT_LOG_OUTPUT_FILE) + /* get path to logger configuration file */ + logConfPath = apt_confdir_filepath_get(pDirLayout,"logger.xml",pool); + /* create and load singleton logger */ + apt_log_instance_load(logConfPath,pool); + + if(m_Options.m_LogPriority) + { + /* override the log priority, if specified in command line */ + apt_log_priority_set((apt_log_priority_e)atoi(m_Options.m_LogPriority)); + } + if(m_Options.m_LogOutput) + { + /* override the log output mode, if specified in command line */ + apt_log_output_mode_set((apt_log_output_e)atoi(m_Options.m_LogOutput)); + } + + if(apt_log_output_mode_check(APT_LOG_OUTPUT_FILE) == TRUE) { /* open the log file */ - apt_log_file_open(pDirLayout->log_dir_path,"unimrcpclient",MAX_LOG_FILE_SIZE,MAX_LOG_FILE_COUNT,pool); + apt_log_file_open(pDirLayout->log_dir_path,"unimrcpclient",MAX_LOG_FILE_SIZE,MAX_LOG_FILE_COUNT,FALSE,pool); } /* create demo framework */ @@ -105,7 +122,7 @@ bool UmcConsole::ProcessCmdLine(char* pCmdLine) const char* pProfileName = apr_strtok(NULL, " ", &last); if(!pProfileName) { - pProfileName = "MRCPv2-Default"; + pProfileName = "uni2"; } m_pFramework->RunSession(pScenarioName,pProfileName); } @@ -118,6 +135,14 @@ bool UmcConsole::ProcessCmdLine(char* pCmdLine) m_pFramework->KillSession(pID); } } + else if(strcasecmp(name,"stop") == 0) + { + char* pID = apr_strtok(NULL, " ", &last); + if(pID) + { + m_pFramework->StopSession(pID); + } + } else if(strcasecmp(name,"show") == 0) { char* pWhat = apr_strtok(NULL, " ", &last); @@ -146,12 +171,12 @@ bool UmcConsole::ProcessCmdLine(char* pCmdLine) printf("usage:\n" "\n- run [scenario] [profile] (run new session)\n" " scenario is one of 'synth', 'recog', ... (use 'show scenarios')\n" - " profile is one of 'MRCPv2-Default', 'MRCPv1-Default', ... (see unimrcpclient.xml)\n" + " profile is one of 'uni2', 'uni1', ... (see unimrcpclient.xml)\n" "\n examples: \n" " run synth\n" " run recog\n" - " run synth MRCPv1-Default\n" - " run recog MRCPv1-Default\n" + " run synth uni1\n" + " run recog uni1\n" "\n- kill [id] (kill session)\n" " id is a session identifier: 1, 2, ... (use 'show sessions')\n" "\n example: \n" @@ -238,8 +263,8 @@ bool UmcConsole::LoadOptions(int argc, const char * const *argv, apr_pool_t *poo /* set the default options */ m_Options.m_RootDirPath = "../"; - m_Options.m_LogPriority = APT_PRIO_INFO; - m_Options.m_LogOutput = APT_LOG_OUTPUT_CONSOLE; + m_Options.m_LogPriority = NULL; + m_Options.m_LogOutput = NULL; rv = apr_getopt_init(&opt, pool , argc, argv); if(rv != APR_SUCCESS) @@ -254,15 +279,11 @@ bool UmcConsole::LoadOptions(int argc, const char * const *argv, apr_pool_t *poo break; case 'l': if(optarg) - { - m_Options.m_LogPriority = (apt_log_priority_e) atoi(optarg); - } + m_Options.m_LogPriority = optarg; break; case 'o': if(optarg) - { - m_Options.m_LogOutput = (apt_log_output_e) atoi(optarg); - } + m_Options.m_LogOutput = optarg; break; case 'h': Usage(); diff --git a/libs/unimrcp/platforms/umc/src/umcframework.cpp b/libs/unimrcp/platforms/umc/src/umcframework.cpp index a4620bbf8b..9c06064919 100644 --- a/libs/unimrcp/platforms/umc/src/umcframework.cpp +++ b/libs/unimrcp/platforms/umc/src/umcframework.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: umcframework.cpp 1767 2010-08-23 19:10:22Z achaloyan $ */ #include "umcframework.h" @@ -21,6 +23,7 @@ #include "recorderscenario.h" #include "dtmfscenario.h" #include "setparamscenario.h" +#include "verifierscenario.h" #include "unimrcp_client.h" #include "apt_log.h" @@ -36,6 +39,7 @@ enum UmcTaskMsgType { UMC_TASK_CLIENT_MSG, UMC_TASK_RUN_SESSION_MSG, + UMC_TASK_STOP_SESSION_MSG, UMC_TASK_KILL_SESSION_MSG, UMC_TASK_SHOW_SCENARIOS_MSG, UMC_TASK_SHOW_SESSIONS_MSG @@ -134,7 +138,7 @@ bool UmcFramework::CreateTask() return false; pTask = apt_consumer_task_base_get(m_pTask); - apt_task_name_set(pTask,"Framework Task"); + apt_task_name_set(pTask,"Framework Agent"); pVtable = apt_consumer_task_vtable_get(m_pTask); if(pVtable) { @@ -175,6 +179,8 @@ UmcScenario* UmcFramework::CreateScenario(const char* pType) return new DtmfScenario(); else if(strcasecmp(pType,"Params") == 0) return new SetParamScenario(); + else if(strcasecmp(pType,"Verifier") == 0) + return new VerifierScenario(); } return NULL; } @@ -335,6 +341,24 @@ bool UmcFramework::ProcessRunRequest(const char* pScenarioName, const char* pPro return true; } +void UmcFramework::ProcessStopRequest(const char* id) +{ + UmcSession* pSession; + void* pVal; + apr_hash_index_t* it = apr_hash_first(m_pPool,m_pSessionTable); + for(; it; it = apr_hash_next(it)) + { + apr_hash_this(it,NULL,NULL,&pVal); + pSession = (UmcSession*) pVal; + if(pSession && strcasecmp(pSession->GetId(),id) == 0) + { + /* stop in-progress request */ + pSession->Stop(); + return; + } + } +} + void UmcFramework::ProcessKillRequest(const char* id) { UmcSession* pSession; @@ -346,7 +370,7 @@ void UmcFramework::ProcessKillRequest(const char* id) pSession = (UmcSession*) pVal; if(pSession && strcasecmp(pSession->GetId(),id) == 0) { - /* first, terminate session */ + /* terminate session */ pSession->Terminate(); return; } @@ -403,6 +427,22 @@ void UmcFramework::RunSession(const char* pScenarioName, const char* pProfileNam apt_task_msg_signal(pTask,pTaskMsg); } +void UmcFramework::StopSession(const char* id) +{ + apt_task_t* pTask = apt_consumer_task_base_get(m_pTask); + apt_task_msg_t* pTaskMsg = apt_task_msg_get(pTask); + if(!pTaskMsg) + return; + + pTaskMsg->type = TASK_MSG_USER; + pTaskMsg->sub_type = UMC_TASK_STOP_SESSION_MSG; + + UmcTaskMsg* pUmcMsg = (UmcTaskMsg*) pTaskMsg->data; + strncpy(pUmcMsg->m_SessionId,id,sizeof(pUmcMsg->m_SessionId)-1); + pUmcMsg->m_pAppMessage = NULL; + apt_task_msg_signal(pTask,pTaskMsg); +} + void UmcFramework::KillSession(const char* id) { apt_task_t* pTask = apt_consumer_task_base_get(m_pTask); @@ -562,6 +602,11 @@ apt_bool_t UmcProcessMsg(apt_task_t *pTask, apt_task_msg_t *pMsg) pFramework->ProcessRunRequest(pUmcMsg->m_ScenarioName,pUmcMsg->m_ProfileName); break; } + case UMC_TASK_STOP_SESSION_MSG: + { + pFramework->ProcessStopRequest(pUmcMsg->m_SessionId); + break; + } case UMC_TASK_KILL_SESSION_MSG: { pFramework->ProcessKillRequest(pUmcMsg->m_SessionId); diff --git a/libs/unimrcp/platforms/umc/src/umcscenario.cpp b/libs/unimrcp/platforms/umc/src/umcscenario.cpp index e93c53a1b6..f48bea74c9 100644 --- a/libs/unimrcp/platforms/umc/src/umcscenario.cpp +++ b/libs/unimrcp/platforms/umc/src/umcscenario.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,14 +12,17 @@ * 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. + * + * $Id: umcscenario.cpp 1571 2010-03-07 20:33:39Z achaloyan $ */ #include #include "umcscenario.h" +#include "apt_log.h" UmcScenario::UmcScenario() : m_pName(NULL), - m_pMrcpProfile("MRCPv2-Default"), + m_pMrcpProfile("uni2"), m_pDirLayout(NULL), m_ResourceDiscovery(false), m_pCapabilities(NULL), @@ -200,14 +203,31 @@ const char* UmcScenario::LoadFileContent(const char* pFileName, apr_pool_t* pool if(!pFilePath) return NULL; - FILE* pFile = fopen(pFilePath,"r"); - if(!pFile) + apr_file_t *pFile; + if(apr_file_open(&pFile,pFilePath,APR_FOPEN_READ|APR_FOPEN_BINARY,0,pool) != APR_SUCCESS) + { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Open File %s",pFilePath); return NULL; + } - char text[1024]; - apr_size_t size; - size = fread(text,1,sizeof(text)-1,pFile); - text[size] = '\0'; - fclose(pFile); - return apr_pstrdup(pool,text); + apr_finfo_t finfo; + if(apr_file_info_get(&finfo,APR_FINFO_SIZE,pFile) != APR_SUCCESS) + { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Get File Info %s",pFilePath); + apr_file_close(pFile); + return NULL; + } + + apr_size_t size = (apr_size_t)finfo.size; + char* pContent = (char*) apr_palloc(pool,size+1); + apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Load File Content size [%"APR_SIZE_T_FMT" bytes] %s",size,pFilePath); + if(apr_file_read(pFile,pContent,&size) != APR_SUCCESS) + { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Read Content %s",pFilePath); + apr_file_close(pFile); + return NULL; + } + pContent[size] = '\0'; + apr_file_close(pFile); + return pContent; } diff --git a/libs/unimrcp/platforms/umc/src/umcsession.cpp b/libs/unimrcp/platforms/umc/src/umcsession.cpp index d19be46466..d619893cac 100644 --- a/libs/unimrcp/platforms/umc/src/umcsession.cpp +++ b/libs/unimrcp/platforms/umc/src/umcsession.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,16 +12,20 @@ * 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. + * + * $Id: umcsession.cpp 1695 2010-05-19 18:56:15Z achaloyan $ */ #include "umcsession.h" #include "umcscenario.h" +#include "mrcp_message.h" UmcSession::UmcSession(const UmcScenario* pScenario) : m_pScenario(pScenario), m_pMrcpProfile(NULL), m_pMrcpApplication(NULL), m_pMrcpSession(NULL), + m_pMrcpMessage(NULL), m_Running(false), m_Terminating(false) { @@ -69,6 +73,14 @@ bool UmcSession::Run() return ret; } +bool UmcSession::Stop() +{ + if(m_Terminating) + return false; + + return true; +} + bool UmcSession::Terminate() { if(m_Terminating) @@ -105,7 +117,17 @@ bool UmcSession::OnChannelRemove(mrcp_channel_t *channel, mrcp_sig_status_code_e bool UmcSession::OnMessageReceive(mrcp_channel_t *channel, mrcp_message_t *message) { - return m_Running; + if(!m_Running) + return false; + + if(!m_pMrcpMessage) + return false; + + /* match request identifiers */ + if(m_pMrcpMessage->start_line.request_id != message->start_line.request_id) + return false; + + return true; } bool UmcSession::OnTerminateEvent(mrcp_channel_t *channel) @@ -129,6 +151,9 @@ bool UmcSession::OnResourceDiscover(mrcp_session_descriptor_t* descriptor, mrcp_ bool UmcSession::CreateMrcpSession(const char* pProfileName) { m_pMrcpSession = mrcp_application_session_create(m_pMrcpApplication,pProfileName,this); + char name[32]; + apr_snprintf(name,sizeof(name),"umc-%s",m_Id); + mrcp_application_session_name_set(m_pMrcpSession,name); return (m_pMrcpSession != NULL); } @@ -163,6 +188,7 @@ bool UmcSession::SendMrcpRequest(mrcp_channel_t* pMrcpChannel, mrcp_message_t* p if(!m_Running) return false; + m_pMrcpMessage = pMrcpMessage; return (mrcp_application_message_send(m_pMrcpSession,pMrcpChannel,pMrcpMessage) == TRUE); } diff --git a/libs/unimrcp/platforms/umc/src/verifierscenario.cpp b/libs/unimrcp/platforms/umc/src/verifierscenario.cpp new file mode 100644 index 0000000000..23ee362803 --- /dev/null +++ b/libs/unimrcp/platforms/umc/src/verifierscenario.cpp @@ -0,0 +1,82 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: verifierscenario.cpp 1775 2010-08-26 18:23:38Z achaloyan $ + */ + +#include +#include "verifierscenario.h" +#include "verifiersession.h" +#include "mrcp_message.h" +#include "mrcp_generic_header.h" +#include "mrcp_recog_header.h" +#include "mrcp_recog_resource.h" +#include "apt_log.h" + +VerifierScenario::VerifierScenario() : + m_RepositoryURI(NULL), + m_VerificationMode(NULL), + m_VoiceprintIdentifier(NULL) +{ +} + +VerifierScenario::~VerifierScenario() +{ +} + +void VerifierScenario::Destroy() +{ +} + +bool VerifierScenario::LoadElement(const apr_xml_elem* pElem, apr_pool_t* pool) +{ + if(UmcScenario::LoadElement(pElem,pool)) + return true; + + if(strcasecmp(pElem->name,"verify") == 0) + { + LoadVerify(pElem,pool); + return true; + } + return false; +} + +bool VerifierScenario::LoadVerify(const apr_xml_elem* pElem, apr_pool_t* pool) +{ + const apr_xml_attr* pAttr; + for(pAttr = pElem->attr; pAttr; pAttr = pAttr->next) + { + if(strcasecmp(pAttr->name,"repository-uri") == 0) + { + m_RepositoryURI = pAttr->value; + } + else if(strcasecmp(pAttr->name,"verification-mode") == 0) + { + m_VerificationMode = pAttr->value; + } + else if(strcasecmp(pAttr->name,"voiceprint-identifier") == 0) + { + m_VoiceprintIdentifier = pAttr->value; + } + } + + return true; +} + + +UmcSession* VerifierScenario::CreateSession() +{ + return new VerifierSession(this); +} diff --git a/libs/unimrcp/platforms/umc/src/verifiersession.cpp b/libs/unimrcp/platforms/umc/src/verifiersession.cpp new file mode 100644 index 0000000000..c44530e006 --- /dev/null +++ b/libs/unimrcp/platforms/umc/src/verifiersession.cpp @@ -0,0 +1,389 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: verifiersession.cpp 1778 2010-08-27 17:34:52Z achaloyan $ + */ + +#include "verifiersession.h" +#include "verifierscenario.h" +#include "mrcp_message.h" +#include "mrcp_generic_header.h" +#include "mrcp_verifier_header.h" +#include "mrcp_verifier_resource.h" +#include "apt_nlsml_doc.h" +#include "apt_log.h" + +struct VerifierChannel +{ + /** MRCP control channel */ + mrcp_channel_t* m_pMrcpChannel; + /** IN-PROGRESS VERIFY request */ + mrcp_message_t* m_pVerificationRequest; + /** Streaming is in-progress */ + bool m_Streaming; + /** File to read audio stream from */ + FILE* m_pAudioIn; + /** Estimated time to complete (used if no audio_in available) */ + apr_size_t m_TimeToComplete; + + VerifierChannel() : + m_pMrcpChannel(NULL), + m_pVerificationRequest(NULL), + m_Streaming(false), + m_pAudioIn(NULL), + m_TimeToComplete(0) {} +}; + +VerifierSession::VerifierSession(const VerifierScenario* pScenario) : + UmcSession(pScenario), + m_pVerifierChannel(NULL), + m_ContentId("request1@form-level") +{ +} + +VerifierSession::~VerifierSession() +{ +} + +bool VerifierSession::Start() +{ + /* create channel and associate all the required data */ + m_pVerifierChannel = CreateVerifierChannel(); + if(!m_pVerifierChannel) + return false; + + /* add channel to session (send asynchronous request) */ + if(!AddMrcpChannel(m_pVerifierChannel->m_pMrcpChannel)) + { + delete m_pVerifierChannel; + m_pVerifierChannel = NULL; + return false; + } + return true; +} + +bool VerifierSession::Stop() +{ + if(!UmcSession::Stop()) + return false; + + if(!m_pVerifierChannel) + return false; + + mrcp_message_t* pStopMessage = CreateMrcpMessage(m_pVerifierChannel->m_pMrcpChannel,VERIFIER_STOP); + if(!pStopMessage) + return false; + + return SendMrcpRequest(m_pVerifierChannel->m_pMrcpChannel,pStopMessage); +} + +bool VerifierSession::OnSessionTerminate(mrcp_sig_status_code_e status) +{ + if(m_pVerifierChannel) + { + FILE* pAudioIn = m_pVerifierChannel->m_pAudioIn; + if(pAudioIn) + { + m_pVerifierChannel->m_pAudioIn = NULL; + fclose(pAudioIn); + } + + delete m_pVerifierChannel; + m_pVerifierChannel = NULL; + } + return UmcSession::OnSessionTerminate(status); +} + +static apt_bool_t ReadStream(mpf_audio_stream_t* pStream, mpf_frame_t* pFrame) +{ + VerifierChannel* pVerifierChannel = (VerifierChannel*) pStream->obj; + if(pVerifierChannel && pVerifierChannel->m_Streaming) + { + if(pVerifierChannel->m_pAudioIn) + { + if(fread(pFrame->codec_frame.buffer,1,pFrame->codec_frame.size,pVerifierChannel->m_pAudioIn) == pFrame->codec_frame.size) + { + /* normal read */ + pFrame->type |= MEDIA_FRAME_TYPE_AUDIO; + } + else + { + /* file is over */ + pVerifierChannel->m_Streaming = false; + } + } + else + { + /* fill with silence in case no file available */ + if(pVerifierChannel->m_TimeToComplete >= CODEC_FRAME_TIME_BASE) + { + pFrame->type |= MEDIA_FRAME_TYPE_AUDIO; + memset(pFrame->codec_frame.buffer,0,pFrame->codec_frame.size); + pVerifierChannel->m_TimeToComplete -= CODEC_FRAME_TIME_BASE; + } + else + { + pVerifierChannel->m_Streaming = false; + } + } + } + return TRUE; +} + +VerifierChannel* VerifierSession::CreateVerifierChannel() +{ + mrcp_channel_t* pChannel; + mpf_termination_t* pTermination; + mpf_stream_capabilities_t* pCapabilities; + apr_pool_t* pool = GetSessionPool(); + + /* create channel */ + VerifierChannel* pVerifierChannel = new VerifierChannel; + + /* create source stream capabilities */ + pCapabilities = mpf_source_stream_capabilities_create(pool); + GetScenario()->InitCapabilities(pCapabilities); + + static const mpf_audio_stream_vtable_t audio_stream_vtable = + { + NULL, + NULL, + NULL, + ReadStream, + NULL, + NULL, + NULL + }; + + pTermination = CreateAudioTermination( + &audio_stream_vtable, /* virtual methods table of audio stream */ + pCapabilities, /* capabilities of audio stream */ + pVerifierChannel); /* object to associate */ + + pChannel = CreateMrcpChannel( + MRCP_VERIFIER_RESOURCE, /* MRCP resource identifier */ + pTermination, /* media termination, used to terminate audio stream */ + NULL, /* RTP descriptor, used to create RTP termination (NULL by default) */ + pVerifierChannel); /* object to associate */ + if(!pChannel) + { + delete pVerifierChannel; + return NULL; + } + + pVerifierChannel->m_pMrcpChannel = pChannel; + return pVerifierChannel; +} + +bool VerifierSession::OnChannelAdd(mrcp_channel_t* pMrcpChannel, mrcp_sig_status_code_e status) +{ + if(!UmcSession::OnChannelAdd(pMrcpChannel,status)) + return false; + + if(status != MRCP_SIG_STATUS_CODE_SUCCESS) + { + /* error case, just terminate the demo */ + return Terminate(); + } + + return StartVerification(pMrcpChannel); +} + +bool VerifierSession::OnMessageReceive(mrcp_channel_t* pMrcpChannel, mrcp_message_t* pMrcpMessage) +{ + if(!UmcSession::OnMessageReceive(pMrcpChannel,pMrcpMessage)) + return false; + + VerifierChannel* pVerifierChannel = (VerifierChannel*) mrcp_application_channel_object_get(pMrcpChannel); + if(pMrcpMessage->start_line.message_type == MRCP_MESSAGE_TYPE_RESPONSE) + { + /* received MRCP response */ + if(pMrcpMessage->start_line.method_id == VERIFIER_START_SESSION) + { + /* received the response to START-SESSION request */ + /* create and send VERIFY request */ + mrcp_message_t* pMrcpMessage = CreateVerificationRequest(pMrcpChannel); + if(pMrcpMessage) + { + SendMrcpRequest(pVerifierChannel->m_pMrcpChannel,pMrcpMessage); + } + } + else if(pMrcpMessage->start_line.method_id == VERIFIER_END_SESSION) + { + /* received the response to END-SESSION request */ + Terminate(); + } + else if(pMrcpMessage->start_line.method_id == VERIFIER_VERIFY) + { + /* received the response to VERIFY request */ + if(pMrcpMessage->start_line.request_state == MRCP_REQUEST_STATE_INPROGRESS) + { + VerifierChannel* pVerifierChannel = (VerifierChannel*) mrcp_application_channel_object_get(pMrcpChannel); + if(pVerifierChannel) + pVerifierChannel->m_pVerificationRequest = GetMrcpMessage(); + + /* start to stream the speech to Verify */ + if(pVerifierChannel) + pVerifierChannel->m_Streaming = true; + } + else + { + /* create and send END-SESSION request */ + mrcp_message_t* pMrcpMessage = CreateEndSessionRequest(pMrcpChannel); + if(pMrcpMessage) + { + SendMrcpRequest(pVerifierChannel->m_pMrcpChannel,pMrcpMessage); + } + } + } + else + { + /* received unexpected response */ + } + } + else if(pMrcpMessage->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) + { + if(pMrcpMessage->start_line.method_id == VERIFIER_VERIFICATION_COMPLETE) + { + if(pVerifierChannel) + pVerifierChannel->m_Streaming = false; + + VerifierChannel* pVerifierChannel = (VerifierChannel*) mrcp_application_channel_object_get(pMrcpChannel); + if(pVerifierChannel) + pVerifierChannel->m_pVerificationRequest = NULL; + + /* create and send END-SESSION request */ + mrcp_message_t* pMrcpMessage = CreateEndSessionRequest(pMrcpChannel); + if(pMrcpMessage) + { + SendMrcpRequest(pVerifierChannel->m_pMrcpChannel,pMrcpMessage); + } + } + else if(pMrcpMessage->start_line.method_id == VERIFIER_START_OF_INPUT) + { + /* received start-of-input, do whatever you need here */ + } + } + return true; +} + +bool VerifierSession::StartVerification(mrcp_channel_t* pMrcpChannel) +{ + VerifierChannel* pVerifierChannel = (VerifierChannel*) mrcp_application_channel_object_get(pMrcpChannel); + /* create and send Verification request */ + mrcp_message_t* pMrcpMessage = CreateStartSessionRequest(pMrcpChannel); + if(pMrcpMessage) + { + SendMrcpRequest(pVerifierChannel->m_pMrcpChannel,pMrcpMessage); + } + + const mpf_codec_descriptor_t* pDescriptor = mrcp_application_source_descriptor_get(pMrcpChannel); + pVerifierChannel->m_pAudioIn = GetAudioIn(pDescriptor,GetSessionPool()); + if(!pVerifierChannel->m_pAudioIn) + { + /* no audio input availble, set some estimated time to complete instead */ + pVerifierChannel->m_TimeToComplete = 5000; // 5 sec + } + return true; +} + +mrcp_message_t* VerifierSession::CreateStartSessionRequest(mrcp_channel_t* pMrcpChannel) +{ + mrcp_message_t* pMrcpMessage = CreateMrcpMessage(pMrcpChannel,VERIFIER_START_SESSION); + if(!pMrcpMessage) + return NULL; + + mrcp_verifier_header_t* pVerifierHeader; + + /* get/allocate verifier header */ + pVerifierHeader = (mrcp_verifier_header_t*) mrcp_resource_header_prepare(pMrcpMessage); + if(pVerifierHeader) + { + const VerifierScenario* pScenario = GetScenario(); + const char* pRepositoryURI = pScenario->GetRepositoryURI(); + if(pRepositoryURI) + { + apt_string_set(&pVerifierHeader->repository_uri,pRepositoryURI); + mrcp_resource_header_property_add(pMrcpMessage,VERIFIER_HEADER_REPOSITORY_URI); + } + const char* pVoiceprintIdentifier = pScenario->GetVoiceprintIdentifier(); + if(pVoiceprintIdentifier) + { + apt_string_set(&pVerifierHeader->voiceprint_identifier,pVoiceprintIdentifier); + mrcp_resource_header_property_add(pMrcpMessage,VERIFIER_HEADER_VOICEPRINT_IDENTIFIER); + } + const char* pVerificationMode = pScenario->GetVerificationMode(); + if(pVerificationMode) + { + apt_string_set(&pVerifierHeader->verification_mode,pVerificationMode); + mrcp_resource_header_property_add(pMrcpMessage,VERIFIER_HEADER_VERIFICATION_MODE); + } + } + return pMrcpMessage; +} + +mrcp_message_t* VerifierSession::CreateEndSessionRequest(mrcp_channel_t* pMrcpChannel) +{ + return CreateMrcpMessage(pMrcpChannel,VERIFIER_END_SESSION); +} + +mrcp_message_t* VerifierSession::CreateVerificationRequest(mrcp_channel_t* pMrcpChannel) +{ + mrcp_message_t* pMrcpMessage = CreateMrcpMessage(pMrcpChannel,VERIFIER_VERIFY); + if(!pMrcpMessage) + return NULL; + + mrcp_verifier_header_t* pVerifierHeader; + + /* get/allocate verifier header */ + pVerifierHeader = (mrcp_verifier_header_t*) mrcp_resource_header_prepare(pMrcpMessage); + if(pVerifierHeader) + { + pVerifierHeader->no_input_timeout = 5000; + mrcp_resource_header_property_add(pMrcpMessage,VERIFIER_HEADER_NO_INPUT_TIMEOUT); + pVerifierHeader->start_input_timers = TRUE; + mrcp_resource_header_property_add(pMrcpMessage,VERIFIER_HEADER_START_INPUT_TIMERS); + } + return pMrcpMessage; +} + +FILE* VerifierSession::GetAudioIn(const mpf_codec_descriptor_t* pDescriptor, apr_pool_t* pool) const +{ + const VerifierScenario* pScenario = GetScenario(); + const char* pVoiceprintIdentifier = pScenario->GetVoiceprintIdentifier(); + if(!pVoiceprintIdentifier) + { + apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Voiceprint Specified"); + return NULL; + } + + const char* pFileName = apr_psprintf(pool,"%s-%dkHz.pcm", + pVoiceprintIdentifier, + pDescriptor ? pDescriptor->sampling_rate/1000 : 8); + apt_dir_layout_t* pDirLayout = pScenario->GetDirLayout(); + const char* pFilePath = apt_datadir_filepath_get(pDirLayout,pFileName,pool); + if(!pFilePath) + return NULL; + + FILE* pFile = fopen(pFilePath,"rb"); + if(!pFile) + { + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Cannot Find [%s]",pFilePath); + return NULL; + } + + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set [%s] as Speech Source",pFilePath); + return pFile; +} diff --git a/libs/unimrcp/platforms/umc/umc.rc b/libs/unimrcp/platforms/umc/umc.rc new file mode 100644 index 0000000000..511efb81b6 --- /dev/null +++ b/libs/unimrcp/platforms/umc/umc.rc @@ -0,0 +1,39 @@ +#include "uni_version.h" + +1 VERSIONINFO + FILEVERSION UNI_VERSION_STRING_CSV,0 + PRODUCTVERSION UNI_VERSION_STRING_CSV,0 + FILEFLAGSMASK 0x3fL +#if defined(_DEBUG) + FILEFLAGS 0x01L +#else + FILEFLAGS 0x00L +#endif +#if defined(WINNT) || defined(WIN64) + FILEOS 0x40004L +#else + FILEOS 0x4L +#endif + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", UNI_LICENSE "\0" + VALUE "CompanyName", "UniMRCP\0" + VALUE "FileDescription", "UniMRCP Client Application\0" + VALUE "FileVersion", UNI_VERSION_STRING "\0" + VALUE "InternalName", "umc" "\0" + VALUE "LegalCopyright", UNI_COPYRIGHT "\0" + VALUE "OriginalFilename", "umc.exe" "\0" + VALUE "ProductName", "UniMRCP Project\0" + VALUE "ProductVersion", UNI_VERSION_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/libs/unimrcp/platforms/umc/umc.vcproj b/libs/unimrcp/platforms/umc/umc.vcproj index 5862942a50..d003362f18 100644 --- a/libs/unimrcp/platforms/umc/umc.vcproj +++ b/libs/unimrcp/platforms/umc/umc.vcproj @@ -339,6 +339,14 @@ RelativePath=".\src\umcsession.cpp" > + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/unimrcp/platforms/unimrcp-client/include/demo_application.h b/libs/unimrcp/platforms/unimrcp-client/include/demo_application.h index 608d996f98..305858b642 100644 --- a/libs/unimrcp/platforms/unimrcp-client/include/demo_application.h +++ b/libs/unimrcp/platforms/unimrcp-client/include/demo_application.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: demo_application.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __DEMO_APPLICATION_H__ -#define __DEMO_APPLICATION_H__ +#ifndef DEMO_APPLICATION_H +#define DEMO_APPLICATION_H /** * @file demo_application.h @@ -58,4 +60,4 @@ demo_application_t* demo_discover_application_create(apr_pool_t *pool); APT_END_EXTERN_C -#endif /*__DEMO_APPLICATION_H__*/ +#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 index 5cef92305d..ef173ef7de 100644 --- a/libs/unimrcp/platforms/unimrcp-client/include/demo_framework.h +++ b/libs/unimrcp/platforms/unimrcp-client/include/demo_framework.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: demo_framework.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __DEMO_FRAMEWORK_H__ -#define __DEMO_FRAMEWORK_H__ +#ifndef DEMO_FRAMEWORK_H +#define DEMO_FRAMEWORK_H /** * @file demo_framework.h @@ -50,4 +52,4 @@ apt_bool_t demo_framework_destroy(demo_framework_t *framework); APT_END_EXTERN_C -#endif /*__DEMO_FRAMEWORK_H__*/ +#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 index c3d6e793d9..82b1d5ada5 100644 --- a/libs/unimrcp/platforms/unimrcp-client/include/demo_util.h +++ b/libs/unimrcp/platforms/unimrcp-client/include/demo_util.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: demo_util.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __DEMO_UTIL_H__ -#define __DEMO_UTIL_H__ +#ifndef DEMO_UTIL_H +#define DEMO_UTIL_H /** * @file demo_util.h @@ -42,4 +44,4 @@ mpf_rtp_termination_descriptor_t* demo_rtp_descriptor_create(apr_pool_t *pool); APT_END_EXTERN_C -#endif /*__DEMO_UTIL_H__*/ +#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 index 6a9b660bce..5780a87ae5 100644 --- a/libs/unimrcp/platforms/unimrcp-client/src/demo_bypass_application.c +++ b/libs/unimrcp/platforms/unimrcp-client/src/demo_bypass_application.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: demo_bypass_application.c 1474 2010-02-07 20:51:47Z achaloyan $ */ /* diff --git a/libs/unimrcp/platforms/unimrcp-client/src/demo_discover_application.c b/libs/unimrcp/platforms/unimrcp-client/src/demo_discover_application.c index a31b96873c..652fc72a07 100644 --- a/libs/unimrcp/platforms/unimrcp-client/src/demo_discover_application.c +++ b/libs/unimrcp/platforms/unimrcp-client/src/demo_discover_application.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: demo_discover_application.c 1474 2010-02-07 20:51:47Z achaloyan $ */ /* diff --git a/libs/unimrcp/platforms/unimrcp-client/src/demo_framework.c b/libs/unimrcp/platforms/unimrcp-client/src/demo_framework.c index 9d65750fbd..69ac8b1a60 100644 --- a/libs/unimrcp/platforms/unimrcp-client/src/demo_framework.c +++ b/libs/unimrcp/platforms/unimrcp-client/src/demo_framework.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: demo_framework.c 1571 2010-03-07 20:33:39Z achaloyan $ */ #include @@ -21,7 +23,7 @@ #include "apt_consumer_task.h" #include "apt_log.h" -#define FRAMEWORK_TASK_NAME "Framework Task" +#define FRAMEWORK_TASK_NAME "Framework Agent" #define MAX_APP_NAME_LENGTH 16 #define MAX_PROFILE_NAME_LENGTH 16 diff --git a/libs/unimrcp/platforms/unimrcp-client/src/demo_recog_application.c b/libs/unimrcp/platforms/unimrcp-client/src/demo_recog_application.c index 3235b2ad86..a4b4845741 100644 --- a/libs/unimrcp/platforms/unimrcp-client/src/demo_recog_application.c +++ b/libs/unimrcp/platforms/unimrcp-client/src/demo_recog_application.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: demo_recog_application.c 1474 2010-02-07 20:51:47Z achaloyan $ */ /* diff --git a/libs/unimrcp/platforms/unimrcp-client/src/demo_synth_application.c b/libs/unimrcp/platforms/unimrcp-client/src/demo_synth_application.c index 4ad6a7d0d5..d010bb3883 100644 --- a/libs/unimrcp/platforms/unimrcp-client/src/demo_synth_application.c +++ b/libs/unimrcp/platforms/unimrcp-client/src/demo_synth_application.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: demo_synth_application.c 1474 2010-02-07 20:51:47Z achaloyan $ */ /* diff --git a/libs/unimrcp/platforms/unimrcp-client/src/demo_util.c b/libs/unimrcp/platforms/unimrcp-client/src/demo_util.c index db873f288e..ebbc0a5c67 100644 --- a/libs/unimrcp/platforms/unimrcp-client/src/demo_util.c +++ b/libs/unimrcp/platforms/unimrcp-client/src/demo_util.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: demo_util.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include "demo_util.h" diff --git a/libs/unimrcp/platforms/unimrcp-client/src/main.c b/libs/unimrcp/platforms/unimrcp-client/src/main.c index 6a242ca4cd..5da982b533 100644 --- a/libs/unimrcp/platforms/unimrcp-client/src/main.c +++ b/libs/unimrcp/platforms/unimrcp-client/src/main.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: main.c 1785 2010-09-22 06:14:29Z achaloyan $ */ #include @@ -23,9 +25,9 @@ #include "apt_log.h" typedef struct { - const char *root_dir_path; - apt_log_priority_e log_priority; - apt_log_output_e log_output; + const char *root_dir_path; + const char *log_priority; + const char *log_output; } client_options_t; static apt_bool_t demo_framework_cmdline_process(demo_framework_t *framework, char *cmdline) @@ -40,7 +42,7 @@ static apt_bool_t demo_framework_cmdline_process(demo_framework_t *framework, ch if(app_name) { char *profile_name = apr_strtok(NULL, " ", &last); if(!profile_name) { - profile_name = "MRCPv2-Default"; + profile_name = "uni2"; } demo_framework_app_run(framework,app_name,profile_name); } @@ -58,12 +60,12 @@ static apt_bool_t demo_framework_cmdline_process(demo_framework_t *framework, ch 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" + " profile_name is one of 'uni2', 'uni1', ...\n" "\n examples: \n" " run synth\n" " run recog\n" - " run synth MRCPv1-Default\n" - " run recog MRCPv1-Default\n" + " run synth uni1\n" + " run recog uni1\n" "\n- loglevel [level] (set loglevel, one of 0,1...7)\n" "\n- quit, exit\n"); } @@ -145,14 +147,10 @@ static apt_bool_t demo_framework_options_load(client_options_t *options, int arg options->root_dir_path = optarg; break; case 'l': - if(optarg) { - options->log_priority = atoi(optarg); - } + options->log_priority = optarg; break; case 'o': - if(optarg) { - options->log_output = atoi(optarg); - } + options->log_output = optarg; break; case 'h': usage(); @@ -173,6 +171,7 @@ int main(int argc, const char * const *argv) apr_pool_t *pool = NULL; client_options_t options; apt_dir_layout_t *dir_layout; + const char *log_conf_path; demo_framework_t *framework; /* APR global initialization */ @@ -190,8 +189,8 @@ int main(int argc, const char * const *argv) /* set the default options */ options.root_dir_path = "../"; - options.log_priority = APT_PRIO_INFO; - options.log_output = APT_LOG_OUTPUT_CONSOLE; + options.log_priority = NULL; + options.log_output = NULL; /* load options */ if(demo_framework_options_load(&options,argc,argv,pool) != TRUE) { @@ -202,12 +201,24 @@ int main(int argc, const char * const *argv) /* 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) { + /* get path to logger configuration file */ + log_conf_path = apt_confdir_filepath_get(dir_layout,"logger.xml",pool); + /* create and load singleton logger */ + apt_log_instance_load(log_conf_path,pool); + + if(options.log_priority) { + /* override the log priority, if specified in command line */ + apt_log_priority_set(atoi(options.log_priority)); + } + if(options.log_output) { + /* override the log output mode, if specified in command line */ + apt_log_output_mode_set(atoi(options.log_output)); + } + + if(apt_log_output_mode_check(APT_LOG_OUTPUT_FILE) == TRUE) { /* open the log file */ - apt_log_file_open(dir_layout->log_dir_path,"unimrcpclient",MAX_LOG_FILE_SIZE,MAX_LOG_FILE_COUNT,pool); + apt_log_file_open(dir_layout->log_dir_path,"unimrcpclient",MAX_LOG_FILE_SIZE,MAX_LOG_FILE_COUNT,FALSE,pool); } /* create demo framework */ diff --git a/libs/unimrcp/platforms/unimrcp-client/unimrcpclient.2008.vcproj b/libs/unimrcp/platforms/unimrcp-client/unimrcpclient.2008.vcproj deleted file mode 100644 index 46cd13ccaa..0000000000 --- a/libs/unimrcp/platforms/unimrcp-client/unimrcpclient.2008.vcproj +++ /dev/null @@ -1,200 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/unimrcp/platforms/unimrcp-client/unimrcpclient.rc b/libs/unimrcp/platforms/unimrcp-client/unimrcpclient.rc new file mode 100644 index 0000000000..b7d34091c4 --- /dev/null +++ b/libs/unimrcp/platforms/unimrcp-client/unimrcpclient.rc @@ -0,0 +1,39 @@ +#include "uni_version.h" + +1 VERSIONINFO + FILEVERSION UNI_VERSION_STRING_CSV,0 + PRODUCTVERSION UNI_VERSION_STRING_CSV,0 + FILEFLAGSMASK 0x3fL +#if defined(_DEBUG) + FILEFLAGS 0x01L +#else + FILEFLAGS 0x00L +#endif +#if defined(WINNT) || defined(WIN64) + FILEOS 0x40004L +#else + FILEOS 0x4L +#endif + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", UNI_LICENSE "\0" + VALUE "CompanyName", "UniMRCP\0" + VALUE "FileDescription", "UniMRCP Client Application\0" + VALUE "FileVersion", UNI_VERSION_STRING "\0" + VALUE "InternalName", "unimrcpclient" "\0" + VALUE "LegalCopyright", UNI_COPYRIGHT "\0" + VALUE "OriginalFilename", "unimrcpclient.exe" "\0" + VALUE "ProductName", "UniMRCP Project\0" + VALUE "ProductVersion", UNI_VERSION_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/libs/unimrcp/platforms/unimrcp-client/unimrcpclient.vcproj b/libs/unimrcp/platforms/unimrcp-client/unimrcpclient.vcproj index 36b3bf1072..706498e4a4 100644 --- a/libs/unimrcp/platforms/unimrcp-client/unimrcpclient.vcproj +++ b/libs/unimrcp/platforms/unimrcp-client/unimrcpclient.vcproj @@ -326,6 +326,42 @@ > + + + + + + + + + + + + + + diff --git a/libs/unimrcp/platforms/unimrcp-server/src/main.c b/libs/unimrcp/platforms/unimrcp-server/src/main.c index eb283f957c..3d2c75e78b 100644 --- a/libs/unimrcp/platforms/unimrcp-server/src/main.c +++ b/libs/unimrcp/platforms/unimrcp-server/src/main.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: main.c 1785 2010-09-22 06:14:29Z achaloyan $ */ #include @@ -22,10 +24,10 @@ #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; + const char *root_dir_path; + apt_bool_t foreground; + const char *log_priority; + const char *log_output; } server_options_t; #ifdef WIN32 @@ -98,14 +100,10 @@ static apt_bool_t options_load(server_options_t *options, int argc, const char * options->root_dir_path = optarg; break; case 'l': - if(optarg) { - options->log_priority = atoi(optarg); - } + options->log_priority = optarg; break; case 'o': - if(optarg) { - options->log_output = atoi(optarg); - } + options->log_output = optarg; break; #ifdef WIN32 case 's': @@ -135,6 +133,7 @@ int main(int argc, const char * const *argv) apr_pool_t *pool = NULL; server_options_t options; apt_dir_layout_t *dir_layout; + const char *log_conf_path; /* APR global initialization */ if(apr_initialize() != APR_SUCCESS) { @@ -152,8 +151,8 @@ int main(int argc, const char * const *argv) /* set the default options */ options.root_dir_path = "../"; options.foreground = TRUE; - options.log_priority = APT_PRIO_INFO; - options.log_output = APT_LOG_OUTPUT_CONSOLE; + options.log_priority = NULL; + options.log_output = NULL; /* load options */ if(options_load(&options,argc,argv,pool) != TRUE) { @@ -164,12 +163,24 @@ int main(int argc, const char * const *argv) /* 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); + + /* get path to logger configuration file */ + log_conf_path = apt_confdir_filepath_get(dir_layout,"logger.xml",pool); + /* create and load singleton logger */ + apt_log_instance_load(log_conf_path,pool); + + if(options.log_priority) { + /* override the log priority, if specified in command line */ + apt_log_priority_set(atoi(options.log_priority)); + } + if(options.log_output) { + /* override the log output mode, if specified in command line */ + apt_log_output_mode_set(atoi(options.log_output)); + } - if((options.log_output & APT_LOG_OUTPUT_FILE) == APT_LOG_OUTPUT_FILE) { + if(apt_log_output_mode_check(APT_LOG_OUTPUT_FILE) == TRUE) { /* open the log file */ - apt_log_file_open(dir_layout->log_dir_path,"unimrcpserver",MAX_LOG_FILE_SIZE,MAX_LOG_FILE_COUNT,pool); + apt_log_file_open(dir_layout->log_dir_path,"unimrcpserver",MAX_LOG_FILE_SIZE,MAX_LOG_FILE_COUNT,TRUE,pool); } if(options.foreground == TRUE) { diff --git a/libs/unimrcp/platforms/unimrcp-server/src/uni_cmdline.c b/libs/unimrcp/platforms/unimrcp-server/src/uni_cmdline.c index bac1d6685e..36db7f6412 100644 --- a/libs/unimrcp/platforms/unimrcp-server/src/uni_cmdline.c +++ b/libs/unimrcp/platforms/unimrcp-server/src/uni_cmdline.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: uni_cmdline.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include diff --git a/libs/unimrcp/platforms/unimrcp-server/src/uni_daemon.c b/libs/unimrcp/platforms/unimrcp-server/src/uni_daemon.c index ee7287009b..76c1b00a87 100644 --- a/libs/unimrcp/platforms/unimrcp-server/src/uni_daemon.c +++ b/libs/unimrcp/platforms/unimrcp-server/src/uni_daemon.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: uni_daemon.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include diff --git a/libs/unimrcp/platforms/unimrcp-server/src/uni_service.c b/libs/unimrcp/platforms/unimrcp-server/src/uni_service.c index 9b597d88d9..b179b90e7b 100644 --- a/libs/unimrcp/platforms/unimrcp-server/src/uni_service.c +++ b/libs/unimrcp/platforms/unimrcp-server/src/uni_service.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: uni_service.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include diff --git a/libs/unimrcp/platforms/unimrcp-server/unimrcpserver.2008.vcproj b/libs/unimrcp/platforms/unimrcp-server/unimrcpserver.2008.vcproj deleted file mode 100644 index 147b8dccde..0000000000 --- a/libs/unimrcp/platforms/unimrcp-server/unimrcpserver.2008.vcproj +++ /dev/null @@ -1,174 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/unimrcp/platforms/unimrcp-server/unimrcpserver.rc b/libs/unimrcp/platforms/unimrcp-server/unimrcpserver.rc new file mode 100644 index 0000000000..7c562afc96 --- /dev/null +++ b/libs/unimrcp/platforms/unimrcp-server/unimrcpserver.rc @@ -0,0 +1,39 @@ +#include "uni_version.h" + +1 VERSIONINFO + FILEVERSION UNI_VERSION_STRING_CSV,0 + PRODUCTVERSION UNI_VERSION_STRING_CSV,0 + FILEFLAGSMASK 0x3fL +#if defined(_DEBUG) + FILEFLAGS 0x01L +#else + FILEFLAGS 0x00L +#endif +#if defined(WINNT) || defined(WIN64) + FILEOS 0x40004L +#else + FILEOS 0x4L +#endif + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", UNI_LICENSE "\0" + VALUE "CompanyName", "UniMRCP\0" + VALUE "FileDescription", "UniMRCP Server Application\0" + VALUE "FileVersion", UNI_VERSION_STRING "\0" + VALUE "InternalName", "unimrcpserver" "\0" + VALUE "LegalCopyright", UNI_COPYRIGHT "\0" + VALUE "OriginalFilename", "unimrcpserver.exe" "\0" + VALUE "ProductName", "UniMRCP Project\0" + VALUE "ProductVersion", UNI_VERSION_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/libs/unimrcp/platforms/unimrcp-server/unimrcpserver.vcproj b/libs/unimrcp/platforms/unimrcp-server/unimrcpserver.vcproj index c2b6f6c3f7..46e57dab5a 100644 --- a/libs/unimrcp/platforms/unimrcp-server/unimrcpserver.vcproj +++ b/libs/unimrcp/platforms/unimrcp-server/unimrcpserver.vcproj @@ -298,6 +298,42 @@ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + + + + + + + + + + + + + diff --git a/libs/unimrcp/plugins/Makefile.am b/libs/unimrcp/plugins/Makefile.am index 9bc7eb75c8..9d8b7b5964 100644 --- a/libs/unimrcp/plugins/Makefile.am +++ b/libs/unimrcp/plugins/Makefile.am @@ -10,12 +10,12 @@ if DEMORECOG_PLUGIN SUBDIRS += demo-recog endif -if RECORDER_PLUGIN -SUBDIRS += mrcp-recorder +if DEMOVERIFIER_PLUGIN +SUBDIRS += demo-verifier endif -if CEPSTRAL_PLUGIN -SUBDIRS += mrcp-cepstral +if RECORDER_PLUGIN +SUBDIRS += mrcp-recorder endif if POCKETSPHINX_PLUGIN diff --git a/libs/unimrcp/plugins/demo-recog/demorecog.2008.vcproj b/libs/unimrcp/plugins/demo-recog/demorecog.2008.vcproj deleted file mode 100644 index ff23c031b4..0000000000 --- a/libs/unimrcp/plugins/demo-recog/demorecog.2008.vcproj +++ /dev/null @@ -1,164 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/unimrcp/plugins/demo-recog/src/demo_recog_engine.c b/libs/unimrcp/plugins/demo-recog/src/demo_recog_engine.c index 5c1e66f38b..95681c8c84 100644 --- a/libs/unimrcp/plugins/demo-recog/src/demo_recog_engine.c +++ b/libs/unimrcp/plugins/demo-recog/src/demo_recog_engine.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: demo_recog_engine.c 1706 2010-05-23 14:11:11Z achaloyan $ */ /* @@ -175,7 +177,7 @@ static apt_bool_t demo_recog_engine_open(mrcp_engine_t *engine) apt_task_t *task = apt_consumer_task_base_get(demo_engine->task); apt_task_start(task); } - return TRUE; + return mrcp_engine_open_respond(engine,TRUE); } /** Close recognizer engine */ @@ -186,7 +188,7 @@ static apt_bool_t demo_recog_engine_close(mrcp_engine_t *engine) apt_task_t *task = apt_consumer_task_base_get(demo_engine->task); apt_task_terminate(task,TRUE); } - return TRUE; + return mrcp_engine_close_respond(engine); } static mrcp_engine_channel_t* demo_recog_engine_channel_create(mrcp_engine_t *engine, apr_pool_t *pool) @@ -459,15 +461,18 @@ static apt_bool_t demo_recog_stream_write(mpf_audio_stream_t *stream, const mpf_ 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"); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected Voice Activity "APT_SIDRES_FMT, + MRCP_MESSAGE_SIDRES(recog_channel->recog_request)); demo_recog_start_of_input(recog_channel); break; case MPF_DETECTOR_EVENT_INACTIVITY: - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected Voice Inactivity"); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected Voice Inactivity "APT_SIDRES_FMT, + MRCP_MESSAGE_SIDRES(recog_channel->recog_request)); 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"); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected Noinput "APT_SIDRES_FMT, + MRCP_MESSAGE_SIDRES(recog_channel->recog_request)); if(recog_channel->timers_started == TRUE) { demo_recog_recognition_complete(recog_channel,RECOGNIZER_COMPLETION_CAUSE_NO_INPUT_TIMEOUT); } @@ -478,11 +483,13 @@ static apt_bool_t demo_recog_stream_write(mpf_audio_stream_t *stream, const mpf_ if((frame->type & MEDIA_FRAME_TYPE_EVENT) == MEDIA_FRAME_TYPE_EVENT) { if(frame->marker == MPF_MARKER_START_OF_EVENT) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected Start of Event: id [%d]", + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected Start of Event "APT_SIDRES_FMT" id:%d", + MRCP_MESSAGE_SIDRES(recog_channel->recog_request), frame->event_frame.event_id); } else if(frame->marker == MPF_MARKER_END_OF_EVENT) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected End of Event: id [%d] duration [%d ts]", + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected End of Event "APT_SIDRES_FMT" id:%d duration:%d ts", + MRCP_MESSAGE_SIDRES(recog_channel->recog_request), frame->event_frame.event_id, frame->event_frame.duration); } diff --git a/libs/unimrcp/plugins/demo-synth/demosynth.2008.vcproj b/libs/unimrcp/plugins/demo-synth/demosynth.2008.vcproj deleted file mode 100644 index 3c5897e6ee..0000000000 --- a/libs/unimrcp/plugins/demo-synth/demosynth.2008.vcproj +++ /dev/null @@ -1,164 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/unimrcp/plugins/demo-synth/src/demo_synth_engine.c b/libs/unimrcp/plugins/demo-synth/src/demo_synth_engine.c index 5374fdc75a..9daa99f5e3 100644 --- a/libs/unimrcp/plugins/demo-synth/src/demo_synth_engine.c +++ b/libs/unimrcp/plugins/demo-synth/src/demo_synth_engine.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: demo_synth_engine.c 1706 2010-05-23 14:11:11Z achaloyan $ */ /* @@ -177,7 +179,7 @@ static apt_bool_t demo_synth_engine_open(mrcp_engine_t *engine) apt_task_t *task = apt_consumer_task_base_get(demo_engine->task); apt_task_start(task); } - return TRUE; + return mrcp_engine_open_respond(engine,TRUE); } /** Close synthesizer engine */ @@ -188,7 +190,7 @@ static apt_bool_t demo_synth_engine_close(mrcp_engine_t *engine) apt_task_t *task = apt_consumer_task_base_get(demo_engine->task); apt_task_terminate(task,TRUE); } - return TRUE; + return mrcp_engine_close_respond(engine); } /** Create demo synthesizer channel derived from engine channel base */ @@ -270,10 +272,14 @@ static apt_bool_t demo_synth_channel_speak(mrcp_engine_channel_t *channel, mrcp_ 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); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set [%s] as Speech Source "APT_SIDRES_FMT, + file_path, + MRCP_MESSAGE_SIDRES(request)); } else { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"No Speech Source [%s] Found",file_path); + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"No Speech Source [%s] Found "APT_SIDRES_FMT, + file_path, + MRCP_MESSAGE_SIDRES(request)); /* 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); diff --git a/libs/unimrcp/plugins/mrcp-cepstral/Makefile.am b/libs/unimrcp/plugins/demo-verifier/Makefile.am similarity index 70% rename from libs/unimrcp/plugins/mrcp-cepstral/Makefile.am rename to libs/unimrcp/plugins/demo-verifier/Makefile.am index 38b9bab308..175950a055 100644 --- a/libs/unimrcp/plugins/mrcp-cepstral/Makefile.am +++ b/libs/unimrcp/plugins/demo-verifier/Makefile.am @@ -8,10 +8,9 @@ INCLUDES = -Iinclude \ -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) + $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES) -plugin_LTLIBRARIES = mrcpcepstral.la +plugin_LTLIBRARIES = demoverifier.la -mrcpcepstral_la_SOURCES = src/mrcp_swift.c -mrcpcepstral_la_LDFLAGS = -module $(PLUGIN_LT_VERSION) $(UNIMRCP_SWIFT_LDFLAGS) -mrcpcepstral_la_LIBADD = $(UNIMRCP_SWIFT_LIBS) +demoverifier_la_SOURCES = src/demo_verifier_engine.c +demoverifier_la_LDFLAGS = -module $(PLUGIN_LT_VERSION) diff --git a/libs/unimrcp/plugins/mrcp-cepstral/mrcpcepstral.vcproj b/libs/unimrcp/plugins/demo-verifier/demoverifier.vcproj similarity index 93% rename from libs/unimrcp/plugins/mrcp-cepstral/mrcpcepstral.vcproj rename to libs/unimrcp/plugins/demo-verifier/demoverifier.vcproj index e5a57dea79..efe5f79423 100644 --- a/libs/unimrcp/plugins/mrcp-cepstral/mrcpcepstral.vcproj +++ b/libs/unimrcp/plugins/demo-verifier/demoverifier.vcproj @@ -2,9 +2,9 @@ @@ -21,7 +21,7 @@ @@ -146,7 +146,7 @@ @@ -286,7 +286,7 @@ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" > diff --git a/libs/unimrcp/plugins/demo-verifier/src/demo_verifier_engine.c b/libs/unimrcp/plugins/demo-verifier/src/demo_verifier_engine.c new file mode 100644 index 0000000000..8918bedcbf --- /dev/null +++ b/libs/unimrcp/plugins/demo-verifier/src/demo_verifier_engine.c @@ -0,0 +1,577 @@ +/* + * Copyright 2008-2010 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. + * + * $Id: demo_verifier_engine.c 1776 2010-08-27 16:36:38Z achaloyan $ + */ + +/* + * Mandatory rules concerning plugin implementation. + * 1. Each plugin MUST implement a plugin/engine creator function + * with the exact signature and name (the main entry point) + * MRCP_PLUGIN_DECLARE(mrcp_engine_t*) mrcp_plugin_create(apr_pool_t *pool) + * 2. Each plugin MUST declare its version number + * MRCP_PLUGIN_VERSION_DECLARE + * 3. One and only one response MUST be sent back to the received request. + * 4. Methods (callbacks) of the MRCP engine channel MUST not block. + * (asynchronous response can be sent from the context of other thread) + * 5. Methods (callbacks) of the MPF engine stream MUST not block. + */ + +#include "mrcp_verifier_engine.h" +#include "mpf_activity_detector.h" +#include "apt_consumer_task.h" +#include "apt_log.h" + +#define VERIFIER_ENGINE_TASK_NAME "Demo Verifier Engine" + +typedef struct demo_verifier_engine_t demo_verifier_engine_t; +typedef struct demo_verifier_channel_t demo_verifier_channel_t; +typedef struct demo_verifier_msg_t demo_verifier_msg_t; + +/** Declaration of verification engine methods */ +static apt_bool_t demo_verifier_engine_destroy(mrcp_engine_t *engine); +static apt_bool_t demo_verifier_engine_open(mrcp_engine_t *engine); +static apt_bool_t demo_verifier_engine_close(mrcp_engine_t *engine); +static mrcp_engine_channel_t* demo_verifier_engine_channel_create(mrcp_engine_t *engine, apr_pool_t *pool); + +static const struct mrcp_engine_method_vtable_t engine_vtable = { + demo_verifier_engine_destroy, + demo_verifier_engine_open, + demo_verifier_engine_close, + demo_verifier_engine_channel_create +}; + + +/** Declaration of verification channel methods */ +static apt_bool_t demo_verifier_channel_destroy(mrcp_engine_channel_t *channel); +static apt_bool_t demo_verifier_channel_open(mrcp_engine_channel_t *channel); +static apt_bool_t demo_verifier_channel_close(mrcp_engine_channel_t *channel); +static apt_bool_t demo_verifier_channel_request_process(mrcp_engine_channel_t *channel, mrcp_message_t *request); + +static const struct mrcp_engine_channel_method_vtable_t channel_vtable = { + demo_verifier_channel_destroy, + demo_verifier_channel_open, + demo_verifier_channel_close, + demo_verifier_channel_request_process +}; + +/** Declaration of verification audio stream methods */ +static apt_bool_t demo_verifier_stream_destroy(mpf_audio_stream_t *stream); +static apt_bool_t demo_verifier_stream_open(mpf_audio_stream_t *stream, mpf_codec_t *codec); +static apt_bool_t demo_verifier_stream_close(mpf_audio_stream_t *stream); +static apt_bool_t demo_verifier_stream_write(mpf_audio_stream_t *stream, const mpf_frame_t *frame); + +static const mpf_audio_stream_vtable_t audio_stream_vtable = { + demo_verifier_stream_destroy, + NULL, + NULL, + NULL, + demo_verifier_stream_open, + demo_verifier_stream_close, + demo_verifier_stream_write +}; + +/** Declaration of demo verification engine */ +struct demo_verifier_engine_t { + apt_consumer_task_t *task; +}; + +/** Declaration of demo verification channel */ +struct demo_verifier_channel_t { + /** Back pointer to engine */ + demo_verifier_engine_t *demo_engine; + /** Engine channel base */ + mrcp_engine_channel_t *channel; + + /** Active (in-progress) verification request */ + mrcp_message_t *verifier_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 voiceprint to */ + FILE *audio_out; +}; + +typedef enum { + DEMO_VERIF_MSG_OPEN_CHANNEL, + DEMO_VERIF_MSG_CLOSE_CHANNEL, + DEMO_VERIF_MSG_REQUEST_PROCESS +} demo_verifier_msg_type_e; + +/** Declaration of demo verification task message */ +struct demo_verifier_msg_t { + demo_verifier_msg_type_e type; + mrcp_engine_channel_t *channel; + mrcp_message_t *request; +}; + +static apt_bool_t demo_verifier_msg_signal(demo_verifier_msg_type_e type, mrcp_engine_channel_t *channel, mrcp_message_t *request); +static apt_bool_t demo_verifier_msg_process(apt_task_t *task, apt_task_msg_t *msg); + +static apt_bool_t demo_verifier_result_load(demo_verifier_channel_t *verifier_channel, mrcp_message_t *message); + +/** Declare this macro to set plugin version */ +MRCP_PLUGIN_VERSION_DECLARE + +/** Declare this macro to use log routine of the server, plugin is loaded from */ +MRCP_PLUGIN_LOGGER_IMPLEMENT + +/** Create demo verification engine */ +MRCP_PLUGIN_DECLARE(mrcp_engine_t*) mrcp_plugin_create(apr_pool_t *pool) +{ + demo_verifier_engine_t *demo_engine = apr_palloc(pool,sizeof(demo_verifier_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_verifier_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,VERIFIER_ENGINE_TASK_NAME); + vtable = apt_task_vtable_get(task); + if(vtable) { + vtable->process_msg = demo_verifier_msg_process; + } + + /* create engine base */ + return mrcp_engine_create( + MRCP_VERIFIER_RESOURCE, /* MRCP resource identifier */ + demo_engine, /* object to associate */ + &engine_vtable, /* virtual methods table of engine */ + pool); /* pool to allocate memory from */ +} + +/** Destroy verification engine */ +static apt_bool_t demo_verifier_engine_destroy(mrcp_engine_t *engine) +{ + demo_verifier_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 verification engine */ +static apt_bool_t demo_verifier_engine_open(mrcp_engine_t *engine) +{ + demo_verifier_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 mrcp_engine_open_respond(engine,TRUE); +} + +/** Close verification engine */ +static apt_bool_t demo_verifier_engine_close(mrcp_engine_t *engine) +{ + demo_verifier_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 mrcp_engine_close_respond(engine); +} + +static mrcp_engine_channel_t* demo_verifier_engine_channel_create(mrcp_engine_t *engine, apr_pool_t *pool) +{ + mpf_stream_capabilities_t *capabilities; + mpf_termination_t *termination; + + /* create demo verification channel */ + demo_verifier_channel_t *verifier_channel = apr_palloc(pool,sizeof(demo_verifier_channel_t)); + verifier_channel->demo_engine = engine->obj; + verifier_channel->verifier_request = NULL; + verifier_channel->stop_response = NULL; + verifier_channel->detector = mpf_activity_detector_create(pool); + verifier_channel->audio_out = NULL; + + capabilities = mpf_sink_stream_capabilities_create(pool); + mpf_codec_capabilities_add( + &capabilities->codecs, + MPF_SAMPLE_RATE_8000 | MPF_SAMPLE_RATE_16000, + "LPCM"); + + /* create media termination */ + termination = mrcp_engine_audio_termination_create( + verifier_channel, /* object to associate */ + &audio_stream_vtable, /* virtual methods table of audio stream */ + capabilities, /* stream capabilities */ + pool); /* pool to allocate memory from */ + + /* create engine channel base */ + verifier_channel->channel = mrcp_engine_channel_create( + engine, /* engine */ + &channel_vtable, /* virtual methods table of engine channel */ + verifier_channel, /* object to associate */ + termination, /* associated media termination */ + pool); /* pool to allocate memory from */ + + return verifier_channel->channel; +} + +/** Destroy engine channel */ +static apt_bool_t demo_verifier_channel_destroy(mrcp_engine_channel_t *channel) +{ + /* nothing to destrtoy */ + return TRUE; +} + +/** Open engine channel (asynchronous response MUST be sent)*/ +static apt_bool_t demo_verifier_channel_open(mrcp_engine_channel_t *channel) +{ + return demo_verifier_msg_signal(DEMO_VERIF_MSG_OPEN_CHANNEL,channel,NULL); +} + +/** Close engine channel (asynchronous response MUST be sent)*/ +static apt_bool_t demo_verifier_channel_close(mrcp_engine_channel_t *channel) +{ + return demo_verifier_msg_signal(DEMO_VERIF_MSG_CLOSE_CHANNEL,channel,NULL); +} + +/** Process MRCP channel request (asynchronous response MUST be sent)*/ +static apt_bool_t demo_verifier_channel_request_process(mrcp_engine_channel_t *channel, mrcp_message_t *request) +{ + return demo_verifier_msg_signal(DEMO_VERIF_MSG_REQUEST_PROCESS,channel,request); +} + +/** Process VERIFY request */ +static apt_bool_t demo_verifier_channel_verify(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response) +{ + /* process verify request */ + mrcp_verifier_header_t *verifier_header; + demo_verifier_channel_t *verifier_channel = channel->method_obj; + verifier_channel->timers_started = TRUE; + + /* get verifier header */ + verifier_header = mrcp_resource_header_get(request); + if(verifier_header) { + if(mrcp_resource_header_property_check(request,VERIFIER_HEADER_START_INPUT_TIMERS) == TRUE) { + verifier_channel->timers_started = verifier_header->start_input_timers; + } + if(mrcp_resource_header_property_check(request,VERIFIER_HEADER_NO_INPUT_TIMEOUT) == TRUE) { + mpf_activity_detector_noinput_timeout_set(verifier_channel->detector,verifier_header->no_input_timeout); + } + if(mrcp_resource_header_property_check(request,VERIFIER_HEADER_SPEECH_COMPLETE_TIMEOUT) == TRUE) { + mpf_activity_detector_silence_timeout_set(verifier_channel->detector,verifier_header->speech_complete_timeout); + } + } + + if(!verifier_channel->audio_out) { + const apt_dir_layout_t *dir_layout = channel->engine->dir_layout; + const mpf_codec_descriptor_t *descriptor = mrcp_engine_sink_stream_codec_get(channel); + char *file_name = apr_psprintf(channel->pool,"voiceprint-%dkHz-%s.pcm", + descriptor ? descriptor->sampling_rate/1000 : 8, + request->channel_id.session_id.buf); + char *file_path = apt_datadir_filepath_get(dir_layout,file_name,channel->pool); + if(file_path) { + verifier_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); + verifier_channel->verifier_request = request; + return TRUE; +} + +/** Process STOP request */ +static apt_bool_t demo_verifier_channel_stop(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response) +{ + /* process STOP request */ + demo_verifier_channel_t *verifier_channel = channel->method_obj; + /* store STOP request, make sure there is no more activity and only then send the response */ + verifier_channel->stop_response = response; + return TRUE; +} + +/** Process START-INPUT-TIMERS request */ +static apt_bool_t demo_verifier_channel_timers_start(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response) +{ + demo_verifier_channel_t *verifier_channel = channel->method_obj; + verifier_channel->timers_started = TRUE; + return mrcp_engine_channel_message_send(channel,response); +} + +/** Process GET-INTERMEDIATE-RESULT request */ +static apt_bool_t demo_verifier_channel_get_result(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response) +{ + demo_verifier_channel_t *verifier_channel = channel->method_obj; + demo_verifier_result_load(verifier_channel,response); + return mrcp_engine_channel_message_send(channel,response); +} + + +/** Dispatch MRCP request */ +static apt_bool_t demo_verifier_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 VERIFIER_SET_PARAMS: + break; + case VERIFIER_GET_PARAMS: + break; + case VERIFIER_START_SESSION: + break; + case VERIFIER_END_SESSION: + break; + case VERIFIER_QUERY_VOICEPRINT: + break; + case VERIFIER_DELETE_VOICEPRINT: + break; + case VERIFIER_VERIFY: + processed = demo_verifier_channel_verify(channel,request,response); + break; + case VERIFIER_VERIFY_FROM_BUFFER: + break; + case VERIFIER_VERIFY_ROLLBACK: + break; + case VERIFIER_STOP: + processed = demo_verifier_channel_stop(channel,request,response); + break; + case VERIFIER_CLEAR_BUFFER: + break; + case VERIFIER_START_INPUT_TIMERS: + processed = demo_verifier_channel_timers_start(channel,request,response); + break; + case VERIFIER_GET_INTERMIDIATE_RESULT: + processed = demo_verifier_channel_get_result(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_verifier_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_verifier_stream_open(mpf_audio_stream_t *stream, mpf_codec_t *codec) +{ + return TRUE; +} + +/** Callback is called from MPF engine context to perform any action after close */ +static apt_bool_t demo_verifier_stream_close(mpf_audio_stream_t *stream) +{ + return TRUE; +} + +/* Raise demo START-OF-INPUT event */ +static apt_bool_t demo_verifier_start_of_input(demo_verifier_channel_t *verifier_channel) +{ + /* create START-OF-INPUT event */ + mrcp_message_t *message = mrcp_event_create( + verifier_channel->verifier_request, + VERIFIER_START_OF_INPUT, + verifier_channel->verifier_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(verifier_channel->channel,message); +} + +/* Load demo verification result */ +static apt_bool_t demo_verifier_result_load(demo_verifier_channel_t *verifier_channel, mrcp_message_t *message) +{ + FILE *file; + mrcp_engine_channel_t *channel = verifier_channel->channel; + const apt_dir_layout_t *dir_layout = channel->engine->dir_layout; + char *file_path = apt_datadir_filepath_get(dir_layout,"result-verification.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/nlsml+xml",message->pool); + mrcp_generic_header_property_add(message,GENERIC_HEADER_CONTENT_TYPE); + } + } + return TRUE; +} + +/* Raise demo VERIFICATION-COMPLETE event */ +static apt_bool_t demo_verifier_verification_complete(demo_verifier_channel_t *verifier_channel, mrcp_verifier_completion_cause_e cause) +{ + mrcp_verifier_header_t *verifier_header; + /* create VERIFICATION-COMPLETE event */ + mrcp_message_t *message = mrcp_event_create( + verifier_channel->verifier_request, + VERIFIER_VERIFICATION_COMPLETE, + verifier_channel->verifier_request->pool); + if(!message) { + return FALSE; + } + + /* get/allocate verifier header */ + verifier_header = mrcp_resource_header_prepare(message); + if(verifier_header) { + /* set completion cause */ + verifier_header->completion_cause = cause; + mrcp_resource_header_property_add(message,VERIFIER_HEADER_COMPLETION_CAUSE); + } + /* set request state */ + message->start_line.request_state = MRCP_REQUEST_STATE_COMPLETE; + + if(cause == VERIFIER_COMPLETION_CAUSE_SUCCESS) { + demo_verifier_result_load(verifier_channel,message); + } + + verifier_channel->verifier_request = NULL; + /* send asynch event */ + return mrcp_engine_channel_message_send(verifier_channel->channel,message); +} + +/** Callback is called from MPF engine context to write/send new frame */ +static apt_bool_t demo_verifier_stream_write(mpf_audio_stream_t *stream, const mpf_frame_t *frame) +{ + demo_verifier_channel_t *verifier_channel = stream->obj; + if(verifier_channel->stop_response) { + /* send asynchronous response to STOP request */ + mrcp_engine_channel_message_send(verifier_channel->channel,verifier_channel->stop_response); + verifier_channel->stop_response = NULL; + verifier_channel->verifier_request = NULL; + return TRUE; + } + + if(verifier_channel->verifier_request) { + mpf_detector_event_e det_event = mpf_activity_detector_process(verifier_channel->detector,frame); + switch(det_event) { + case MPF_DETECTOR_EVENT_ACTIVITY: + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected Voice Activity "APT_SIDRES_FMT, + MRCP_MESSAGE_SIDRES(verifier_channel->verifier_request)); + demo_verifier_start_of_input(verifier_channel); + break; + case MPF_DETECTOR_EVENT_INACTIVITY: + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected Voice Inactivity "APT_SIDRES_FMT, + MRCP_MESSAGE_SIDRES(verifier_channel->verifier_request)); + demo_verifier_verification_complete(verifier_channel,VERIFIER_COMPLETION_CAUSE_SUCCESS); + break; + case MPF_DETECTOR_EVENT_NOINPUT: + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected Noinput "APT_SIDRES_FMT, + MRCP_MESSAGE_SIDRES(verifier_channel->verifier_request)); + if(verifier_channel->timers_started == TRUE) { + demo_verifier_verification_complete(verifier_channel,VERIFIER_COMPLETION_CAUSE_NO_INPUT_TIMEOUT); + } + break; + default: + break; + } + + if((frame->type & MEDIA_FRAME_TYPE_EVENT) == MEDIA_FRAME_TYPE_EVENT) { + if(frame->marker == MPF_MARKER_START_OF_EVENT) { + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected Start of Event "APT_SIDRES_FMT" id:%d", + MRCP_MESSAGE_SIDRES(verifier_channel->verifier_request), + frame->event_frame.event_id); + } + else if(frame->marker == MPF_MARKER_END_OF_EVENT) { + apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected End of Event "APT_SIDRES_FMT" id:%d duration:%d ts", + MRCP_MESSAGE_SIDRES(verifier_channel->verifier_request), + frame->event_frame.event_id, + frame->event_frame.duration); + } + } + + if(verifier_channel->audio_out) { + fwrite(frame->codec_frame.buffer,1,frame->codec_frame.size,verifier_channel->audio_out); + } + } + return TRUE; +} + +static apt_bool_t demo_verifier_msg_signal(demo_verifier_msg_type_e type, mrcp_engine_channel_t *channel, mrcp_message_t *request) +{ + apt_bool_t status = FALSE; + demo_verifier_channel_t *demo_channel = channel->method_obj; + demo_verifier_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_verifier_msg_t *demo_msg; + msg->type = TASK_MSG_USER; + demo_msg = (demo_verifier_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_verifier_msg_process(apt_task_t *task, apt_task_msg_t *msg) +{ + demo_verifier_msg_t *demo_msg = (demo_verifier_msg_t*)msg->data; + switch(demo_msg->type) { + case DEMO_VERIF_MSG_OPEN_CHANNEL: + /* open channel and send asynch response */ + mrcp_engine_channel_open_respond(demo_msg->channel,TRUE); + break; + case DEMO_VERIF_MSG_CLOSE_CHANNEL: + { + /* close channel, make sure there is no activity and send asynch response */ + demo_verifier_channel_t *verifier_channel = demo_msg->channel->method_obj; + if(verifier_channel->audio_out) { + fclose(verifier_channel->audio_out); + verifier_channel->audio_out = NULL; + } + + mrcp_engine_channel_close_respond(demo_msg->channel); + break; + } + case DEMO_VERIF_MSG_REQUEST_PROCESS: + demo_verifier_channel_request_dispatch(demo_msg->channel,demo_msg->request); + break; + default: + break; + } + return TRUE; +} diff --git a/libs/unimrcp/plugins/mrcp-cepstral/mrcpcepstral.2008.vcproj b/libs/unimrcp/plugins/mrcp-cepstral/mrcpcepstral.2008.vcproj deleted file mode 100644 index abdb4cec4c..0000000000 --- a/libs/unimrcp/plugins/mrcp-cepstral/mrcpcepstral.2008.vcproj +++ /dev/null @@ -1,164 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/unimrcp/plugins/mrcp-cepstral/src/mrcp_swift.c b/libs/unimrcp/plugins/mrcp-cepstral/src/mrcp_swift.c deleted file mode 100644 index 037939b8dd..0000000000 --- a/libs/unimrcp/plugins/mrcp-cepstral/src/mrcp_swift.c +++ /dev/null @@ -1,774 +0,0 @@ -/* - * 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. - */ - -/* - * Mandatory rules concerning plugin implementation. - * 1. Each plugin MUST implement a plugin/engine creator function - * with the exact signature and name (the main entry point) - * MRCP_PLUGIN_DECLARE(mrcp_engine_t*) mrcp_plugin_create(apr_pool_t *pool) - * 2. Each plugin MUST declare its version number - * MRCP_PLUGIN_VERSION_DECLARE - * 3. One and only one response MUST be sent back to the received request. - * 4. Methods (callbacks) of the MRCP engine channel MUST not block. - * (asynchronous response can be sent from the context of other thread) - * 5. Methods (callbacks) of the MPF engine stream MUST not block. - */ - -#include -#include -#include "mrcp_synth_engine.h" -#include "mpf_buffer.h" -#include "apt_log.h" - -/** Declaration of synthesizer engine methods */ -static apt_bool_t mrcp_swift_engine_destroy(mrcp_engine_t *engine); -static apt_bool_t mrcp_swift_engine_open(mrcp_engine_t *engine); -static apt_bool_t mrcp_swift_engine_close(mrcp_engine_t *engine); -static mrcp_engine_channel_t* mrcp_swift_engine_channel_create(mrcp_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, mpf_codec_t *codec); -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_engine_t mrcp_swift_engine_t; -/** Declaration of Swift synthesizer engine */ -struct mrcp_swift_engine_t { - /** Swift synthesizer engine */ - swift_engine *swift; - /** Speech language mapping */ - apr_table_t *language_table; - /** Sampling rates (bitmask of mpf_sample_rates_e) - installed voices support */ - int sample_rates; -}; - -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* mrcp_swift_language_table_create(apr_pool_t *pool); -static apt_bool_t mrcp_swift_voices_scan(mrcp_swift_engine_t *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 set plugin version */ -MRCP_PLUGIN_VERSION_DECLARE - -/** 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_engine_t*) mrcp_plugin_create(apr_pool_t *pool) -{ - mrcp_swift_engine_t *synth_engine = apr_palloc(pool,sizeof(mrcp_swift_engine_t)); - synth_engine->swift = NULL; - synth_engine->language_table = mrcp_swift_language_table_create(pool); - synth_engine->sample_rates = MPF_SAMPLE_RATE_NONE; - - /* create engine base */ - return mrcp_engine_create( - MRCP_SYNTHESIZER_RESOURCE, /* MRCP resource identifier */ - synth_engine, /* object to associate */ - &engine_vtable, /* virtual methods table of engine */ - pool); /* pool to allocate memory from */ -} - -/** Destroy synthesizer engine */ -static apt_bool_t mrcp_swift_engine_destroy(mrcp_engine_t *engine) -{ - /* nothing to destroy */ - return TRUE; -} - -/** Open synthesizer engine */ -static apt_bool_t mrcp_swift_engine_open(mrcp_engine_t *engine) -{ - mrcp_swift_engine_t *synth_engine = engine->obj; - - /* open swift engine */ - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open Swift Engine [%s]",swift_version); - if((synth_engine->swift = swift_engine_open(NULL)) == NULL) { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Open Swift Engine"); - return FALSE; - } - - if(mrcp_swift_voices_scan(synth_engine) == FALSE) { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Scan Swift Voices"); - swift_engine_close(synth_engine->swift); - synth_engine->swift = NULL; - return FALSE; - } - return TRUE; -} - -/** Close synthesizer engine */ -static apt_bool_t mrcp_swift_engine_close(mrcp_engine_t *engine) -{ - mrcp_swift_engine_t *synth_engine = engine->obj; - - /* close swift engine */ - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close Swift Engine"); - if(synth_engine->swift) { - swift_engine_close(synth_engine->swift); - synth_engine->swift = NULL; - } - return TRUE; -} - -/** Create demo synthesizer channel derived from engine channel base */ -static mrcp_engine_channel_t* mrcp_swift_engine_channel_create(mrcp_engine_t *engine, apr_pool_t *pool) -{ - mrcp_swift_engine_t *synth_engine = engine->obj; - - mpf_stream_capabilities_t *capabilities; - mpf_termination_t *termination; - mrcp_engine_channel_t *channel; - - /* create swift synth channel */ - mrcp_swift_channel_t *synth_channel = apr_palloc(pool,sizeof(mrcp_swift_channel_t)); - synth_channel->port = NULL; - synth_channel->tts_stream = 0; - synth_channel->channel = NULL; - synth_channel->audio_buffer = NULL; - synth_channel->speak_request = NULL; - synth_channel->stop_response = NULL; - synth_channel->paused = FALSE; - - capabilities = mpf_source_stream_capabilities_create(pool); - mpf_codec_capabilities_add( - &capabilities->codecs, - synth_engine->sample_rates, - "LPCM"); - - /* create media termination */ - termination = mrcp_engine_audio_termination_create( - synth_channel, /* object to associate */ - &audio_stream_vtable, /* virtual methods table of audio stream */ - capabilities, /* stream capabilities */ - pool); /* pool to allocate memory from */ - - /* create engine channel base */ - channel = mrcp_engine_channel_create( - engine, /* engine */ - &channel_vtable, /* virtual methods table of engine channel */ - synth_channel, /* object to associate */ - termination, /* associated media termination */ - pool); /* pool to allocate memory from */ - - if(channel) { - synth_channel->audio_buffer = mpf_buffer_create(pool); - } - synth_channel->channel = channel; - return channel; -} - -/** Destroy engine channel */ -static apt_bool_t mrcp_swift_channel_destroy(mrcp_engine_channel_t *channel) -{ - /* nothing to destroy */ - 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 */ - apt_bool_t status = FALSE; - mrcp_swift_channel_t *synth_channel = channel->method_obj; - mrcp_swift_engine_t *synth_engine = channel->engine->obj; - const mpf_codec_descriptor_t *descriptor = mrcp_engine_source_stream_codec_get(synth_channel->channel); - if(descriptor) { - swift_params *params; - swift_port *port; - - params = swift_params_new(NULL); - swift_params_set_string(params, "audio/encoding", "pcm16"); - swift_params_set_int(params, "audio/sampling-rate", descriptor->sampling_rate); - /* open swift port */ - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open Swift Port"); - port = swift_port_open(synth_engine->swift,params); - if(port) { - /* 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->port = port; - status = TRUE; - } - else { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Open Swift Port"); - } - } - - return mrcp_engine_channel_open_respond(channel,status); -} - -/** 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 */ - 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 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, mpf_codec_t *codec) -{ - 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; - mrcp_engine_t *engine = synth_channel->channel->engine; - mrcp_swift_engine_t *synth_engine = engine->obj; - if(synth_engine && synth_engine->language_table) { - swift_lang_name = apr_table_get(synth_engine->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 Swift Voice Matching the Criteria [%s]", search_criteria); - voice = swift_port_find_first_voice(synth_channel->port,search_criteria,NULL); - if(!voice) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"No Swift Voice Available Matching the Criteria [%s]",search_criteria); - /* find the first available one */ - voice = swift_port_find_first_voice(synth_channel->port,NULL,NULL); - } - - if(voice) { - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set Swift Voice [%s]", - swift_voice_get_attribute(voice, "name")); - 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; -} - -/** Get volume by prosody params */ -static 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; -} - -/** Get rate by prosody params */ -static 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; -} - -static void mrcp_swift_sample_rates_set(mrcp_swift_engine_t *engine, const char *str) -{ - if(str) { - int value = atoi(str); - if(value == 8000) { - engine->sample_rates |= MPF_SAMPLE_RATE_8000; - } - else if(value == 16000) { - engine->sample_rates |= MPF_SAMPLE_RATE_8000 | MPF_SAMPLE_RATE_16000; - } - } -} - -/** Scan Swift available voices */ -static apt_bool_t mrcp_swift_voices_scan(mrcp_swift_engine_t *engine) -{ - swift_port *port; - swift_voice *voice; - const char *license_status; - const char *sample_rate; - - if(!engine->swift) { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Invalid Swift Engine"); - return FALSE; - } - - /* open swift port*/ - if((port = swift_port_open(engine->swift, NULL)) == NULL) { - apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Open Swift Port"); - return FALSE; - } - - engine->sample_rates = MPF_SAMPLE_RATE_NONE; - - /* 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 FALSE; - } - /* 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"; - } - sample_rate = swift_voice_get_attribute(voice, "sample-rate"); - apt_log(APT_LOG_MARK,APT_PRIO_INFO,"%s: %s, age %s, %s, %sHz, %s, %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"), - sample_rate, - swift_voice_get_attribute(voice, "version"), - license_status); - - mrcp_swift_sample_rates_set(engine,sample_rate); - } - - swift_port_close(port); - return TRUE; -} - -/** 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/plugins/mrcp-flite/include/flite_voices.h b/libs/unimrcp/plugins/mrcp-flite/include/flite_voices.h index eb5a438368..59ebaf8b4d 100644 --- a/libs/unimrcp/plugins/mrcp-flite/include/flite_voices.h +++ b/libs/unimrcp/plugins/mrcp-flite/include/flite_voices.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ * 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. + * + * $Id: flite_voices.h 1474 2010-02-07 20:51:47Z achaloyan $ */ -#ifndef __FLITE_VOICES_H__ -#define __FLITE_VOICES_H__ +#ifndef FLITE_VOICES_H +#define FLITE_VOICES_H /** * @file flite_voices.h @@ -42,4 +44,4 @@ cst_voice* flite_voices_best_match_get(flite_voices_t *voices, mrcp_message_t *m APT_END_EXTERN_C -#endif /*__FLITE_VOICES_H__*/ +#endif /* FLITE_VOICES_H */ diff --git a/libs/unimrcp/plugins/mrcp-flite/mrcpflite.2008.vcproj b/libs/unimrcp/plugins/mrcp-flite/mrcpflite.2008.vcproj deleted file mode 100644 index 9767ed6e40..0000000000 --- a/libs/unimrcp/plugins/mrcp-flite/mrcpflite.2008.vcproj +++ /dev/null @@ -1,172 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/unimrcp/plugins/mrcp-flite/src/flite_voices.c b/libs/unimrcp/plugins/mrcp-flite/src/flite_voices.c index eb37963b32..d3bfe293ae 100644 --- a/libs/unimrcp/plugins/mrcp-flite/src/flite_voices.c +++ b/libs/unimrcp/plugins/mrcp-flite/src/flite_voices.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: flite_voices.c 1474 2010-02-07 20:51:47Z achaloyan $ */ #include "flite_voices.h" diff --git a/libs/unimrcp/plugins/mrcp-flite/src/mrcp_flite.c b/libs/unimrcp/plugins/mrcp-flite/src/mrcp_flite.c index 5d691aca80..b3b3f80130 100644 --- a/libs/unimrcp/plugins/mrcp-flite/src/mrcp_flite.c +++ b/libs/unimrcp/plugins/mrcp-flite/src/mrcp_flite.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Arsen Chaloyan + * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,8 @@ * 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. + * + * $Id: mrcp_flite.c 1678 2010-05-01 18:54:07Z achaloyan $ */ /* @@ -158,7 +160,7 @@ static apt_bool_t flite_synth_engine_open(mrcp_engine_t *engine) flite_engine->voices = flite_voices_load(engine->pool); apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite init success"); - return TRUE; + return mrcp_engine_open_respond(engine,TRUE); } /** Close synthesizer engine */ @@ -169,7 +171,7 @@ static apt_bool_t flite_synth_engine_close(mrcp_engine_t *engine) flite_voices_unload(flite_engine->voices); - return TRUE; + return mrcp_engine_close_respond(engine); } static apt_bool_t flite_synth_task_create(flite_synth_channel_t *synth_channel) diff --git a/libs/unimrcp/plugins/mrcp-pocketsphinx/conf/pocketsphinx.xml b/libs/unimrcp/plugins/mrcp-pocketsphinx/conf/pocketsphinx.xml index f9bbb6a6b3..6d7bfa1ef5 100644 --- a/libs/unimrcp/plugins/mrcp-pocketsphinx/conf/pocketsphinx.xml +++ b/libs/unimrcp/plugins/mrcp-pocketsphinx/conf/pocketsphinx.xml @@ -1,9 +1,10 @@ + - + FreeSWITCH logging bridge */ -static apt_bool_t unimrcp_log(const char *file, int line, const char *id, apt_log_priority_e priority, const char *format, va_list arg_ptr); +static apt_bool_t unimrcp_log(const char *file, int line, const char *obj, apt_log_priority_e priority, const char *format, va_list arg_ptr); static apt_log_priority_e str_to_log_level(const char *level); static int get_next_speech_channel_number(void); @@ -1810,56 +1814,66 @@ static apt_bool_t speech_on_session_terminate(mrcp_application_t *application, m * @return TRUE */ static apt_bool_t speech_on_channel_add(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, - mrcp_sig_status_code_e status) + mrcp_sig_status_code_e status) { switch_event_t *event = NULL; speech_channel_t *schannel = (speech_channel_t *) mrcp_application_channel_object_get(channel); + char codec_name[60] = { 0 }; + const mpf_codec_descriptor_t *descriptor; /* check status */ - if (session && schannel && status == MRCP_SIG_STATUS_CODE_SUCCESS) { - char codec_name[60] = { 0 }; - const mpf_codec_descriptor_t *descriptor; - /* what sample rate did we negotiate? */ + if (!session || !schannel || status != MRCP_SIG_STATUS_CODE_SUCCESS) { + goto error; + } + + /* what sample rate did we negotiate? */ + if (schannel->type == SPEECH_CHANNEL_SYNTHESIZER) { + descriptor = mrcp_application_sink_descriptor_get(channel); + } else { + descriptor = mrcp_application_source_descriptor_get(channel); + } + if (!descriptor) { + goto error; + } + schannel->rate = descriptor->sampling_rate; + if (descriptor->name.length) { + strncpy(codec_name, descriptor->name.buf, sizeof(codec_name)); + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) %s channel is ready, codec = %s, sample rate = %d\n", schannel->name, + speech_channel_type_to_string(schannel->type), codec_name, schannel->rate); + speech_channel_set_state(schannel, SPEECH_CHANNEL_READY); + + /* notify of channel open */ + if (globals.enable_profile_events && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_PROFILE_OPEN) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "MRCP-Profile", schannel->profile->name); if (schannel->type == SPEECH_CHANNEL_SYNTHESIZER) { - descriptor = mrcp_application_sink_descriptor_get(channel); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "MRCP-Resource-Type", "TTS"); } else { - descriptor = mrcp_application_source_descriptor_get(channel); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "MRCP-Resource-Type", "ASR"); } - schannel->rate = descriptor->sampling_rate; - if (descriptor->name.length) { - strncpy(codec_name, descriptor->name.buf, sizeof(codec_name)); - } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) %s channel is ready, codec = %s, sample rate = %d\n", schannel->name, - speech_channel_type_to_string(schannel->type), codec_name, schannel->rate); - speech_channel_set_state(schannel, SPEECH_CHANNEL_READY); - /* notify of channel open */ - if (globals.enable_profile_events && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_PROFILE_OPEN) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "MRCP-Profile", schannel->profile->name); - if (schannel->type == SPEECH_CHANNEL_SYNTHESIZER) { - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "MRCP-Resource-Type", "TTS"); - } else { - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "MRCP-Resource-Type", "ASR"); - } - switch_event_fire(&event); - } - schannel->channel_opened = 1; + switch_event_fire(&event); + } + schannel->channel_opened = 1; + + return TRUE; + +error: + if (schannel) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "(%s) %s channel error!\n", schannel->name, + speech_channel_type_to_string(schannel->type)); } else { - if (schannel) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "(%s) %s channel error!\n", schannel->name, - speech_channel_type_to_string(schannel->type)); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "(unknown) channel error!\n"); - } - if (session) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Terminating MRCP session\n"); - speech_channel_set_state(schannel, SPEECH_CHANNEL_ERROR); - mrcp_application_session_terminate(session); - } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "(unknown) channel error!\n"); + } + if (session) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Terminating MRCP session\n"); + speech_channel_set_state(schannel, SPEECH_CHANNEL_ERROR); + mrcp_application_session_terminate(session); } return TRUE; } + /** * Handle the UniMRCP responses sent to channel remove requests * @@ -3729,7 +3743,7 @@ static int process_profile_config(profile_t *profile, const char *param, const c * @param pool memory pool to use * @return true if this param belongs to RTP config */ -static int process_rtp_config(mrcp_client_t *client, mpf_rtp_config_t *rtp_config, const char *param, const char *val, apr_pool_t *pool) +static int process_rtp_config(mrcp_client_t *client, mpf_rtp_config_t *rtp_config, mpf_rtp_settings_t *rtp_settings, const char *param, const char *val, apr_pool_t *pool) { int mine = 1; if (strcasecmp(param, "rtp-ip") == 0) { @@ -3741,26 +3755,26 @@ static int process_rtp_config(mrcp_client_t *client, mpf_rtp_config_t *rtp_confi } else if (strcasecmp(param, "rtp-port-max") == 0) { rtp_config->rtp_port_max = (apr_port_t) atol(val); } else if (strcasecmp(param, "playout-delay") == 0) { - rtp_config->jb_config.initial_playout_delay = atol(val); + rtp_settings->jb_config.initial_playout_delay = atol(val); } else if (strcasecmp(param, "min-playout-delay") == 0) { - rtp_config->jb_config.min_playout_delay = atol(val); + rtp_settings->jb_config.min_playout_delay = atol(val); } else if (strcasecmp(param, "max-playout-delay") == 0) { - rtp_config->jb_config.max_playout_delay = atol(val); + rtp_settings->jb_config.max_playout_delay = atol(val); } else if (strcasecmp(param, "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, val, pool); + mpf_codec_manager_codec_list_load(codec_manager, &rtp_settings->codec_list, val, pool); } } else if (strcasecmp(param, "ptime") == 0) { - rtp_config->ptime = (apr_uint16_t) atol(val); + rtp_settings->ptime = (apr_uint16_t) atol(val); } else if (strcasecmp(param, "rtcp") == 0) { - rtp_config->rtcp = atoi(val); + rtp_settings->rtcp = atoi(val); } else if (strcasecmp(param, "rtcp-bye") == 0) { - rtp_config->rtcp_bye_policy = atoi(val); + rtp_settings->rtcp_bye_policy = atoi(val); } else if (strcasecmp(param, "rtcp-tx-interval") == 0) { - rtp_config->rtcp_tx_interval = (apr_uint16_t) atoi(val); + rtp_settings->rtcp_tx_interval = (apr_uint16_t) atoi(val); } else if (strcasecmp(param, "rtcp-rx-resolution") == 0) { - rtp_config->rtcp_rx_resolution = (apr_uint16_t) atol(val); + rtp_settings->rtcp_rx_resolution = (apr_uint16_t) atol(val); } else { mine = 0; } @@ -3771,28 +3785,29 @@ static int process_rtp_config(mrcp_client_t *client, mpf_rtp_config_t *rtp_confi /** * set RTSP client config struct with param, val pair * @param config the config struct to set + * @param sig_settings the sig settings struct to set * @param param the param name * @param val the param value * @param pool memory pool to use * @return true if this param belongs to RTSP config */ -static int process_mrcpv1_config(rtsp_client_config_t *config, const char *param, const char *val, apr_pool_t *pool) +static int process_mrcpv1_config(rtsp_client_config_t *config, mrcp_sig_settings_t *sig_settings, const char *param, const char *val, apr_pool_t *pool) { int mine = 1; if (strcasecmp(param, "server-ip") == 0) { - config->server_ip = ip_addr_get(val, pool); + sig_settings->server_ip = ip_addr_get(val, pool); } else if (strcasecmp(param, "server-port") == 0) { - config->server_port = (apr_port_t) atol(val); + sig_settings->server_port = (apr_port_t) atol(val); } else if (strcasecmp(param, "resource-location") == 0) { - config->resource_location = apr_pstrdup(pool, val); + sig_settings->resource_location = apr_pstrdup(pool, val); } else if (strcasecmp(param, "sdp-origin") == 0) { config->origin = apr_pstrdup(pool, val); } else if (strcasecmp(param, "max-connection-count") == 0) { config->max_connection_count = atol(val); } else if (strcasecmp(param, "force-destination") == 0) { - config->force_destination = atoi(val); + sig_settings->force_destination = atoi(val); } else if (strcasecmp(param, "speechsynth") == 0 || strcasecmp(param, "speechrecog") == 0) { - apr_table_set(config->resource_map, param, val); + apr_table_set(sig_settings->resource_map, param, val); } else { mine = 0; } @@ -3802,12 +3817,13 @@ static int process_mrcpv1_config(rtsp_client_config_t *config, const char *param /** * set SofiaSIP client config struct with param, val pair * @param config the config struct to set + * @param sig_settings the sig settings struct to set * @param param the param name * @param val the param value * @param pool memory pool to use * @return true if this param belongs to SofiaSIP config */ -static int process_mrcpv2_config(mrcp_sofia_client_config_t *config, const char *param, const char *val, apr_pool_t *pool) +static int process_mrcpv2_config(mrcp_sofia_client_config_t *config, mrcp_sig_settings_t *sig_settings, const char *param, const char *val, apr_pool_t *pool) { int mine = 1; if (strcasecmp(param, "client-ip") == 0) { @@ -3817,13 +3833,13 @@ static int process_mrcpv2_config(mrcp_sofia_client_config_t *config, const char } else if (strcasecmp(param, "client-port") == 0) { config->local_port = (apr_port_t) atol(val); } else if (strcasecmp(param, "server-ip") == 0) { - config->remote_ip = ip_addr_get(val, pool); + sig_settings->server_ip = ip_addr_get(val, pool); } else if (strcasecmp(param, "server-port") == 0) { - config->remote_port = (apr_port_t) atol(val); + sig_settings->server_port = (apr_port_t) atol(val); } else if (strcasecmp(param, "server-username") == 0) { - config->remote_user_name = apr_pstrdup(pool, val); + sig_settings->user_name = apr_pstrdup(pool, val); } else if (strcasecmp(param, "force-destination") == 0) { - config->force_destination = atoi(val); + sig_settings->force_destination = atoi(val); } else if (strcasecmp(param, "sip-transport") == 0) { config->transport = apr_pstrdup(pool, val); } else if (strcasecmp(param, "ua-name") == 0) { @@ -3905,15 +3921,21 @@ static mrcp_client_t *mod_unimrcp_client_create(switch_memory_pool_t *mod_pool) if (!zstr(globals.unimrcp_offer_new_connection)) { offer_new_connection = strcasecmp("true", globals.unimrcp_offer_new_connection); } - connection_agent = mrcp_client_connection_agent_create(max_connection_count, offer_new_connection, pool); + connection_agent = mrcp_client_connection_agent_create("MRCPv2ConnectionAgent", max_connection_count, offer_new_connection, pool); if (connection_agent) { - mrcp_client_connection_agent_register(client, connection_agent, "MRCPv2ConnectionAgent"); + if (!zstr(globals.unimrcp_request_timeout)) { + apr_size_t request_timeout = (apr_size_t)atol(globals.unimrcp_request_timeout); + if (request_timeout > 0) { + mrcp_client_connection_timeout_set(connection_agent, request_timeout); + } + } + mrcp_client_connection_agent_register(client, connection_agent); } /* Set up the media engine that will be shared with all profiles */ - media_engine = mpf_engine_create(pool); + media_engine = mpf_engine_create("MediaEngine", pool); if (media_engine) { - mrcp_client_media_engine_register(client, media_engine, "MediaEngine"); + mrcp_client_media_engine_register(client, media_engine); } /* configure the client profiles */ @@ -3929,6 +3951,8 @@ static mrcp_client_t *mod_unimrcp_client_create(switch_memory_pool_t *mod_pool) mpf_termination_factory_t *termination_factory = NULL; mrcp_profile_t *mprofile = NULL; mpf_rtp_config_t *rtp_config = NULL; + mpf_rtp_settings_t *rtp_settings = mpf_rtp_settings_alloc(pool); + mrcp_sig_settings_t *sig_settings = mrcp_signaling_settings_alloc(pool); profile_t *mod_profile = NULL; switch_xml_t default_params = NULL; @@ -3992,18 +4016,24 @@ static mrcp_client_t *mod_unimrcp_client_create(switch_memory_pool_t *mod_pool) } /* create RTP config, common to MRCPv1 and MRCPv2 */ - rtp_config = mpf_rtp_config_create(pool); + rtp_config = mpf_rtp_config_alloc(pool); rtp_config->rtp_port_min = DEFAULT_RTP_PORT_MIN; rtp_config->rtp_port_max = DEFAULT_RTP_PORT_MAX; apt_string_set(&rtp_config->ip, DEFAULT_LOCAL_IP_ADDRESS); if (strcmp("1", version) == 0) { /* MRCPv1 configuration */ - rtsp_client_config_t *config = mrcp_unirtsp_client_config_alloc(pool); switch_xml_t param = NULL; + rtsp_client_config_t *config = mrcp_unirtsp_client_config_alloc(pool); config->origin = DEFAULT_SDP_ORIGIN; - config->resource_location = DEFAULT_RESOURCE_LOCATION; + sig_settings->resource_location = DEFAULT_RESOURCE_LOCATION; + if (!zstr(globals.unimrcp_request_timeout)) { + apr_size_t request_timeout = (apr_size_t)atol(globals.unimrcp_request_timeout); + if (request_timeout > 0) { + config->request_timeout = request_timeout; + } + } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Loading MRCPv1 profile: %s\n", name); for (param = switch_xml_child(profile, "param"); param; param = switch_xml_next(param)) { const char *param_name = switch_xml_attr(param, "name"); @@ -4014,21 +4044,21 @@ static mrcp_client_t *mod_unimrcp_client_create(switch_memory_pool_t *mod_pool) goto done; } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Loading Param %s:%s\n", param_name, param_value); - if (!process_mrcpv1_config(config, param_name, param_value, pool) && - !process_rtp_config(client, rtp_config, param_name, param_value, pool) && + if (!process_mrcpv1_config(config, sig_settings, param_name, param_value, pool) && + !process_rtp_config(client, rtp_config, rtp_settings, param_name, param_value, pool) && !process_profile_config(mod_profile, param_name, param_value, mod_pool)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown param %s\n", param_name); } } - agent = mrcp_unirtsp_client_agent_create(config, pool); + agent = mrcp_unirtsp_client_agent_create(name, config, pool); } else if (strcmp("2", version) == 0) { /* MRCPv2 configuration */ mrcp_sofia_client_config_t *config = mrcp_sofiasip_client_config_alloc(pool); switch_xml_t param = NULL; 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; + sig_settings->server_ip = DEFAULT_REMOTE_IP_ADDRESS; + sig_settings->server_port = DEFAULT_SIP_REMOTE_PORT; config->ext_ip = NULL; config->user_agent_name = DEFAULT_SOFIASIP_UA_NAME; config->origin = DEFAULT_SDP_ORIGIN; @@ -4042,13 +4072,13 @@ static mrcp_client_t *mod_unimrcp_client_create(switch_memory_pool_t *mod_pool) goto done; } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Loading Param %s:%s\n", param_name, param_value); - if (!process_mrcpv2_config(config, param_name, param_value, pool) && - !process_rtp_config(client, rtp_config, param_name, param_value, pool) && + if (!process_mrcpv2_config(config, sig_settings, param_name, param_value, pool) && + !process_rtp_config(client, rtp_config, rtp_settings, param_name, param_value, pool) && !process_profile_config(mod_profile, param_name, param_value, mod_pool)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown param %s\n", param_name); } } - agent = mrcp_sofiasip_client_agent_create(config, pool); + agent = mrcp_sofiasip_client_agent_create(name, config, pool); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "version must be either \"1\" or \"2\"\n"); client = NULL; @@ -4060,11 +4090,11 @@ static mrcp_client_t *mod_unimrcp_client_create(switch_memory_pool_t *mod_pool) mrcp_client_rtp_factory_register(client, termination_factory, name); } if (agent) { - mrcp_client_signaling_agent_register(client, agent, name); + mrcp_client_signaling_agent_register(client, agent); } /* create the profile and register it */ - mprofile = mrcp_client_profile_create(NULL, agent, connection_agent, media_engine, termination_factory, pool); + mprofile = mrcp_client_profile_create(NULL, agent, connection_agent, media_engine, termination_factory, rtp_settings, sig_settings, pool); if (mprofile) { mrcp_client_profile_register(client, mprofile, name); } @@ -4195,11 +4225,12 @@ static apt_log_priority_e str_to_log_level(const char *level) * Connects UniMRCP logging to FreeSWITCH * @return TRUE */ -static apt_bool_t unimrcp_log(const char *file, int line, const char *id, apt_log_priority_e priority, const char *format, va_list arg_ptr) +static apt_bool_t unimrcp_log(const char *file, int line, const char *obj, apt_log_priority_e priority, const char *format, va_list arg_ptr) { switch_log_level_t level; char log_message[4096] = { 0 }; /* same size as MAX_LOG_ENTRY_SIZE in UniMRCP apt_log.c */ size_t msglen; + const char *id = (obj == NULL) ? "" : ((speech_channel_t *)obj)->name; if (zstr(format)) { return TRUE; @@ -4237,10 +4268,10 @@ static apt_bool_t unimrcp_log(const char *file, int line, const char *id, apt_lo msglen = strlen(log_message); if (msglen >= 2 && log_message[msglen - 2] == '\\' && log_message[msglen - 1] == 'n') { /* log_message already ends in \n */ - switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, "", line, id, level, "%s", log_message); + switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, "", line, NULL, level, "(%s) %s", id, log_message); } else if (msglen > 0) { /* log message needs \n appended */ - switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, "", line, id, level, "%s\n", log_message); + switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, "", line, NULL, level, "(%s) %s\n", id, log_message); } return TRUE; -- 2.47.3