From a81d673f94b3d82899734bfb6c8d5625ba34dfce Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 20 Aug 2015 12:02:37 +0200 Subject: [PATCH] Added API to get the meta RTP transports + test to check we can append a RTP transport modifier on it --- .gitignore | 3 + coreapi/linphonecall.c | 40 ++++++++++++- coreapi/linphonecore.h | 38 +++++++++++- tester/call_tester.c | 132 ++++++++++++++++++++++++++++++++++++++++- 4 files changed, 210 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index be3581420..d662f5ade 100644 --- a/.gitignore +++ b/.gitignore @@ -90,3 +90,6 @@ tester/record-call_with_file_player.wav tester/ZIDCache*.xml tester/stereo-record.wav +coreapi/bellesip_sal/.dirstamp +coreapi/ldap/.dirstamp + diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 93670d2de..516617141 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2009,6 +2009,7 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ ms_free(cname); rtp_session_set_symmetric_rtp(audiostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc)); setup_dtls_params(call, &audiostream->ms); + media_stream_reclaim_sessions(&audiostream->ms, &call->sessions[0]); }else{ call->audiostream=audio_stream_new_with_sessions(&call->sessions[0]); } @@ -2108,8 +2109,8 @@ void linphone_call_init_video_stream(LinphoneCall *call){ video_stream_set_rtcp_information(call->videostream, cname, rtcp_tool); ms_free(cname); rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc)); - setup_dtls_params(call, &call->videostream->ms); + media_stream_reclaim_sessions(&call->videostream->ms, &call->sessions[1]); }else{ call->videostream=video_stream_new_with_sessions(&call->sessions[1]); } @@ -4143,3 +4144,40 @@ void linphone_call_set_audio_route(LinphoneCall *call, LinphoneAudioRoute route) audio_stream_set_audio_route(call->audiostream, (MSAudioRoute) route); } } + +int linphone_call_get_stream_count(LinphoneCall *call) { + // Revisit when multiple media streams will be implemented + return 2; +} + +MSFormatType linphone_call_get_stream_type(LinphoneCall *call, int stream_index) { + // Revisit when multiple media streams will be implemented + if (stream_index == 0) { + return MSAudio; + } + return MSVideo; +} + +RtpTransport* linphone_call_get_meta_rtp_transport(LinphoneCall *call, int stream_index) { + RtpTransport *meta_rtp; + RtpTransport *meta_rtcp; + + if (!call || stream_index < 0 || stream_index >= linphone_call_get_stream_count(call)) { + return NULL; + } + + rtp_session_get_transports(call->sessions[stream_index].rtp_session, &meta_rtp, &meta_rtcp); + return meta_rtp; +} + +RtpTransport* linphone_call_get_meta_rtcp_transport(LinphoneCall *call, int stream_index) { + RtpTransport *meta_rtp; + RtpTransport *meta_rtcp; + + if (!call || stream_index < 0 || stream_index >= linphone_call_get_stream_count(call)) { + return NULL; + } + + rtp_session_get_transports(call->sessions[stream_index].rtp_session, &meta_rtp, &meta_rtcp); + return meta_rtcp; +} \ No newline at end of file diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index c0d48b1f3..db795a295 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -898,7 +898,43 @@ typedef enum _LinphoneAudioRoute LinphoneAudioRoute; * * @ingroup call_control **/ -LINPHONE_PUBLIC void linphone_call_set_audio_route(LinphoneCall *call, LinphoneAudioRoute route); +LINPHONE_PUBLIC void linphone_call_set_audio_route(LinphoneCall *call, LinphoneAudioRoute route); + +/** + * Returns the number of stream for the given call. + * Currently there is only two (Audio, Video), but later there will be more. + * @param call + * + * @return 2 +**/ +LINPHONE_PUBLIC int linphone_call_get_stream_count(LinphoneCall *call); + +/** + * Returns the type of stream for the given stream index. + * @param call + * @param stream_index + * + * @return MsAudio if stream_index = 0, MsVideo otherwise +**/ +LINPHONE_PUBLIC MSFormatType linphone_call_get_stream_type(LinphoneCall *call, int stream_index); + +/** + * Returns the meta rtp transport for the given stream index. + * @param call + * @param stream_index + * + * @return a pointer to the meta rtp transport if it exists, NULL otherwise +**/ +LINPHONE_PUBLIC RtpTransport* linphone_call_get_meta_rtp_transport(LinphoneCall *call, int stream_index); + +/** + * Returns the meta rtcp transport for the given stream index. + * @param call + * @param stream_index + * + * @return a pointer to the meta rtcp transport if it exists, NULL otherwise +**/ +LINPHONE_PUBLIC RtpTransport* linphone_call_get_meta_rtcp_transport(LinphoneCall *call, int stream_index); /*keep this in sync with mediastreamer2/msvolume.h*/ diff --git a/tester/call_tester.c b/tester/call_tester.c index fbe81b2b6..6b3982a7d 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -33,6 +33,16 @@ #endif #endif +int static min(int a, int b) { + if (a < b) return a; + return b; +} + +int static max(int a, int b) { + if (a < b) return b; + return a; +} + static void srtp_call(void); static char *create_filepath(const char *dir, const char *filename, const char *ext); @@ -4430,6 +4440,125 @@ end: linphone_core_manager_destroy(pauline); } +typedef struct _RtpTransportModifierData { + int packetSentCount; + int packetReceivedCount; +} RtpTransportModifierData; + +static int rtptm_on_send(RtpTransportModifier *rtptm, mblk_t *msg) { + RtpTransportModifierData *data = rtptm->data; + data->packetSentCount += 1; + /* /!\ DO NOT RETURN 0 or the packet will never leave /!\ */ + return msgdsize(msg); +} + +static int rtptm_on_receive(RtpTransportModifier *rtptm, mblk_t *msg) { + RtpTransportModifierData *data = rtptm->data; + data->packetReceivedCount += 1; + return 0; +} + +static void rtptm_destroy(RtpTransportModifier *rtptm) { + // Do nothing, we'll free it later +} + +void static call_state_changed_4(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg){ + if (cstate == LinphoneCallIncomingReceived || cstate == LinphoneCallOutgoingProgress) { + RtpTransport *rtpt = NULL; + RtpTransportModifierData *data = ms_new0(RtpTransportModifierData, 1); + RtpTransportModifier *rtptm = ms_new0(RtpTransportModifier, 1); + + rtpt = linphone_call_get_meta_rtp_transport(call, 0); + rtptm->data = data; + rtptm->t_process_on_send = rtptm_on_send; + rtptm->t_process_on_receive = rtptm_on_receive; + rtptm->t_destroy = rtptm_destroy; + meta_rtp_transport_append_modifier(rtpt, rtptm); + call->user_data = rtptm; + } +} + +static void call_with_custom_rtp_modifier(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCall* call_pauline; + LinphoneCall* call_marie; + const rtp_stats_t * stats; + bool_t call_ok; + LinphoneCoreVTable * v_table; + RtpTransportModifier *rtptm_marie = NULL; + RtpTransportModifier *rtptm_pauline = NULL; + RtpTransportModifierData *data_marie = NULL; + RtpTransportModifierData *data_pauline = NULL; + + v_table = linphone_core_v_table_new(); + v_table->call_state_changed=call_state_changed_4; + linphone_core_add_listener(pauline->lc,v_table); + v_table = linphone_core_v_table_new(); + v_table->call_state_changed=call_state_changed_4; + linphone_core_add_listener(marie->lc,v_table); + + BC_ASSERT_TRUE((call_ok=call(pauline,marie))); + + if (!call_ok) goto end; + + wait_for_until(pauline->lc, marie->lc, NULL, 5, 3000); + + call_pauline = linphone_core_get_current_call(pauline->lc); + rtptm_pauline = (RtpTransportModifier *)call_pauline->user_data; + call_marie = linphone_core_get_current_call(marie->lc); + rtptm_marie = (RtpTransportModifier *)call_marie->user_data; + + linphone_core_pause_call(pauline->lc,call_pauline); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausing,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPaused,1)); + + /*stay in pause a little while in order to generate traffic*/ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000); + + linphone_core_resume_call(pauline->lc,call_pauline); + + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + /*same here: wait a while for a bit of a traffic, we need to receive a RTCP packet*/ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 5000); + + /*since RTCP streams are reset when call is paused/resumed, there should be no loss at all*/ + stats = rtp_session_get_stats(call_pauline->sessions->rtp_session); + BC_ASSERT_EQUAL(stats->cum_packet_loss, 0, int, "%d"); + + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + BC_ASSERT_PTR_NOT_NULL(rtptm_marie); + BC_ASSERT_PTR_NOT_NULL(rtptm_pauline); + data_marie = (RtpTransportModifierData *)rtptm_marie->data; + data_pauline = (RtpTransportModifierData *)rtptm_pauline->data; + + BC_ASSERT_PTR_NOT_NULL(data_marie); + BC_ASSERT_PTR_NOT_NULL(data_pauline); + ms_message("Marie sent %i RTP packets and received %i", data_marie->packetSentCount, data_marie->packetReceivedCount); + ms_message("Pauline sent %i RTP packets and received %i", data_pauline->packetSentCount, data_pauline->packetReceivedCount); + // There will be a few RTP packets sent on marie's side before the call is ended at pauline's request, so we need the threshold + BC_ASSERT_TRUE(max(data_pauline->packetReceivedCount, data_marie->packetSentCount) - min(data_pauline->packetReceivedCount, data_marie->packetSentCount) < 8); + BC_ASSERT_TRUE(data_marie->packetReceivedCount == data_pauline->packetSentCount); + +end: + if (data_pauline) { + ms_free(data_pauline); + } + ms_free(rtptm_pauline); + if (data_marie) { + ms_free(data_marie); + } + ms_free(rtptm_marie); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + test_t call_tests[] = { { "Early declined call", early_declined_call }, { "Call declined", call_declined }, @@ -4557,7 +4686,8 @@ test_t call_tests[] = { { "Simple mono call with opus", simple_mono_call_opus }, { "Call with FQDN in SDP", call_with_fqdn_in_sdp}, { "Call with RTP IO mode", call_with_rtp_io_mode }, - { "Call with generic NACK RTCP feedback", call_with_generic_nack_rtcp_feedback } + { "Call with generic NACK RTCP feedback", call_with_generic_nack_rtcp_feedback }, + { "Call with custom RTP Modifier", call_with_custom_rtp_modifier } }; test_suite_t call_test_suite = {