diff options
Diffstat (limited to 'tinyDAV/src/tdav_session_av.c')
-rwxr-xr-x | tinyDAV/src/tdav_session_av.c | 1308 |
1 files changed, 675 insertions, 633 deletions
diff --git a/tinyDAV/src/tdav_session_av.c b/tinyDAV/src/tdav_session_av.c index 8c15c18..3140100 100755 --- a/tinyDAV/src/tdav_session_av.c +++ b/tinyDAV/src/tdav_session_av.c @@ -88,34 +88,31 @@ static int _tdav_session_av_dtls_set_remote_setup(struct tdav_session_av_s* self #define SDP_DECLARE_TAG int32_t tag // [1 - *] #define SDP_TAG(self) ((self) ? *((int32_t*)(self)) : 0) -typedef enum RTP_PROFILE_E -{ +typedef enum RTP_PROFILE_E { RTP_PROFILE_NONE = 0x00, - + RTP_PROFILE_AVP = (1 << 0), RTP_PROFILE_AVPF = (1 << 1), - + RTP_PROFILE_SECURE = (1 << 2), RTP_PROFILE_SECURE_SDES = (RTP_PROFILE_SECURE | (1 << 3)), RTP_PROFILE_SECURE_DTLS = (RTP_PROFILE_SECURE | (1 << 4)), - + RTP_PROFILE_SAVP = (RTP_PROFILE_AVP | RTP_PROFILE_SECURE_SDES), RTP_PROFILE_SAVPF = (RTP_PROFILE_AVPF | RTP_PROFILE_SECURE_SDES), - + RTP_PROFILE_UDP_TLS_RTP_SAVP = (RTP_PROFILE_AVP | RTP_PROFILE_SECURE_DTLS), RTP_PROFILE_UDP_TLS_RTP_SAVPF = (RTP_PROFILE_AVPF | RTP_PROFILE_SECURE_DTLS) } RTP_PROFILE_T; -typedef struct RTP_PROFILE_XS -{ +typedef struct RTP_PROFILE_XS { enum RTP_PROFILE_E type; const char* name; } RTP_PROFILE_XT; -static const RTP_PROFILE_XT RTP_PROFILES[] = -{ +static const RTP_PROFILE_XT RTP_PROFILES[] = { { RTP_PROFILE_AVP, "RTP/AVP" }, { RTP_PROFILE_AVPF, "RTP/AVPF" }, { RTP_PROFILE_SAVP, "RTP/SAVP" }, @@ -125,8 +122,7 @@ static const RTP_PROFILE_XT RTP_PROFILES[] = }; #define RTP_PROFILES_COUNT (sizeof(RTP_PROFILES) / sizeof(RTP_PROFILES[0])) -typedef struct sdp_acap_xs -{ +typedef struct sdp_acap_xs { SDP_DECLARE_TAG; unsigned optional:1; // "e.g. [2]" unsigned or:1; // "e.g.|2" @@ -135,16 +131,14 @@ typedef struct sdp_acap_xs sdp_acap_xt; typedef sdp_acap_xt sdp_acaps_xt[SDP_CAPS_COUNT_MAX]; -typedef struct sdp_tcap_xs -{ +typedef struct sdp_tcap_xs { SDP_DECLARE_TAG; RTP_PROFILE_T profile; } sdp_tcap_xt; typedef sdp_tcap_xt sdp_tcaps_xt[SDP_CAPS_COUNT_MAX]; -typedef struct sdp_pcfg_xs -{ +typedef struct sdp_pcfg_xs { SDP_DECLARE_TAG; sdp_tcap_xt tcap; sdp_acaps_xt acaps; @@ -179,10 +173,9 @@ return i; \ return -1; \ } -typedef struct tdav_sdp_caps_s -{ +typedef struct tdav_sdp_caps_s { TSK_DECLARE_OBJECT; - + sdp_pcfgs_xt local; sdp_pcfgs_xt remote; sdp_acfg_xt acfg; @@ -211,8 +204,8 @@ int tdav_session_av_init(tdav_session_av_t* self, tmedia_type_t media_type) { uint64_t session_id; tmedia_session_t* base = TMEDIA_SESSION(self); - - if(!self){ + + if(!self) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } @@ -222,9 +215,9 @@ int tdav_session_av_init(tdav_session_av_t* self, tmedia_type_t media_type) return ret; } } - + /* base::init(): called by tmedia_session_create() */ - + self->media_type = media_type; self->media_profile = tmedia_defaults_get_profile(); self->use_rtcp = tmedia_defaults_get_rtcp_enabled(); @@ -241,9 +234,9 @@ int tdav_session_av_init(tdav_session_av_t* self, tmedia_type_t media_type) self->srtp_mode = (self->media_profile == tmedia_profile_rtcweb) ? tmedia_srtp_mode_mandatory : tmedia_defaults_get_srtp_mode(); self->use_srtp = (self->srtp_mode == tmedia_srtp_mode_mandatory); // if optional -> negotiate // remove DTLS-SRTP option if not supported - if((self->srtp_type & tmedia_srtp_type_dtls) && !tnet_dtls_is_srtp_supported()){ + if((self->srtp_type & tmedia_srtp_type_dtls) && !tnet_dtls_is_srtp_supported()) { TSK_DEBUG_WARN("DTLS-SRTP enabled but not supported. Please rebuild the code with this option enabled (requires OpenSSL 1.0.1+)"); - if(!(self->srtp_type &= ~tmedia_srtp_type_dtls)){ + if(!(self->srtp_type &= ~tmedia_srtp_type_dtls)) { // only DTLS-SRTP was enabled self->srtp_mode = tmedia_srtp_mode_none; self->use_srtp = tsk_false; @@ -251,77 +244,77 @@ int tdav_session_av_init(tdav_session_av_t* self, tmedia_type_t media_type) } //!\ DTLS-SRTP requires certificates but do not check right now as it could be defined later #endif - + tsk_safeobj_init(self); - + // session id if (!(session_id = TMEDIA_SESSION(self)->id)) { // set the session id if not already done TMEDIA_SESSION(self)->id = session_id = tmedia_session_get_unique_id(); } // consumer TSK_OBJECT_SAFE_FREE(self->consumer); - if (!(self->consumer = tmedia_consumer_create((self->media_type & tmedia_video || (self->media_type & tmedia_bfcp_video) == tmedia_bfcp_video) ? tmedia_video : tmedia_audio, session_id))){ // get an audio (or video) consumer and ignore "bfcp" part + if (!(self->consumer = tmedia_consumer_create((self->media_type & tmedia_video || (self->media_type & tmedia_bfcp_video) == tmedia_bfcp_video) ? tmedia_video : tmedia_audio, session_id))) { // get an audio (or video) consumer and ignore "bfcp" part TSK_DEBUG_ERROR("Failed to create consumer for media type = %d", self->media_type); } // producer TSK_OBJECT_SAFE_FREE(self->producer); - if (!(self->producer = tmedia_producer_create(self->media_type, session_id))){ + if (!(self->producer = tmedia_producer_create(self->media_type, session_id))) { TSK_DEBUG_ERROR("Failed to create producer for media type = %d", self->media_type); } - + // sdp caps TSK_OBJECT_SAFE_FREE(self->sdp_caps); if (!(self->sdp_caps = tdav_sdp_caps_create())) { TSK_DEBUG_ERROR("Failed to create SDP caps"); return -1; } - + // pt mapping (when bypassing is enabled) self->pt_map.local = self->pt_map.remote = self->pt_map.neg = -1; - + return 0; } tsk_bool_t tdav_session_av_set(tdav_session_av_t* self, const tmedia_param_t* param) { - if(!self){ + if(!self) { TSK_DEBUG_ERROR("Invalid parameter"); return tsk_false; } - + // try with base class first - if(tmedia_session_set_2(TMEDIA_SESSION(self), param)){ + if(tmedia_session_set_2(TMEDIA_SESSION(self), param)) { return tsk_true; } - - if(param->plugin_type == tmedia_ppt_consumer && self->consumer){ + + if(param->plugin_type == tmedia_ppt_consumer && self->consumer) { return (tmedia_consumer_set(self->consumer, param) == 0); } - else if(param->plugin_type == tmedia_ppt_producer && self->producer){ + else if(param->plugin_type == tmedia_ppt_producer && self->producer) { return (tmedia_producer_set(self->producer, param) == 0); } - else if(param->plugin_type == tmedia_ppt_session){ - if(param->value_type == tmedia_pvt_pchar){ - if(tsk_striequals(param->key, "remote-ip")){ - if(param->value){ + else if(param->plugin_type == tmedia_ppt_session) { + if(param->value_type == tmedia_pvt_pchar) { + if(tsk_striequals(param->key, "remote-ip")) { + if(param->value) { tsk_strupdate(&self->remote_ip, (const char*)param->value); return tsk_true; } } - else if(tsk_striequals(param->key, "local-ip")){ + else if(tsk_striequals(param->key, "local-ip")) { tsk_strupdate(&self->local_ip, (const char*)param->value); return tsk_true; } - else if(tsk_striequals(param->key, "local-ipver")){ + else if(tsk_striequals(param->key, "local-ipver")) { self->use_ipv6 = tsk_striequals(param->value, "ipv6"); return tsk_true; } } - else if(param->value_type == tmedia_pvt_int32){ - if(tsk_striequals(param->key, "srtp-mode")){ + else if(param->value_type == tmedia_pvt_int32) { + if(tsk_striequals(param->key, "srtp-mode")) { #if HAVE_SRTP self->srtp_mode = (tmedia_srtp_mode_t)TSK_TO_INT32((uint8_t*)param->value); - if(self->rtp_manager){ + if(self->rtp_manager) { trtp_manager_set_srtp_type_local(self->rtp_manager, self->srtp_type, self->srtp_mode); } #else @@ -329,26 +322,26 @@ tsk_bool_t tdav_session_av_set(tdav_session_av_t* self, const tmedia_param_t* pa #endif /* HAVE_SRTP */ return tsk_true; } - else if(tsk_striequals(param->key, "rtp-ssrc")){ + else if(tsk_striequals(param->key, "rtp-ssrc")) { self->rtp_ssrc = *((uint32_t*)param->value); - if(self->rtp_manager && self->rtp_ssrc){ + if(self->rtp_manager && self->rtp_ssrc) { self->rtp_manager->rtp.ssrc.local = self->rtp_ssrc; } return tsk_true; } - else if(tsk_striequals(param->key, "rtcp-enabled")){ + else if(tsk_striequals(param->key, "rtcp-enabled")) { self->use_rtcp = (TSK_TO_INT32((uint8_t*)param->value) != 0); return tsk_true; } - else if(tsk_striequals(param->key, "rtcpmux-enabled")){ + else if(tsk_striequals(param->key, "rtcpmux-enabled")) { self->use_rtcpmux = (TSK_TO_INT32((uint8_t*)param->value) != 0); return tsk_true; } - else if(tsk_striequals(param->key, "avpf-mode")){ + else if(tsk_striequals(param->key, "avpf-mode")) { self->avpf_mode_set = (tmedia_mode_t)TSK_TO_INT32((uint8_t*)param->value); return tsk_true; } - else if(tsk_striequals(param->key, "webrtc2sip-mode-enabled")){ + else if(tsk_striequals(param->key, "webrtc2sip-mode-enabled")) { self->is_webrtc2sip_mode_enabled = (TSK_TO_INT32((uint8_t*)param->value) != 0); return tsk_true; } @@ -369,44 +362,44 @@ tsk_bool_t tdav_session_av_set(tdav_session_av_t* self, const tmedia_param_t* pa return tsk_true; } } - else if(param->value_type == tmedia_pvt_pobject){ - if(tsk_striequals(param->key, "natt-ctx")){ + else if(param->value_type == tmedia_pvt_pobject) { + if(tsk_striequals(param->key, "natt-ctx")) { TSK_OBJECT_SAFE_FREE(self->natt_ctx); self->natt_ctx = tsk_object_ref(param->value); return tsk_true; } - else if(tsk_striequals(param->key, "ice-ctx")){ + else if(tsk_striequals(param->key, "ice-ctx")) { TSK_OBJECT_SAFE_FREE(self->ice_ctx); self->ice_ctx = tsk_object_ref(param->value); - if(self->rtp_manager){ + if(self->rtp_manager) { trtp_manager_set_ice_ctx(self->rtp_manager, self->ice_ctx); } return tsk_true; } - else if(tsk_striequals(param->key, "remote-sdp-message")){ + else if(tsk_striequals(param->key, "remote-sdp-message")) { TSK_OBJECT_SAFE_FREE(self->remote_sdp); self->remote_sdp = (struct tsdp_message_s*)tsk_object_ref(param->value); return tsk_true; } - else if(tsk_striequals(param->key, "local-sdp-message")){ + else if(tsk_striequals(param->key, "local-sdp-message")) { TSK_OBJECT_SAFE_FREE(self->local_sdp); self->local_sdp = (struct tsdp_message_s*)tsk_object_ref(param->value); return tsk_true; } } } - + return tsk_false; } tsk_bool_t tdav_session_av_get(tdav_session_av_t* self, tmedia_param_t* param) { - if(!self || !param){ + if(!self || !param) { TSK_DEBUG_ERROR("Invalid parameter"); return tsk_false; } - - if (param->plugin_type == tmedia_ppt_session){ + + if (param->plugin_type == tmedia_ppt_session) { if (param->value_type == tmedia_pvt_int32) { if (tsk_striequals(param->key, "codecs-negotiated")) { // negotiated codecs tmedia_codecs_L_t* neg_codecs = tsk_object_ref(TMEDIA_SESSION(self)->neg_codecs); @@ -439,7 +432,7 @@ tsk_bool_t tdav_session_av_get(tdav_session_av_t* self, tmedia_param_t* param) } } } - + return tsk_false; } @@ -458,12 +451,17 @@ int tdav_session_av_init_encoder(tdav_session_av_t* self, struct tmedia_codec_s* } if (self->pref_size != video->pref_size) { unsigned width, height; - if (tmedia_video_get_size(self->pref_size, &width, &height) == 0){ + if (tmedia_video_get_size(self->pref_size, &width, &height) == 0) { video->pref_size = self->pref_size; video->out.width = width; video->out.height = height; } } + // QoS metrics default values + TMEDIA_SESSION(self)->qos_metrics.video_out_width = video->out.width; + TMEDIA_SESSION(self)->qos_metrics.video_out_height = video->out.height; + TMEDIA_SESSION(self)->qos_metrics.video_in_width = video->in.width; + TMEDIA_SESSION(self)->qos_metrics.video_in_height = video->in.height; } return 0; } @@ -471,12 +469,12 @@ int tdav_session_av_init_encoder(tdav_session_av_t* self, struct tmedia_codec_s* int tdav_session_av_prepare(tdav_session_av_t* self) { int ret = 0; - - if(!self){ + + if(!self) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - + /* SRTPType */ #if HAVE_SRTP // Now that SSL certs are defined update SRTPType before creating the RTP manager @@ -484,11 +482,11 @@ int tdav_session_av_prepare(tdav_session_av_t* self) self->srtp_type = tsk_strnullORempty(TMEDIA_SESSION(self)->dtls.file_pbk) ? tmedia_srtp_type_sdes : tmedia_srtp_type_dtls; } #endif - + /* set local port */ - if (!self->rtp_manager){ + if (!self->rtp_manager) { self->rtp_manager = self->ice_ctx ? trtp_manager_create_2(self->ice_ctx, self->srtp_type, self->srtp_mode) - : trtp_manager_create(self->use_rtcp, self->local_ip, self->use_ipv6, self->srtp_type, self->srtp_mode); + : trtp_manager_create(self->use_rtcp, self->local_ip, self->use_ipv6, self->srtp_type, self->srtp_mode); } if (self->rtp_manager) { const char *webproxy_type = tsk_null, *webproxy_host = tsk_null, *webproxy_login = tsk_null, *webproxy_password = tsk_null; @@ -502,17 +500,17 @@ int tdav_session_av_prepare(tdav_session_av_t* self) return ret; } if ((ret = tmedia_defaults_get_webproxy_info(&webproxy_type, &webproxy_host, &webproxy_port, &webproxy_login, &webproxy_password))) { - + } if ((ret = trtp_manager_set_proxy_info(self->rtp_manager, tnet_proxy_type_from_string(webproxy_type), webproxy_host, webproxy_port, webproxy_login, webproxy_password))) { } - + #if HAVE_SRTP if (tsk_strnullORempty(TMEDIA_SESSION(self)->dtls.file_pbk)) { // DTLS-SRTP requires certificates - if(self->srtp_type & tmedia_srtp_type_dtls){ + if(self->srtp_type & tmedia_srtp_type_dtls) { TSK_DEBUG_WARN("DTLS-SRTP requested but no SSL certificates provided, disabling this option :("); - if(!(self->srtp_type &= ~tmedia_srtp_type_dtls)){ + if(!(self->srtp_type &= ~tmedia_srtp_type_dtls)) { // only DTLS-SRTP was enabled self->srtp_mode = tmedia_srtp_mode_none; self->use_srtp = tsk_false; @@ -521,55 +519,55 @@ int tdav_session_av_prepare(tdav_session_av_t* self) } } } - - if ((self->srtp_type & tmedia_srtp_type_dtls) && (self->srtp_mode == tmedia_srtp_mode_optional || self->srtp_mode == tmedia_srtp_mode_mandatory)){ - if((ret = trtp_manager_set_dtls_certs(self->rtp_manager, TMEDIA_SESSION(self)->dtls.file_ca, TMEDIA_SESSION(self)->dtls.file_pbk, TMEDIA_SESSION(self)->dtls.file_pvk, TMEDIA_SESSION(self)->dtls.verify))){ + + if ((self->srtp_type & tmedia_srtp_type_dtls) && (self->srtp_mode == tmedia_srtp_mode_optional || self->srtp_mode == tmedia_srtp_mode_mandatory)) { + if((ret = trtp_manager_set_dtls_certs(self->rtp_manager, TMEDIA_SESSION(self)->dtls.file_ca, TMEDIA_SESSION(self)->dtls.file_pbk, TMEDIA_SESSION(self)->dtls.file_pvk, TMEDIA_SESSION(self)->dtls.verify))) { return ret; } } #endif /* HAVE_SRTP */ - if((ret = trtp_manager_prepare(self->rtp_manager))){ + if((ret = trtp_manager_prepare(self->rtp_manager))) { return ret; } - if(self->natt_ctx){ - if((ret = trtp_manager_set_natt_ctx(self->rtp_manager, self->natt_ctx))){ + if(self->natt_ctx) { + if((ret = trtp_manager_set_natt_ctx(self->rtp_manager, self->natt_ctx))) { return ret; } } - if(self->rtp_ssrc){ + if(self->rtp_ssrc) { self->rtp_manager->rtp.ssrc.local = self->rtp_ssrc; } } - - + + /* SRTP */ #if HAVE_SRTP { - + } #endif - + /* Consumer will be prepared in tdav_session_audio_start() */ /* Producer will be prepared in tdav_session_audio_start() */ - + return ret; } int tdav_session_av_start(tdav_session_av_t* self, const tmedia_codec_t* best_codec) { int ret; - if(!self || !best_codec){ + if(!self || !best_codec) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - + // RED codec TSK_OBJECT_SAFE_FREE(self->red.codec); self->red.payload_type = 0; - if((self->red.codec = tsk_object_ref((tsk_object_t*)tdav_session_av_get_red_codec(self)))){ + if((self->red.codec = tsk_object_ref((tsk_object_t*)tdav_session_av_get_red_codec(self)))) { self->red.payload_type = atoi(self->red.codec->neg_format); - if(!TMEDIA_CODEC(self->red.codec)->opened){ - if((ret = tmedia_codec_open(self->red.codec))){ + if(!TMEDIA_CODEC(self->red.codec)->opened) { + if((ret = tmedia_codec_open(self->red.codec))) { TSK_DEBUG_ERROR("Failed to open [%s] codec", self->red.codec->plugin->desc); return ret; } @@ -577,59 +575,64 @@ int tdav_session_av_start(tdav_session_av_t* self, const tmedia_codec_t* best_co // set RED callback (unencapsulated data) ret = tdav_codec_red_set_callback((struct tdav_codec_red_s*)self->red.codec, _tdav_session_av_red_cb, self); } - + // ULPFEC TSK_OBJECT_SAFE_FREE(self->ulpfec.codec); self->ulpfec.payload_type = 0; - if((self->ulpfec.codec = tsk_object_ref((tsk_object_t*)tdav_session_av_get_ulpfec_codec(self)))){ + if((self->ulpfec.codec = tsk_object_ref((tsk_object_t*)tdav_session_av_get_ulpfec_codec(self)))) { self->ulpfec.payload_type = atoi(self->ulpfec.codec->neg_format); - if(!TMEDIA_CODEC(self->ulpfec.codec)->opened){ - if((ret = tmedia_codec_open(self->ulpfec.codec))){ + if(!TMEDIA_CODEC(self->ulpfec.codec)->opened) { + if((ret = tmedia_codec_open(self->ulpfec.codec))) { TSK_DEBUG_ERROR("Failed to open [%s] codec", self->ulpfec.codec->plugin->desc); return ret; } } } - // Check if "RTCP-NACK", "RTC-FIR", "RTCP-GOOG-REMB".... are supported by the selected encoder - self->is_fb_fir_neg = self->is_fb_nack_neg = self->is_fb_googremb_neg = tsk_false; - if (TMEDIA_SESSION(self)->M.ro) { - // a=rtcp-fb:* ccm fir - // a=rtcp-fb:* nack - // a=rtcp-fb:* goog-remb - char attr_fir[256], attr_nack[256], attr_goog_remb[256]; - int index = 0; - const tsdp_header_A_t* A; - - sprintf(attr_fir, "%s ccm fir", best_codec->neg_format); - sprintf(attr_nack, "%s nack", best_codec->neg_format); - sprintf(attr_goog_remb, "%s goog-remb", best_codec->neg_format); - - while ((A = tsdp_header_M_findA_at(TMEDIA_SESSION(self)->M.ro, "rtcp-fb", index++))) { - if (!self->is_fb_fir_neg) { - self->is_fb_fir_neg = (tsk_striequals(A->value, "* ccm fir") || tsk_striequals(A->value, attr_fir)); - } - if (!self->is_fb_nack_neg) { - self->is_fb_nack_neg = (tsk_striequals(A->value, "* nack") || tsk_striequals(A->value, attr_nack)); - } - if (!self->is_fb_googremb_neg) { - self->is_fb_googremb_neg = (tsk_striequals(A->value, "* goog-remb") || tsk_striequals(A->value, attr_goog_remb)); - } - } - } - + // Check if "RTCP-NACK", "RTC-FIR", "RTCP-GOOG-REMB", "RTCP-DOUBS-JCNG".... are supported by the selected encoder + self->is_fb_fir_neg = self->is_fb_nack_neg = self->is_fb_googremb_neg = self->is_fb_doubsjcng_neg = tsk_false; + if (TMEDIA_SESSION(self)->M.ro) { + // a=rtcp-fb:* ccm fir + // a=rtcp-fb:* nack + // a=rtcp-fb:* goog-remb + // a=rtcp-fb:* doubs-jcng + char attr_fir[256], attr_nack[256], attr_goog_remb[256], attr_doubs_jcng[256]; + int index = 0; + const tsdp_header_A_t* A; + + sprintf(attr_fir, "%s ccm fir", best_codec->neg_format); + sprintf(attr_nack, "%s nack", best_codec->neg_format); + sprintf(attr_goog_remb, "%s goog-remb", best_codec->neg_format); + sprintf(attr_doubs_jcng, "%s doubs-jcng", best_codec->neg_format); + + while ((A = tsdp_header_M_findA_at(TMEDIA_SESSION(self)->M.ro, "rtcp-fb", index++))) { + if (!self->is_fb_fir_neg) { + self->is_fb_fir_neg = (tsk_striequals(A->value, "* ccm fir") || tsk_striequals(A->value, attr_fir)); + } + if (!self->is_fb_nack_neg) { + self->is_fb_nack_neg = (tsk_striequals(A->value, "* nack") || tsk_striequals(A->value, attr_nack)); + } + if (!self->is_fb_googremb_neg) { + self->is_fb_googremb_neg = (tsk_striequals(A->value, "* goog-remb") || tsk_striequals(A->value, attr_goog_remb)); + } + if (!self->is_fb_doubsjcng_neg) { + self->is_fb_doubsjcng_neg = (tsk_striequals(A->value, "* doubs-jcng") || tsk_striequals(A->value, attr_doubs_jcng)); + } + } + } + if (self->rtp_manager) { int ret; tmedia_param_t* media_param = tsk_null; static const int32_t __ByPassIsYes = 1; static const int32_t __ByPassIsNo = 0; /* RTP/RTCP manager: use latest information. */ - + // set callbacks #if HAVE_SRTP ret = trtp_manager_set_dtls_callback(self->rtp_manager, self, _tdav_session_av_srtp_dtls_cb); #endif /* HAVE_SRTP */ - + // network information will be updated when the RTP manager starts if ICE is enabled ret = trtp_manager_set_rtp_remote(self->rtp_manager, self->remote_ip, self->remote_port); self->rtp_manager->use_rtcpmux = self->use_rtcpmux; @@ -637,30 +640,33 @@ int tdav_session_av_start(tdav_session_av_t* self, const tmedia_codec_t* best_co { int32_t bandwidth_max_upload_kbps = self->bandwidth_max_upload_kbps; int32_t bandwidth_max_download_kbps = self->bandwidth_max_download_kbps; - if((self->media_type & tmedia_video || (self->media_type & tmedia_bfcp_video) == tmedia_bfcp_video)){ - if(self->congestion_ctrl_enabled){ + if ((self->media_type & tmedia_video || (self->media_type & tmedia_bfcp_video) == tmedia_bfcp_video)) { + if (self->congestion_ctrl_enabled) { const tmedia_codec_t* best_codec = tdav_session_av_get_best_neg_codec(self); // use for encoding for sure and probably for decoding - if(TDAV_IS_VIDEO_CODEC(best_codec)){ + if (TDAV_IS_VIDEO_CODEC(best_codec)) { // the up bandwidth will be updated once the decode the first frame as the current values (width, height, fps) are not really correct and based on the SDP negotiation bandwidth_max_download_kbps = TSK_MIN( - tmedia_get_video_bandwidth_kbps_2(TMEDIA_CODEC_VIDEO(best_codec)->in.width, TMEDIA_CODEC_VIDEO(best_codec)->in.height, TMEDIA_CODEC_VIDEO(best_codec)->in.fps), - bandwidth_max_download_kbps); + tmedia_get_video_bandwidth_kbps_2(TMEDIA_CODEC_VIDEO(best_codec)->in.width, TMEDIA_CODEC_VIDEO(best_codec)->in.height, TMEDIA_CODEC_VIDEO(best_codec)->in.fps), + bandwidth_max_download_kbps); bandwidth_max_upload_kbps = TSK_MIN( - tmedia_get_video_bandwidth_kbps_2(TMEDIA_CODEC_VIDEO(best_codec)->out.width, TMEDIA_CODEC_VIDEO(best_codec)->out.height, TMEDIA_CODEC_VIDEO(best_codec)->out.fps), - bandwidth_max_upload_kbps); + tmedia_get_video_bandwidth_kbps_2(TMEDIA_CODEC_VIDEO(best_codec)->out.width, TMEDIA_CODEC_VIDEO(best_codec)->out.height, TMEDIA_CODEC_VIDEO(best_codec)->out.fps), + bandwidth_max_upload_kbps); } - else if((self->media_type & tmedia_video || (self->media_type & tmedia_bfcp_video) == tmedia_bfcp_video)){ + else if ((self->media_type & tmedia_video || (self->media_type & tmedia_bfcp_video) == tmedia_bfcp_video)) { bandwidth_max_download_kbps = TSK_MIN(tmedia_get_video_bandwidth_kbps_3(), bandwidth_max_download_kbps); bandwidth_max_upload_kbps = TSK_MIN(tmedia_get_video_bandwidth_kbps_3(), bandwidth_max_upload_kbps); } } + else { + TSK_DEBUG_WARN("Video congestion control not enabled"); + } } - + TSK_DEBUG_INFO("max_bw_up=%d kpbs, max_bw_down=%d kpbs, congestion_ctrl_enabled=%d, media_type=%d", bandwidth_max_upload_kbps, bandwidth_max_download_kbps, self->congestion_ctrl_enabled, self->media_type); // forward up/down bandwidth info to rctp session (used in RTCP-REMB) - ret = trtp_manager_set_app_bandwidth_max(self->rtp_manager, bandwidth_max_upload_kbps, bandwidth_max_download_kbps); + ret = trtp_manager_set_app_bw_and_jcng(self->rtp_manager, bandwidth_max_upload_kbps, bandwidth_max_download_kbps, 1.f /*jcng_q*/); } - + // because of AudioUnit under iOS => prepare both consumer and producer then start() at the same time /* prepare consumer and producer */ // Producer could output encoded frames: @@ -697,35 +703,39 @@ int tdav_session_av_start(tdav_session_av_t* self, const tmedia_codec_t* best_co } } } - + // Start RTP manager ret = trtp_manager_start(self->rtp_manager); - + #if HAVE_SRTP self->use_srtp = trtp_manager_is_srtp_activated(self->rtp_manager); - + /* start consumer and producer */ if (trtp_manager_is_dtls_activated(self->rtp_manager) && !trtp_manager_is_dtls_started(self->rtp_manager)) { // delay starting util DTLS-SRTP negotiation terminates (handshaking succeed) TSK_DEBUG_INFO("Delaying consumer/producer starting until DTLS-SRTP negotiation complete"); } - else{ + else { #endif /* HAVE_SRTP */ tsk_safeobj_lock(self); - if (self->consumer && !self->consumer->is_started) ret = tmedia_consumer_start(self->consumer); - if (self->producer && !self->producer->is_started) ret = tmedia_producer_start(self->producer); + if (self->consumer && !self->consumer->is_started) { + ret = tmedia_consumer_start(self->consumer); + } + if (self->producer && !self->producer->is_started) { + ret = tmedia_producer_start(self->producer); + } tsk_safeobj_unlock(self); #if HAVE_SRTP } #endif /* HAVE_SRTP */ - + return ret; } else { TSK_DEBUG_ERROR("Invalid RTP/RTCP manager"); return -3; } - + return 0; } @@ -734,61 +744,61 @@ int tdav_session_av_stop(tdav_session_av_t* self) tmedia_codec_t* codec; tsk_list_item_t* item; int ret = 0; - - if(!self){ + + if(!self) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - + /* stop Producer */ if (self->producer) { ret = tmedia_producer_stop(self->producer); } - + /* stop RTP/RTCP manager */ if (self->rtp_manager) { ret = trtp_manager_stop(self->rtp_manager); } - + /* stop Consumer (after RTP manager to silently discard in coming packets) */ if (self->consumer) { ret = tmedia_consumer_stop(self->consumer); } - + /* close codecs to force open() for next start (e.g SIP UPDATE with SDP) */ - if(TMEDIA_SESSION(self)->neg_codecs){ - tsk_list_foreach(item, TMEDIA_SESSION(self)->neg_codecs){ - if(!(codec = TMEDIA_CODEC(item->data))){ + if(TMEDIA_SESSION(self)->neg_codecs) { + tsk_list_foreach(item, TMEDIA_SESSION(self)->neg_codecs) { + if(!(codec = TMEDIA_CODEC(item->data))) { continue; } ret = tmedia_codec_close(codec); } } - + self->bytes_in.count_last_time = self->bytes_out.count_last_time = 0; self->bytes_in.count = self->bytes_out.count = 0; - + return ret; } int tdav_session_av_pause(tdav_session_av_t* self) { int ret = 0; - - if(!self){ + + if(!self) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - + /* Consumer */ - if(self->consumer){ + if(self->consumer) { ret = tmedia_consumer_pause(self->consumer); } /* Producer */ - if(self->producer){ + if(self->producer) { ret = tmedia_producer_pause(self->producer); } - + return ret; } @@ -807,38 +817,37 @@ const tsdp_header_M_t* tdav_session_av_get_lo(tdav_session_av_t* self, tsk_bool_ tsk_bool_t is_srtp_local_mandatory = is_srtp_enable && (self->srtp_mode == tmedia_srtp_mode_mandatory); tsk_bool_t is_bfcp_session = ((base->type & tmedia_bfcp) == tmedia_bfcp) ? tsk_true : tsk_false; tsk_bool_t is_first_media; - - if(!base || !base->plugin || !updated){ + + if(!base || !base->plugin || !updated) { TSK_DEBUG_ERROR("Invalid parameter"); return tsk_null; } - + *updated = tsk_false; - - if(!self->rtp_manager || (!self->ice_ctx && !self->rtp_manager->transport)){ - if(self->rtp_manager && (!self->ice_ctx && !self->rtp_manager->transport)){ // reINVITE or UPDATE (manager was destroyed when stoppped) - if(trtp_manager_prepare(self->rtp_manager)){ + + if(!self->rtp_manager || (!self->ice_ctx && !self->rtp_manager->transport)) { + if(self->rtp_manager && (!self->ice_ctx && !self->rtp_manager->transport)) { // reINVITE or UPDATE (manager was destroyed when stoppped) + if(trtp_manager_prepare(self->rtp_manager)) { TSK_DEBUG_ERROR("Failed to prepare transport"); return tsk_null; } } - else{ + else { TSK_DEBUG_ERROR("RTP/RTCP manager in invalid"); return tsk_null; } } - + // only first media will add session-level attributes (e.g. DTLS setup and fingerprint) - if((is_first_media = !!self->local_sdp)){ + if((is_first_media = !!self->local_sdp)) { const tsdp_header_M_t* firstM = (const tsdp_header_M_t*)tsdp_message_get_headerAt(self->local_sdp, tsdp_htype_M, 0); - if(!(is_first_media = !firstM)){ + if(!(is_first_media = !firstM)) { is_first_media = tsk_striequals(TMEDIA_SESSION(self)->plugin->media, firstM->media); } } - - if(base->ro_changed && base->M.lo){ - static const char* __fields[] = - { + + if(base->ro_changed && base->M.lo) { + static const char* __fields[] = { /* Codecs */ "fmtp", "rtpmap", "imageattr", /* QoS */ @@ -858,18 +867,18 @@ const tsdp_header_M_t* tdav_session_av_get_lo(tdav_session_av_t* self, tsk_bool_ tsdp_header_A_removeAll_by_fields(base->M.lo->Attributes, __fields, sizeof(__fields)/sizeof(__fields[0])); tsk_list_clear_items(base->M.lo->FMTs); // remove session-level attributes - if(is_first_media){ + if(is_first_media) { // headers: contains all kind of headers but this is a smart function :) tsdp_header_A_removeAll_by_fields((tsdp_headers_A_L_t*)self->local_sdp->headers, __fields, sizeof(__fields)/sizeof(__fields[0])); } } - + *updated = (base->ro_changed || !base->M.lo); - - if(!base->M.lo){ - if((base->M.lo = tsdp_header_M_create(base->plugin->media, self->rtp_manager->rtp.public_port, "RTP/AVP"))){ + + if(!base->M.lo) { + if((base->M.lo = tsdp_header_M_create(base->plugin->media, self->rtp_manager->rtp.public_port, "RTP/AVP"))) { /* If NATT is active, do not rely on the global IP address Connection line */ - if(self->natt_ctx){ + if(self->natt_ctx) { tsdp_header_M_add_headers(base->M.lo, TSDP_HEADER_C_VA_ARGS("IN", self->use_ipv6 ? "IP6" : "IP4", self->rtp_manager->rtp.public_ip), tsk_null); @@ -880,14 +889,14 @@ const tsdp_header_M_t* tdav_session_av_get_lo(tdav_session_av_t* self, tsk_bool_ transmit at the specified packetization rate. If a UE receives an "audio" media line which does not have "a=ptime" specified or the UE does not support the "a=ptime" attribute, the UE should transmit at the default codec packetization rate as defined in RFC 3551 [55A]. The UE will transmit consistent with the resources available from the network. - + For "video" and "audio" media types that utilize the RTP/RTCP, the UE shall specify the proposed bandwidth for each media stream utilizing the "b=" media descriptor and the "AS" bandwidth modifier in the SDP. - + The UE shall include the MIME subtype "telephone-event" in the "m=" media descriptor in the SDP for audio media flows that support both audio codec and DTMF payloads in RTP packets as described in RFC 4733 [23]. */ - if(self->media_type & tmedia_audio){ + if(self->media_type & tmedia_audio) { tsk_istr_t ptime; tsk_itoa(tmedia_defaults_get_audio_ptime(), &ptime); tsdp_header_M_add_headers(base->M.lo, @@ -899,7 +908,7 @@ const tsdp_header_M_t* tdav_session_av_get_lo(tdav_session_av_t* self, tsk_bool_ tsk_null); // the "telephone-event" fmt/rtpmap is added below } - else if((self->media_type & tmedia_video || (self->media_type & tmedia_bfcp_video) == tmedia_bfcp_video)){ + else if((self->media_type & tmedia_video || (self->media_type & tmedia_bfcp_video) == tmedia_bfcp_video)) { tsk_istr_t session_id; // https://code.google.com/p/webrtc2sip/issues/detail?id=81 // goog-remb: https://groups.google.com/group/discuss-webrtc/browse_thread/thread/c61ad3487e2acd52 @@ -908,6 +917,7 @@ const tsdp_header_M_t* tdav_session_av_get_lo(tdav_session_av_t* self, tsk_bool_ TSDP_HEADER_A_VA_ARGS("rtcp-fb", "* ccm fir"), TSDP_HEADER_A_VA_ARGS("rtcp-fb", "* nack"), TSDP_HEADER_A_VA_ARGS("rtcp-fb", "* goog-remb"), + TSDP_HEADER_A_VA_ARGS("rtcp-fb", "* doubs-jcng"), tsk_null); // https://tools.ietf.org/html/rfc4574 // http://tools.ietf.org/html/rfc4796 @@ -918,7 +928,7 @@ const tsdp_header_M_t* tdav_session_av_get_lo(tdav_session_av_t* self, tsk_bool_ tsk_null); // http://tools.ietf.org/html/rfc3556 // https://tools.ietf.org/html/rfc3890 - if(self->bandwidth_max_download_kbps > 0 && self->bandwidth_max_download_kbps != INT_MAX){ // INT_MAX or <=0 means undefined + if(self->bandwidth_max_download_kbps > 0 && self->bandwidth_max_download_kbps != INT_MAX) { // INT_MAX or <=0 means undefined tsdp_header_M_add_headers(base->M.lo, TSDP_HEADER_B_VA_ARGS("AS", self->bandwidth_max_download_kbps), TSDP_HEADER_B_VA_ARGS("TIAS", (self->bandwidth_max_download_kbps << 10)), @@ -926,48 +936,49 @@ const tsdp_header_M_t* tdav_session_av_get_lo(tdav_session_av_t* self, tsk_bool_ } } } - else{ + else { TSK_DEBUG_ERROR("Failed to create lo"); return tsk_null; } } - - if(*updated){ + + if(*updated) { tmedia_codecs_L_t* neg_codecs = tsk_null; - - if(base->M.ro){ + + if(base->M.ro) { TSK_OBJECT_SAFE_FREE(base->neg_codecs); /* update negociated codecs */ - if((neg_codecs = tmedia_session_match_codec(base, base->M.ro))){ + if((neg_codecs = tmedia_session_match_codec(base, base->M.ro))) { base->neg_codecs = neg_codecs; } /* from codecs to sdp */ - if(TSK_LIST_IS_EMPTY(base->neg_codecs) || ((base->neg_codecs->tail == base->neg_codecs->head) && TDAV_IS_DTMF_CODEC(TSK_LIST_FIRST_DATA(base->neg_codecs)))){ + if(TSK_LIST_IS_EMPTY(base->neg_codecs) || ((base->neg_codecs->tail == base->neg_codecs->head) && TDAV_IS_DTMF_CODEC(TSK_LIST_FIRST_DATA(base->neg_codecs)))) { base->M.lo->port = 0; /* Keep the RTP transport and reuse it when we receive a reINVITE or UPDATE request */ // To reject an offered stream, the port number in the corresponding stream in the answer // MUST be set to zero. Any media formats listed are ignored. AT LEAST ONE MUST BE PRESENT, AS SPECIFIED BY SDP. tsk_strupdate(&base->M.lo->proto, base->M.ro->proto); - if(base->M.ro->FMTs){ + if(base->M.ro->FMTs) { tsk_list_pushback_list(base->M.lo->FMTs, base->M.ro->FMTs); } TSK_DEBUG_INFO("No codec matching for media type = %d", (int32_t)self->media_type); goto DONE; } - else{ + else { tmedia_codec_to_sdp(base->neg_codecs, base->M.lo); } } - else{ + else { /* from codecs to sdp */ tmedia_codec_to_sdp(base->codecs, base->M.lo); } - + /* SRTP */ #if HAVE_SRTP - { //start-of-HAVE_SRTP - + { + //start-of-HAVE_SRTP + /* DTLS-SRTP default values */ - if(is_srtp_dtls_enabled){ + if(is_srtp_dtls_enabled) { /* "setup" and "connection" */ if (self->dtls.local.setup == tnet_dtls_setup_none || self->dtls.local.setup == tnet_dtls_setup_actpass) { // if setup already negotiated then, use the same // rfc5763: the caller is server by default @@ -978,8 +989,8 @@ const tsdp_header_M_t* tdav_session_av_get_lo(tdav_session_av_t* self, tsk_bool_ trtp_manager_set_dtls_local_setup(self->rtp_manager, self->dtls.local.setup, self->dtls.local.connection_new); } } - - if(!base->M.ro){ + + if(!base->M.ro) { // === RO IS NULL === const trtp_srtp_ctx_xt *srtp_ctxs[SRTP_CRYPTO_TYPES_MAX] = { tsk_null }; tsk_size_t ctx_count = 0, ctx_idx, acap_tag = 1; @@ -991,14 +1002,14 @@ const tsdp_header_M_t* tdav_session_av_get_lo(tdav_session_av_t* self, tsk_bool_ tsk_bool_t is_srtp_remote_mandatory = (base->M.ro && _sdp_str_contains(base->M.ro->proto, "SAVP")); tsk_size_t profiles_index = 0; RTP_PROFILE_T profiles[RTP_PROFILES_COUNT] = { RTP_PROFILE_NONE }; - + // get local SRTP context - if(is_srtp_sdes_enabled){ + if(is_srtp_sdes_enabled) { ctx_count = trtp_srtp_get_local_contexts(self->rtp_manager, (const trtp_srtp_ctx_xt **)&srtp_ctxs, sizeof(srtp_ctxs)/sizeof(srtp_ctxs[0])); } - + // a=tcap: - if((negotiate_srtp || negotiate_avpf)){ + if((negotiate_srtp || negotiate_avpf)) { static const int32_t __tcap_tag = 1; char* tcap = tsk_null; const char* fp_sha1 = tsk_null; @@ -1007,35 +1018,35 @@ const tsdp_header_M_t* tdav_session_av_get_lo(tdav_session_av_t* self, tsk_bool_ #define _first_media_strcat(ppstr, format, ...) if(is_first_media) tsk_strcat_2((ppstr), (format), ##__VA_ARGS__) #define _first_media_sprintf(ppstr, format, ...) if(is_first_media) tsk_sprintf((ppstr), (format), ##__VA_ARGS__) #define _first_media_add_headers(sdp, ...) if(is_first_media) tsdp_message_add_headers((sdp), ##__VA_ARGS__) - + _first_media_strcat(&tcap, "%d", __tcap_tag); - - if(is_srtp_dtls_enabled){ - if(!tsk_strnullORempty(TMEDIA_SESSION(self)->dtls.file_pbk)){ + + if(is_srtp_dtls_enabled) { + if(!tsk_strnullORempty(TMEDIA_SESSION(self)->dtls.file_pbk)) { fp_sha1 = trtp_manager_get_dtls_local_fingerprint(self->rtp_manager, tnet_dtls_hash_type_sha1); fp_sha256 = trtp_manager_get_dtls_local_fingerprint(self->rtp_manager, tnet_dtls_hash_type_sha256); } _first_media_strcat(&tcap, negotiate_avpf ? " UDP/TLS/RTP/SAVPF UDP/TLS/RTP/SAVP" : " UDP/TLS/RTP/SAVP"); - if(negotiate_avpf){ + if(negotiate_avpf) { profiles[profiles_index++] = RTP_PROFILE_UDP_TLS_RTP_SAVPF; } profiles[profiles_index++] = RTP_PROFILE_UDP_TLS_RTP_SAVP; } - if(is_srtp_sdes_enabled){ + if(is_srtp_sdes_enabled) { _first_media_strcat(&tcap, negotiate_avpf ? " RTP/SAVPF RTP/SAVP" : " RTP/SAVP"); - if(negotiate_avpf){ + if(negotiate_avpf) { profiles[profiles_index++] = RTP_PROFILE_SAVPF; } profiles[profiles_index++] = RTP_PROFILE_SAVP; } - - if(!is_srtp_local_mandatory){ + + if(!is_srtp_local_mandatory) { _first_media_strcat(&tcap, " RTP/AVPF"); profiles[profiles_index++] = RTP_PROFILE_AVPF; } - + // DTLS "setup" and "fringerprint"s - if((fp_sha1 || fp_sha256) && negotiate_srtp){ + if((fp_sha1 || fp_sha256) && negotiate_srtp) { char* acap_fp = tsk_null; acap_tag_setup = 1, acap_tag_connection = 2; _first_media_sprintf(&str, "%d setup:%s", acap_tag_setup, TNET_DTLS_SETUP_NAMES[self->dtls.local.setup]); @@ -1046,32 +1057,32 @@ const tsdp_header_M_t* tdav_session_av_get_lo(tdav_session_av_t* self, tsk_bool_ _first_media_add_headers(self->local_sdp, TSDP_HEADER_A_VA_ARGS("acap", str), tsk_null); // New Firefox Nightly repspond with SHA-256 when offered SHA-1 -> It's a bug in FF // Just use SHA-256 as first choice - if(fp_sha256){ + if(fp_sha256) { _first_media_sprintf(&acap_fp, "3 fingerprint:%s %s", TNET_DTLS_HASH_NAMES[tnet_dtls_hash_type_sha256], fp_sha256); acap_tag_fp_sha256 = 3; _first_media_add_headers(self->local_sdp, TSDP_HEADER_A_VA_ARGS("acap", acap_fp), tsk_null); } - if(fp_sha1){ + if(fp_sha1) { _first_media_sprintf(&acap_fp, "%d fingerprint:%s %s", fp_sha256 ? 4 : 3, TNET_DTLS_HASH_NAMES[tnet_dtls_hash_type_sha1], fp_sha1); acap_tag_fp_sha1 = (fp_sha256 ? 4 : 3); _first_media_add_headers(self->local_sdp, TSDP_HEADER_A_VA_ARGS("acap", acap_fp), tsk_null); } - + TSK_FREE(acap_fp); } - + // "tcap" _first_media_add_headers(self->local_sdp, TSDP_HEADER_A_VA_ARGS("tcap", tcap), tsk_null); TSK_FREE(tcap); - + acap_tag = TSK_MAX(acap_tag, acap_tag_connection); acap_tag = TSK_MAX(acap_tag, acap_tag_fp_sha1); acap_tag = TSK_MAX(acap_tag, acap_tag_fp_sha256); } - if(is_first_media && !negotiate_srtp && is_srtp_dtls_enabled){ + if(is_first_media && !negotiate_srtp && is_srtp_dtls_enabled) { // add DTLS-SRTP fingerprint and setup at session-level const char* fp_str = trtp_manager_get_dtls_local_fingerprint(self->rtp_manager, TDAV_DFAULT_FP_HASH); - if(fp_str){ + if(fp_str) { tsk_sprintf(&str, "%s %s", TNET_DTLS_HASH_NAMES[TDAV_DFAULT_FP_HASH], fp_str); //!\ From RFC 5763 (DTLS-SRTP Framework) \A75: The endpoint MUST NOT use the connection attribute defined in [RFC4145]. #if TDAV_FIXME_MEDIA_LEVEL_DTLS_ATT @@ -1085,113 +1096,113 @@ const tsdp_header_M_t* tdav_session_av_get_lo(tdav_session_av_t* self, tsk_bool_ #endif } } - + // "a=acap:crypto" or "a=crypto" - for(ctx_idx = 0; ctx_idx < ctx_count; ++ctx_idx){ - if(acap_tag_crypro_start == 0){ + for(ctx_idx = 0; ctx_idx < ctx_count; ++ctx_idx) { + if(acap_tag_crypro_start == 0) { acap_tag_crypro_start = (acap_tag == 1 ? acap_tag : ++acap_tag); } - if(negotiate_srtp){ + if(negotiate_srtp) { tsk_sprintf(&str, "%d crypto:%d %s inline:%s", acap_tag++, srtp_ctxs[ctx_idx]->rtp.tag, trtp_srtp_crypto_type_strings[srtp_ctxs[ctx_idx]->rtp.crypto_type], srtp_ctxs[ctx_idx]->rtp.key_str); cryptoA = tsdp_header_A_create("acap", str); } - else{ + else { tsk_sprintf(&str, "%d %s inline:%s", srtp_ctxs[ctx_idx]->rtp.tag, trtp_srtp_crypto_type_strings[srtp_ctxs[ctx_idx]->rtp.crypto_type], srtp_ctxs[ctx_idx]->rtp.key_str); cryptoA = tsdp_header_A_create("crypto", str); } - + tsdp_header_M_add(base->M.lo, (const tsdp_header_t*)cryptoA); - + TSK_OBJECT_SAFE_FREE(cryptoA); } - + // a=pcfg: - if(negotiate_srtp || negotiate_avpf){ + if(negotiate_srtp || negotiate_avpf) { tsk_size_t pcfg_tag, pcfg_idx; char *acap_crypto = tsk_null, *acap_dtls = tsk_null; - + // crypto - for(ctx_idx = 0; ctx_idx < ctx_count; ++ctx_idx){ + for(ctx_idx = 0; ctx_idx < ctx_count; ++ctx_idx) { tsk_strcat_2(&acap_crypto, "%s%d", acap_crypto ? "," : "", (acap_tag_crypro_start + ctx_idx) - ); + ); } - + // dtls setup and fingerprints - if(acap_tag_setup > 0 && acap_tag_connection > 0 && (acap_tag_fp_sha1 > 0 || acap_tag_fp_sha256 > 0)){ + if(acap_tag_setup > 0 && acap_tag_connection > 0 && (acap_tag_fp_sha1 > 0 || acap_tag_fp_sha256 > 0)) { tsk_sprintf(&acap_dtls, "%d,%d", acap_tag_setup, acap_tag_connection); - if(acap_tag_fp_sha1 > 0){ + if(acap_tag_fp_sha1 > 0) { tsk_strcat_2(&acap_dtls, ",%d", acap_tag_fp_sha1); } - if(acap_tag_fp_sha256 > 0){ + if(acap_tag_fp_sha256 > 0) { tsk_strcat_2(&acap_dtls, "%s%d", acap_tag_fp_sha1 > 0 ? "|" : ",", acap_tag_fp_sha256); } } - - for(pcfg_tag = 1, pcfg_idx = 0; pcfg_idx < profiles_index; ++pcfg_tag, ++pcfg_idx){ - if(((profiles[pcfg_idx] & RTP_PROFILE_SECURE_SDES) == RTP_PROFILE_SECURE_SDES) && acap_crypto){ + + for(pcfg_tag = 1, pcfg_idx = 0; pcfg_idx < profiles_index; ++pcfg_tag, ++pcfg_idx) { + if(((profiles[pcfg_idx] & RTP_PROFILE_SECURE_SDES) == RTP_PROFILE_SECURE_SDES) && acap_crypto) { tsk_sprintf(&str, "%d t=%d a=%s", pcfg_tag, pcfg_tag, acap_crypto); } - else if(((profiles[pcfg_idx] & RTP_PROFILE_SECURE_DTLS) == RTP_PROFILE_SECURE_DTLS) && acap_dtls){ + else if(((profiles[pcfg_idx] & RTP_PROFILE_SECURE_DTLS) == RTP_PROFILE_SECURE_DTLS) && acap_dtls) { tsk_sprintf(&str, "%d t=%d a=%s", pcfg_tag, pcfg_tag, acap_dtls); } - else{ + else { tsk_sprintf(&str, "%d t=%d", pcfg_tag, pcfg_tag); } tsdp_header_M_add_headers(base->M.lo, TSDP_HEADER_A_VA_ARGS("pcfg", str), tsk_null); } - + TSK_FREE(acap_crypto); TSK_FREE(acap_dtls); } - - if(is_srtp_remote_mandatory || is_srtp_local_mandatory || trtp_srtp_is_initialized(self->rtp_manager)){ + + if(is_srtp_remote_mandatory || is_srtp_local_mandatory || trtp_srtp_is_initialized(self->rtp_manager)) { self->use_srtp = tsk_true; } - + /* RFC 5939 - Session Description Protocol (SDP) Capability Negotiation */ { sdp_acaps_xt acaps; sdp_tcaps_xt tcaps; - + _sdp_acaps_reset(&acaps); _sdp_tcaps_reset(&tcaps); _sdp_pcfgs_reset(&self->sdp_caps->local); // session-level attributes - if(self->local_sdp){ + if(self->local_sdp) { _sdp_pcfgs_from_sdp(self->local_sdp, &acaps, &tcaps, &self->sdp_caps->local, tsk_false); } // media-level attributes _sdp_pcfgs_from_sdp(base->M.lo, &acaps, &tcaps, &self->sdp_caps->local, tsk_false); } - + TSK_FREE(str); } //end-of-if(!base->M.ro) - else{ + else { // === RO IS NOT NULL === // the ro validity has been checked in "set_ro()" RTP_PROFILE_T profile_remote = (self->sdp_caps->acfg.tag > 0 && self->sdp_caps->acfg.tcap.tag > 0) - ? self->sdp_caps->acfg.tcap.profile - : _sdp_profile_from_string(base->M.ro->proto); + ? self->sdp_caps->acfg.tcap.profile + : _sdp_profile_from_string(base->M.ro->proto); tsk_bool_t is_srtp_sdes_activated = tsk_false, is_srtp_dtls_activated = tsk_false; - + // intersect remote and local SRTP options if (self->avpf_mode_neg == tmedia_mode_optional && ((profile_remote & RTP_PROFILE_AVPF) == RTP_PROFILE_AVPF)) { self->avpf_mode_neg = tmedia_mode_mandatory; } is_srtp_sdes_enabled &= ((profile_remote & RTP_PROFILE_SECURE_SDES) == RTP_PROFILE_SECURE_SDES); is_srtp_dtls_enabled &= ((profile_remote & RTP_PROFILE_SECURE_DTLS) == RTP_PROFILE_SECURE_DTLS); - - + + // SDES-SRTP - if(is_srtp_sdes_enabled){ + if(is_srtp_sdes_enabled) { const trtp_srtp_ctx_xt *srtp_ctxs[SRTP_CRYPTO_TYPES_MAX] = { tsk_null }; tsk_size_t ctx_count = 0, ctx_idx; // get local SRTP context - if((ctx_count = trtp_srtp_get_local_contexts(self->rtp_manager, (const trtp_srtp_ctx_xt **)&srtp_ctxs, sizeof(srtp_ctxs)/sizeof(srtp_ctxs[0]))) > 0){ + if((ctx_count = trtp_srtp_get_local_contexts(self->rtp_manager, (const trtp_srtp_ctx_xt **)&srtp_ctxs, sizeof(srtp_ctxs)/sizeof(srtp_ctxs[0]))) > 0) { char* str = tsk_null; - for(ctx_idx = 0; ctx_idx < ctx_count; ++ctx_idx){ + for(ctx_idx = 0; ctx_idx < ctx_count; ++ctx_idx) { is_srtp_sdes_activated = tsk_true; tsk_sprintf(&str, "%d %s inline:%s", srtp_ctxs[ctx_idx]->rtp.tag, trtp_srtp_crypto_type_strings[srtp_ctxs[ctx_idx]->rtp.crypto_type], srtp_ctxs[ctx_idx]->rtp.key_str); tsdp_header_M_add_headers(base->M.lo, TSDP_HEADER_A_VA_ARGS("crypto", str), tsk_null); @@ -1199,14 +1210,14 @@ const tsdp_header_M_t* tdav_session_av_get_lo(tdav_session_av_t* self, tsk_bool_ TSK_FREE(str); } } - + // DTLS-SRTP - if(!is_srtp_sdes_activated && is_srtp_dtls_enabled){ + if(!is_srtp_sdes_activated && is_srtp_dtls_enabled) { // get "fingerprint", "setup" and "connection" attributes - if(!tsk_strnullORempty(TMEDIA_SESSION(self)->dtls.file_pbk)){ + if(!tsk_strnullORempty(TMEDIA_SESSION(self)->dtls.file_pbk)) { tnet_dtls_hash_type_t fp_hash_remote; char* str = tsk_null; - if((fp_hash_remote = trtp_manager_get_dtls_remote_fingerprint_hash(self->rtp_manager)) == tnet_dtls_hash_type_none){ + if((fp_hash_remote = trtp_manager_get_dtls_remote_fingerprint_hash(self->rtp_manager)) == tnet_dtls_hash_type_none) { fp_hash_remote = TDAV_DFAULT_FP_HASH; } tsk_sprintf(&str, "%s %s", TNET_DTLS_HASH_NAMES[fp_hash_remote], trtp_manager_get_dtls_local_fingerprint(self->rtp_manager, fp_hash_remote)); @@ -1228,28 +1239,28 @@ const tsdp_header_M_t* tdav_session_av_get_lo(tdav_session_av_t* self, tsk_bool_ _first_media_add_headers(self->local_sdp, TSDP_HEADER_A_VA_ARGS("connection", self->dtls.local.connection_new ? "new" : "existing"), tsk_null); #endif /* TDAV_FIXME_MEDIA_LEVEL_DTLS_ATT */ #endif /* TDAV_FIXME_MEDIA_LEVEL_DTLS_ATT */ - + is_srtp_dtls_activated = tsk_true; } - + // activate the right SRTP type and disable others trtp_manager_set_srtp_type_remote(self->rtp_manager, is_srtp_sdes_activated ? tmedia_srtp_type_sdes : (is_srtp_dtls_activated ? tmedia_srtp_type_dtls : tmedia_srtp_type_none)); - + self->use_srtp |= (is_srtp_sdes_activated || is_srtp_dtls_activated); is_srtp_sdes_enabled &= is_srtp_sdes_activated; is_srtp_dtls_enabled &= is_srtp_dtls_activated; - + }//end-of-else }//end-of-HAVE_SRTP #endif /* HAVE_SRTP */ - - + + /* RFC 5939: acfg */ - if(self->sdp_caps->acfg.tag > 0){ + if(self->sdp_caps->acfg.tag > 0) { _sdp_acfg_to_sdp(base->M.lo, &self->sdp_caps->acfg); } - + /* Hold/Resume */ #if 0 // BFCP sessions send media but not expected to receive any data. @@ -1258,21 +1269,21 @@ const tsdp_header_M_t* tdav_session_av_get_lo(tdav_session_av_t* self, tsk_bool_ #else tsdp_header_M_set_holdresume_att(base->M.lo, base->lo_held, base->ro_held); #endif - + /* Update Proto*/ tsk_strupdate(&base->M.lo->proto, self->use_srtp ? ((self->avpf_mode_neg == tmedia_mode_mandatory) ? (is_srtp_dtls_enabled ? "UDP/TLS/RTP/SAVPF" : "RTP/SAVPF") : (is_srtp_dtls_enabled ? "UDP/TLS/RTP/SAVP" : "RTP/SAVP")) - : ((self->avpf_mode_neg == tmedia_mode_mandatory) ? "RTP/AVPF" : "RTP/AVP") - ); - + : ((self->avpf_mode_neg == tmedia_mode_mandatory) ? "RTP/AVPF" : "RTP/AVP") + ); + // RFC 5761: RTCP/RTP muxing - if(self->use_rtcpmux){ + if(self->use_rtcpmux) { tsdp_header_M_add_headers(base->M.lo, TSDP_HEADER_A_VA_ARGS("rtcp-mux", tsk_null), tsk_null); } - + // draft-lennox-mmusic-sdp-source-attributes-01 - if((self->media_type & tmedia_audio) || (self->media_type & tmedia_video) || ((self->media_type & tmedia_bfcp_video) == tmedia_bfcp_video)){ + if((self->media_type & tmedia_audio) || (self->media_type & tmedia_video) || ((self->media_type & tmedia_bfcp_video) == tmedia_bfcp_video)) { char* str = tsk_null; tsk_sprintf(&str, "%u cname:%s", self->rtp_manager->rtp.ssrc.local, self->rtp_manager->rtcp.cname); // also defined in RTCP session tsdp_header_M_add_headers(base->M.lo, TSDP_HEADER_A_VA_ARGS("ssrc", str), tsk_null); @@ -1282,19 +1293,19 @@ const tsdp_header_M_t* tdav_session_av_get_lo(tdav_session_av_t* self, tsk_bool_ tsdp_header_M_add_headers(base->M.lo, TSDP_HEADER_A_VA_ARGS("ssrc", str), tsk_null); TSK_FREE(str); } - + /* ICE */ - if(self->ice_ctx){ + if(self->ice_ctx) { tsk_size_t index = 0; const tnet_ice_candidate_t* candidate; tsk_bool_t remote_use_rtcpmux = (base->M.ro && (tsdp_header_M_findA(base->M.ro, "rtcp-mux") != tsk_null)); - + // FIXME: for RTCP, use "RFC 3605"in addition to "rtcp-mux" - + // "a=ice-mismatch" if "C=" line is not included in the candidates if ((candidate = tnet_ice_ctx_get_local_candidate_first(self->ice_ctx))) { // at least one candidate base->M.lo->port = candidate->socket->port; - + tsdp_header_M_remove(base->M.lo, tsdp_htype_C); tsdp_header_M_add_headers(base->M.lo, TSDP_HEADER_C_VA_ARGS("IN", TNET_SOCKET_TYPE_IS_IPV6(candidate->socket->type) ? "IP6" : "IP4", candidate->socket->ip), @@ -1308,7 +1319,7 @@ const tsdp_header_M_t* tdav_session_av_get_lo(tdav_session_av_t* self, tsk_bool_ // tsdp_header_M_add_headers(base->M.lo, // TSDP_HEADER_A_VA_ARGS("mid", self->media_type & tmedia_audio ? "audio" : "video"), // tsk_null); - + while ((candidate = tnet_ice_ctx_get_local_candidate_at(self->ice_ctx, index++))) { if (self->use_rtcpmux && remote_use_rtcpmux && candidate->comp_id == TNET_ICE_CANDIDATE_COMPID_RTCP) { continue; // do not add RTCP candidates if RTCP-MUX is activated (local + remote) @@ -1324,15 +1335,15 @@ const tsdp_header_M_t* tdav_session_av_get_lo(tdav_session_av_t* self, tsk_bool_ } } } - else{ - if(base->M.lo->C){ + else { + if(base->M.lo->C) { tsk_strupdate(&base->M.lo->C->addr, self->rtp_manager->rtp.public_ip); tsk_strupdate(&base->M.lo->C->addrtype, (self->use_ipv6 ? "IP6" : "IP4")); } base->M.lo->port = self->rtp_manager->rtp.public_port; } - - if(self->media_type & tmedia_audio){ + + if(self->media_type & tmedia_audio) { ///* 3GPP TS 24.229 - 6.1.1 General // The UE shall include the MIME subtype "telephone-event" in the "m=" media descriptor in the SDP for audio media // flows that support both audio codec and DTMF payloads in RTP packets as described in RFC 4733 [23]. @@ -1345,19 +1356,20 @@ const tsdp_header_M_t* tdav_session_av_get_lo(tdav_session_av_t* self, tsk_bool_ // TSDP_HEADER_A_VA_ARGS("rtpmap", TMEDIA_CODEC_FORMAT_DTMF" telephone-event/8000"), // tsk_null); } - + /* QoS */ - if(base->qos){ + if(base->qos) { tmedia_qos_tline_t* ro_tline; - if(base->M.ro && (ro_tline = tmedia_qos_tline_from_sdp(base->M.ro))){ + if(base->M.ro && (ro_tline = tmedia_qos_tline_from_sdp(base->M.ro))) { tmedia_qos_tline_set_ro(base->qos, ro_tline); TSK_OBJECT_SAFE_FREE(ro_tline); } tmedia_qos_tline_to_sdp(base->qos, base->M.lo); } - DONE:; +DONE: + ; } // end-of-if(*updated) - + return base->M.lo; } @@ -1370,44 +1382,44 @@ int tdav_session_av_set_ro(tdav_session_av_t* self, const struct tsdp_header_M_s tmedia_session_t* base = TMEDIA_SESSION(self); RTP_PROFILE_T profile_remote; int32_t acfg_idx = -1; - - if(!base || !m || !updated){ + + if(!base || !m || !updated) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - if(!self->rtp_manager){ + if(!self->rtp_manager) { TSK_DEBUG_ERROR("RTP manager is null. Did you forget to prepare the session?"); return -1; } - + /* update remote offer */ TSK_OBJECT_SAFE_FREE(base->M.ro); base->M.ro = tsk_object_ref((void*)m); - + *updated = tsk_false; - + // check if the RTP profile from remote party is supported or not - if((profile_remote = _sdp_profile_from_string(m->proto)) == RTP_PROFILE_NONE){ + if((profile_remote = _sdp_profile_from_string(m->proto)) == RTP_PROFILE_NONE) { TSK_DEBUG_ERROR("%s not supported as RTP profile", m->proto); return -2; } // check that all options in the profile are supported - if((is_srtp_remote_mandatory = (profile_remote & RTP_PROFILE_SECURE)) && (self->srtp_mode == tmedia_srtp_mode_none)){ + if((is_srtp_remote_mandatory = (profile_remote & RTP_PROFILE_SECURE)) && (self->srtp_mode == tmedia_srtp_mode_none)) { TSK_DEBUG_ERROR("Remote party requesting secure transport (%s) but this option is not enabled", m->proto); return -2; } - if((is_srtp_sdes_remote_mandatory = (profile_remote & RTP_PROFILE_SECURE_SDES) == RTP_PROFILE_SECURE_SDES) && !(self->srtp_type & tmedia_srtp_type_sdes)){ + if((is_srtp_sdes_remote_mandatory = (profile_remote & RTP_PROFILE_SECURE_SDES) == RTP_PROFILE_SECURE_SDES) && !(self->srtp_type & tmedia_srtp_type_sdes)) { TSK_DEBUG_ERROR("Remote party requesting SRTP-SDES (%s) but this option is not enabled", m->proto); return -2; } - if((is_srtp_dtls_remote_mandatory = (profile_remote & RTP_PROFILE_SECURE_DTLS) == RTP_PROFILE_SECURE_DTLS) && !(self->srtp_type & tmedia_srtp_type_dtls)){ + if((is_srtp_dtls_remote_mandatory = (profile_remote & RTP_PROFILE_SECURE_DTLS) == RTP_PROFILE_SECURE_DTLS) && !(self->srtp_type & tmedia_srtp_type_dtls)) { TSK_DEBUG_ERROR("Remote party requesting DTLS-DTLS (%s) but this option is not enabled", m->proto); return -2; } is_srtp_local_mandatory = (self->srtp_mode == tmedia_srtp_mode_mandatory) && (self->srtp_type != tmedia_srtp_type_none); is_srtp_dtls_local_enabled = (self->srtp_mode != tmedia_srtp_mode_none) && (self->srtp_type & tmedia_srtp_type_dtls); is_srtp_sdes_local_enabled = (self->srtp_mode != tmedia_srtp_mode_none) && (self->srtp_type & tmedia_srtp_type_sdes); - + if (base->M.lo) { if ((neg_codecs = tmedia_session_match_codec(base, m))) { /* update negociated codecs */ @@ -1428,46 +1440,46 @@ int tdav_session_av_set_ro(tdav_session_av_t* self, const struct tsdp_header_M_s } } } - + /* AVPF */ - if(self->avpf_mode_set == tmedia_mode_optional && self->avpf_mode_neg != tmedia_mode_mandatory){ + if(self->avpf_mode_set == tmedia_mode_optional && self->avpf_mode_neg != tmedia_mode_mandatory) { self->avpf_mode_neg = _sdp_str_contains(base->M.ro->proto, "AVPF") ? tmedia_mode_mandatory : tmedia_mode_none; } - + /* RFC 5939 - Session Description Protocol (SDP) Capability Negotiation */ { sdp_acaps_xt acaps; sdp_tcaps_xt tcaps; - + _sdp_acfg_reset(&self->sdp_caps->acfg); - + _sdp_acaps_reset(&acaps); _sdp_tcaps_reset(&tcaps); _sdp_pcfgs_reset(&self->sdp_caps->remote); - + // session-level attributes - if(self->remote_sdp){ + if(self->remote_sdp) { _sdp_pcfgs_from_sdp(self->remote_sdp, &acaps, &tcaps, &self->sdp_caps->remote, tsk_false); } // media-level attributes _sdp_pcfgs_from_sdp(base->M.ro, &acaps, &tcaps, &self->sdp_caps->remote, tsk_false); } - + /* get connection associated to this media line * If the connnection is global, then the manager will call tdav_session_audio_set() */ - if(m->C && m->C->addr){ + if(m->C && m->C->addr) { tsk_strupdate(&self->remote_ip, m->C->addr); self->use_ipv6 = tsk_striequals(m->C->addrtype, "IP6"); } /* set remote port */ self->remote_port = m->port; - + /* RTCP-MUX */ self->use_rtcpmux &= (tsdp_header_M_findA(m, "rtcp-mux") != tsk_null); - if(self->ice_ctx){ + if(self->ice_ctx) { tnet_ice_ctx_set_rtcpmux(self->ice_ctx, self->use_rtcpmux); } - + // BANDWIDTH: // http://tools.ietf.org/html/rfc3556 // https://tools.ietf.org/html/rfc3890 @@ -1490,25 +1502,27 @@ int tdav_session_av_set_ro(tdav_session_av_t* self, const struct tsdp_header_M_s } } } - + /* Remote SSRC */ { // will be also updated based on received RTP packets const tsdp_header_A_t* ssrcA = tsdp_header_M_findA(m, "ssrc"); - if(ssrcA && ssrcA->value){ - if(sscanf(ssrcA->value, "%u %*s", &self->rtp_manager->rtp.ssrc.remote) != EOF){ + if(ssrcA && ssrcA->value) { + if(sscanf(ssrcA->value, "%u %*s", &self->rtp_manager->rtp.ssrc.remote) != EOF) { TSK_DEBUG_INFO("Remote SSRC = %u", self->rtp_manager->rtp.ssrc.remote); } } } - + /* RTCWeb Type */ - if(self->remote_sdp){ + if(self->remote_sdp) { const tsdp_header_S_t* S = (const tsdp_header_S_t*)tsdp_message_get_header(self->remote_sdp, tsdp_htype_S); - if(S && !tsk_strnullORempty(S->value)){ - struct rtcweb_type { const char* name; tmedia_rtcweb_type_t type; }; - static const struct rtcweb_type rtcweb_types[] = - { + if(S && !tsk_strnullORempty(S->value)) { + struct rtcweb_type { + const char* name; + tmedia_rtcweb_type_t type; + }; + static const struct rtcweb_type rtcweb_types[] = { { "firefox", tmedia_rtcweb_type_firefox }, { "chrome", tmedia_rtcweb_type_chrome }, { "bowser", tmedia_rtcweb_type_ericsson }, @@ -1516,69 +1530,71 @@ int tdav_session_av_set_ro(tdav_session_av_t* self, const struct tsdp_header_M_s }; static const int32_t rtcweb_types_count = sizeof(rtcweb_types)/sizeof(rtcweb_types[0]); int32_t i; - for(i = 0; i < rtcweb_types_count; ++i){ - if(_sdp_str_contains(S->value, rtcweb_types[i].name)){ + for(i = 0; i < rtcweb_types_count; ++i) { + if(_sdp_str_contains(S->value, rtcweb_types[i].name)) { trtp_manager_set_rtcweb_type_remote(self->rtp_manager, rtcweb_types[i].type); break; } } } } - + /* SRTP */ #if HAVE_SRTP // this is SRTP negotiation -> do not trust the remote profile - if(is_srtp_dtls_local_enabled || is_srtp_sdes_local_enabled){ + if(is_srtp_dtls_local_enabled || is_srtp_sdes_local_enabled) { int32_t i, j; const sdp_acap_xt *acap; int ret; - if(is_srtp_sdes_local_enabled){ + if(is_srtp_sdes_local_enabled) { const tsdp_header_A_t* A; const char* cryptos[2] = { tsk_null }; - + /* 1. check crypto lines from the SDP */ i = 0; - while((A = tsdp_header_M_findA_at(m, "crypto", i))){ + while((A = tsdp_header_M_findA_at(m, "crypto", i))) { cryptos[i++] = A->value; - if(i >= (sizeof(cryptos)/sizeof(cryptos[0]))){ + if(i >= (sizeof(cryptos)/sizeof(cryptos[0]))) { break; } } - + /* 2. check crypto lines from the caps (RFC 5939)*/ - if(!cryptos[0]){ + if(!cryptos[0]) { tsk_size_t k = 0; - for(i = 0; (i < SDP_CAPS_COUNT_MAX && self->sdp_caps->remote[i].tag > 0); ++i){ + for(i = 0; (i < SDP_CAPS_COUNT_MAX && self->sdp_caps->remote[i].tag > 0); ++i) { j = 0; - while((acap = _sdp_acaps_find_by_field(&self->sdp_caps->remote[i].acaps, "crypto", j++))){ - if(k < (sizeof(cryptos)/sizeof(cryptos[0]))){ + while((acap = _sdp_acaps_find_by_field(&self->sdp_caps->remote[i].acaps, "crypto", j++))) { + if(k < (sizeof(cryptos)/sizeof(cryptos[0]))) { // remove "crypto: " - if((cryptos[k] = strstr(acap->value, ":")) && ++cryptos[k]){ - while(isspace(*cryptos[k])) ++cryptos[k]; + if((cryptos[k] = strstr(acap->value, ":")) && ++cryptos[k]) { + while(isspace(*cryptos[k])) { + ++cryptos[k]; + } ++k; } } } - if(k != 0){ // do not mix crypto lines from different pcfgs + if(k != 0) { // do not mix crypto lines from different pcfgs acfg_idx = i; break; } } } - + /* 3. match cryptos */ - for(i = 0; i< sizeof(cryptos)/sizeof(cryptos[0]); ++i){ - if(!cryptos[i]){ + for(i = 0; i< sizeof(cryptos)/sizeof(cryptos[0]); ++i) { + if(!cryptos[i]) { break; } - if((ret = trtp_srtp_set_crypto_remote(self->rtp_manager, cryptos[i])) == 0){ + if((ret = trtp_srtp_set_crypto_remote(self->rtp_manager, cryptos[i])) == 0) { srtp_sdes_neg_ok = tsk_true; break; } } } // end-of-sdes - - if(!srtp_sdes_neg_ok && is_srtp_dtls_local_enabled){ + + if(!srtp_sdes_neg_ok && is_srtp_dtls_local_enabled) { int ret; const tsdp_header_A_t *setupA = tsk_null, *fpA = tsk_null, *connectionA = tsk_null; const char* fingerprints[4] = { tsk_null }; @@ -1586,75 +1602,93 @@ int tdav_session_av_set_ro(tdav_session_av_t* self, const struct tsdp_header_M_s const char* connections[4] = { tsk_null }; const char* connection = tsk_null; const char* setup = tsk_null; - + /* 1. check DTLS attributes from the SDP */ - - if(self->remote_sdp){ + + if(self->remote_sdp) { setupA = tsdp_message_get_headerA(self->remote_sdp, "setup"); fpA = tsdp_message_get_headerA(self->remote_sdp, "fingerprint"); connectionA = tsdp_message_get_headerA(self->remote_sdp, "connection"); } - if(!setupA) setupA = tsdp_header_M_findA(m, "setup"); - if(!fpA) fpA = tsdp_header_M_findA(m, "fingerprint"); - if(!connectionA) connectionA = tsdp_header_M_findA(m, "connection"); - - if(setupA) setups[0] = setupA->value; - if(fpA) fingerprints[0] = fpA->value; - if(connectionA) connections[0] = connectionA->value; - + if(!setupA) { + setupA = tsdp_header_M_findA(m, "setup"); + } + if(!fpA) { + fpA = tsdp_header_M_findA(m, "fingerprint"); + } + if(!connectionA) { + connectionA = tsdp_header_M_findA(m, "connection"); + } + + if(setupA) { + setups[0] = setupA->value; + } + if(fpA) { + fingerprints[0] = fpA->value; + } + if(connectionA) { + connections[0] = connectionA->value; + } + /* 2. check DTLS attributes from from the caps (RFC 5939) */ - if(!srtp_dtls_neg_ok && !fingerprints[0]){ + if(!srtp_dtls_neg_ok && !fingerprints[0]) { tsk_size_t k_fp = 0, k_st = 0, k_conn = 0; - for(i = 0; (i < SDP_CAPS_COUNT_MAX && self->sdp_caps->remote[i].tag > 0); ++i){ + for(i = 0; (i < SDP_CAPS_COUNT_MAX && self->sdp_caps->remote[i].tag > 0); ++i) { // "fingerprint" j = 0; - while((acap = _sdp_acaps_find_by_field(&self->sdp_caps->remote[i].acaps, "fingerprint", j++))){ - if(k_fp < (sizeof(fingerprints)/sizeof(fingerprints[0]))){ - if((fingerprints[k_fp] = strstr(acap->value, ":")) && ++fingerprints[k_fp]){ - while(isspace(*fingerprints[k_fp])) ++fingerprints[k_fp]; + while((acap = _sdp_acaps_find_by_field(&self->sdp_caps->remote[i].acaps, "fingerprint", j++))) { + if(k_fp < (sizeof(fingerprints)/sizeof(fingerprints[0]))) { + if((fingerprints[k_fp] = strstr(acap->value, ":")) && ++fingerprints[k_fp]) { + while(isspace(*fingerprints[k_fp])) { + ++fingerprints[k_fp]; + } ++k_fp; } } } // "setup" j = 0; - while((acap = _sdp_acaps_find_by_field(&self->sdp_caps->remote[i].acaps, "setup", j++))){ - if(k_st < (sizeof(setups)/sizeof(setups[0]))){ - if((setups[k_st] = strstr(acap->value, ":")) && ++setups[k_st]){ - while(isspace(*setups[k_st])) ++setups[k_st]; + while((acap = _sdp_acaps_find_by_field(&self->sdp_caps->remote[i].acaps, "setup", j++))) { + if(k_st < (sizeof(setups)/sizeof(setups[0]))) { + if((setups[k_st] = strstr(acap->value, ":")) && ++setups[k_st]) { + while(isspace(*setups[k_st])) { + ++setups[k_st]; + } ++k_st; } } } // "connection" j = 0; - while((acap = _sdp_acaps_find_by_field(&self->sdp_caps->remote[i].acaps, "connection", j++))){ - if(k_conn < (sizeof(connections)/sizeof(connections[0]))){ - if((connections[k_conn] = strstr(acap->value, ":")) && ++connections[k_conn]){ - while(isspace(*connections[k_conn])) ++connections[k_conn]; + while((acap = _sdp_acaps_find_by_field(&self->sdp_caps->remote[i].acaps, "connection", j++))) { + if(k_conn < (sizeof(connections)/sizeof(connections[0]))) { + if((connections[k_conn] = strstr(acap->value, ":")) && ++connections[k_conn]) { + while(isspace(*connections[k_conn])) { + ++connections[k_conn]; + } ++k_conn; } } } - - if(k_fp || k_st || k_conn){ // do not mix crypto lines from different pcfgs + + if(k_fp || k_st || k_conn) { // do not mix crypto lines from different pcfgs acfg_idx = i; break; } } } - + /* 3. setup DTLS connection using negotiated attributes */ - - if(!srtp_dtls_neg_ok && fingerprints[0]){ + + if(!srtp_dtls_neg_ok && fingerprints[0]) { tnet_fingerprint_t fingerprint; char hash[16]; - for(i = 0; i < sizeof(fingerprints)/sizeof(fingerprints[0]) && !srtp_dtls_neg_ok; ++i){ - if(!fingerprints[i]){ + for(i = 0; i < sizeof(fingerprints)/sizeof(fingerprints[0]) && !srtp_dtls_neg_ok; ++i) { + if(!fingerprints[i]) { break; } - if(sscanf(fingerprints[i], "%15s %255s", hash, fingerprint) >= 2){ - if((ret = trtp_manager_set_dtls_remote_fingerprint(self->rtp_manager, &fingerprint, hash)) == 0){ + if(sscanf(fingerprints[i], "%15s %255s", hash, fingerprint) >= 2) { + if((ret = trtp_manager_set_dtls_remote_fingerprint(self->rtp_manager, &fingerprint, hash)) == 0) { acfg_idx = i; srtp_dtls_neg_ok = tsk_true; break; @@ -1662,37 +1696,43 @@ int tdav_session_av_set_ro(tdav_session_av_t* self, const struct tsdp_header_M_s } } } - + // only accept sdp without fingerprints if certificate verification is OFF - if(!srtp_dtls_neg_ok && !fingerprints[0] && !TMEDIA_SESSION(self)->dtls.verify){ - for(i = 0; (i < SDP_CAPS_COUNT_MAX && self->sdp_caps->remote[i].tag > 0); ++i){ - if(self->sdp_caps->remote[i].tcap.tag > 0 && (self->sdp_caps->remote[i].tcap.profile & RTP_PROFILE_SECURE_DTLS) == RTP_PROFILE_SECURE_DTLS){ + if(!srtp_dtls_neg_ok && !fingerprints[0] && !TMEDIA_SESSION(self)->dtls.verify) { + for(i = 0; (i < SDP_CAPS_COUNT_MAX && self->sdp_caps->remote[i].tag > 0); ++i) { + if(self->sdp_caps->remote[i].tcap.tag > 0 && (self->sdp_caps->remote[i].tcap.profile & RTP_PROFILE_SECURE_DTLS) == RTP_PROFILE_SECURE_DTLS) { acfg_idx = i; break; } } } - + // defaults - if(!connection) connection = connections[acfg_idx != -1 ? acfg_idx : 0]; - if(!setup) setup = setups[acfg_idx != -1 ? acfg_idx : 0]; - - if((!connection || !setup) && (is_srtp_dtls_remote_mandatory || is_srtp_local_mandatory || (acfg_idx != -1 && (self->sdp_caps->remote[acfg_idx].tcap.profile & RTP_PROFILE_SECURE_DTLS) == RTP_PROFILE_SECURE_DTLS))){ - if(!connection) connection = (self->dtls.local.connection_new ? "existing" : "new"); + if(!connection) { + connection = connections[acfg_idx != -1 ? acfg_idx : 0]; + } + if(!setup) { + setup = setups[acfg_idx != -1 ? acfg_idx : 0]; + } + + if((!connection || !setup) && (is_srtp_dtls_remote_mandatory || is_srtp_local_mandatory || (acfg_idx != -1 && (self->sdp_caps->remote[acfg_idx].tcap.profile & RTP_PROFILE_SECURE_DTLS) == RTP_PROFILE_SECURE_DTLS))) { + if(!connection) { + connection = (self->dtls.local.connection_new ? "existing" : "new"); + } if(!setup) setup = (self->dtls.local.setup == tnet_dtls_setup_active - ? "passive" - : (self->dtls.local.setup == tnet_dtls_setup_passive ? "active" : (base->M.lo ? "passive" : "active"))); + ? "passive" + : (self->dtls.local.setup == tnet_dtls_setup_passive ? "active" : (base->M.lo ? "passive" : "active"))); } - + if (connection && setup) { // update local setup according to remote setup // do not update if local setup already negotiated if (tnet_dtls_get_setup_from_string(setup) != tnet_dtls_setup_actpass || (self->dtls.local.setup == tnet_dtls_setup_none || self->dtls.local.setup == tnet_dtls_setup_actpass)) { ret = _tdav_session_av_dtls_set_remote_setup(self, - tnet_dtls_get_setup_from_string(setup), - !tsk_striequals(connection, "existing"), - (!base->M.ro) - ); + tnet_dtls_get_setup_from_string(setup), + !tsk_striequals(connection, "existing"), + (!base->M.ro) + ); } if (ret == 0) { // pass new local values to the RTP manager @@ -1700,43 +1740,43 @@ int tdav_session_av_set_ro(tdav_session_av_t* self, const struct tsdp_header_M_s srtp_dtls_neg_ok = (ret == 0); } } - + }// end-of-dtls }//end-of-if(srtp=optional|mandatory) - + self->use_srtp = trtp_srtp_is_initialized(self->rtp_manager); - + // activate the right SRTP type and disable others trtp_manager_set_srtp_type_remote(self->rtp_manager, srtp_sdes_neg_ok ? tmedia_srtp_type_sdes : (srtp_dtls_neg_ok ? tmedia_srtp_type_dtls : tmedia_srtp_type_none)); - + #endif - + // set actual config - if(acfg_idx == -1){ + if(acfg_idx == -1) { // none matched (means SRTP negotiation failed or not enabled -> try to negotiate AVP(F)) int32_t i; - for(i = 0; (i < SDP_CAPS_COUNT_MAX && self->sdp_caps->remote[i].tag > 0); ++i){ - if(self->sdp_caps->remote[i].tcap.tag > 0){ - if((self->sdp_caps->remote[i].tcap.profile & RTP_PROFILE_AVPF) == RTP_PROFILE_AVPF){ + for(i = 0; (i < SDP_CAPS_COUNT_MAX && self->sdp_caps->remote[i].tag > 0); ++i) { + if(self->sdp_caps->remote[i].tcap.tag > 0) { + if((self->sdp_caps->remote[i].tcap.profile & RTP_PROFILE_AVPF) == RTP_PROFILE_AVPF) { acfg_idx = i; break; } } } } - if(acfg_idx != -1){ + if(acfg_idx != -1) { self->sdp_caps->acfg = self->sdp_caps->remote[acfg_idx]; if (self->avpf_mode_set == tmedia_mode_optional && self->avpf_mode_neg != tmedia_mode_mandatory) { self->avpf_mode_neg = ((self->sdp_caps->acfg.tcap.profile & RTP_PROFILE_AVPF) == RTP_PROFILE_AVPF) ? tmedia_mode_mandatory : tmedia_mode_none; } } - - if(!srtp_sdes_neg_ok && !srtp_dtls_neg_ok && (is_srtp_remote_mandatory || is_srtp_local_mandatory)){ + + if(!srtp_sdes_neg_ok && !srtp_dtls_neg_ok && (is_srtp_remote_mandatory || is_srtp_local_mandatory)) { TSK_DEBUG_ERROR("SRTP negotiation failed"); return -4; } - + return 0; } @@ -1747,11 +1787,11 @@ const tmedia_codec_t* tdav_session_av_get_best_neg_codec(const tdav_session_av_t TSK_DEBUG_ERROR("Invalid parameter"); return tsk_null; } - + tsk_list_foreach(item, TMEDIA_SESSION(self)->neg_codecs) { // exclude DTMF, RED and ULPFEC if (!TDAV_IS_DTMF_CODEC(item->data) && !TDAV_IS_ULPFEC_CODEC(item->data) && !TDAV_IS_RED_CODEC(item->data) - && TMEDIA_CODEC(item->data)->plugin && TMEDIA_CODEC(item->data)->plugin->encode && TMEDIA_CODEC(item->data)->plugin->decode) { + && TMEDIA_CODEC(item->data)->plugin && TMEDIA_CODEC(item->data)->plugin->encode && TMEDIA_CODEC(item->data)->plugin->decode) { return TMEDIA_CODEC(item->data); } } @@ -1761,14 +1801,14 @@ const tmedia_codec_t* tdav_session_av_get_best_neg_codec(const tdav_session_av_t const tmedia_codec_t* tdav_session_av_get_red_codec(const tdav_session_av_t* self) { const tsk_list_item_t* item; - if(!self){ + if(!self) { TSK_DEBUG_ERROR("Invalid parameter"); return tsk_null; } - - tsk_list_foreach(item, TMEDIA_SESSION(self)->neg_codecs){ + + tsk_list_foreach(item, TMEDIA_SESSION(self)->neg_codecs) { const tmedia_codec_t* codec = (const tmedia_codec_t*)item->data; - if(TDAV_IS_RED_CODEC(codec)){ + if(TDAV_IS_RED_CODEC(codec)) { return TMEDIA_CODEC(item->data); } } @@ -1777,10 +1817,10 @@ const tmedia_codec_t* tdav_session_av_get_red_codec(const tdav_session_av_t* sel static void* TSK_STDCALL _tdav_session_av_error_async_thread(void* usrdata) { - if(usrdata){ + if(usrdata) { tdav_session_av_t* self = (tdav_session_av_t*)usrdata; tsk_safeobj_lock(self); - if(TMEDIA_SESSION(self)->onerror_cb.fun){ + if(TMEDIA_SESSION(self)->onerror_cb.fun) { TMEDIA_SESSION(self)->onerror_cb.fun(TMEDIA_SESSION(self)->onerror_cb.usrdata, TMEDIA_SESSION(self), self->last_error.reason, self->last_error.is_fatal); } tsk_safeobj_unlock(self); @@ -1792,29 +1832,29 @@ static void* TSK_STDCALL _tdav_session_av_error_async_thread(void* usrdata) static int _tdav_session_av_raise_error_async(struct tdav_session_av_s* self, tsk_bool_t is_fatal, const char* reason) { int ret; - if(!self){ + if(!self) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - + tsk_safeobj_lock(self); - + tsk_object_ref(self); // do not unref(), see _tdav_session_av_error_async_thread() - + if (self->last_error.tid[0]) { tsk_thread_join(self->last_error.tid); } - + self->last_error.is_fatal = is_fatal; tsk_strupdate(&self->last_error.reason, reason); if ((ret = tsk_thread_create(self->last_error.tid, _tdav_session_av_error_async_thread, self)) != 0) { tsk_object_unref(self); goto bail; } - + bail: tsk_safeobj_unlock(self); - + return ret; } @@ -1822,35 +1862,36 @@ bail: static int _tdav_session_av_srtp_dtls_cb(const void* usrdata, enum trtp_srtp_dtls_event_type_e type, const char* reason) { tdav_session_av_t* self = tsk_object_ref((tdav_session_av_t*)usrdata); - + tsk_safeobj_lock(self); - switch(type){ - case trtp_srtp_dtls_event_type_handshake_failed: - case trtp_srtp_dtls_event_type_fatal_error: - { - if(TMEDIA_SESSION(self)->onerror_cb.fun){ - static const tsk_bool_t __is_fatal = tsk_true; - _tdav_session_av_raise_error_async(self, __is_fatal, reason); - } - break; - } - case trtp_srtp_dtls_event_type_handshake_succeed: - { - break; + switch(type) { + case trtp_srtp_dtls_event_type_handshake_failed: + case trtp_srtp_dtls_event_type_fatal_error: { + if(TMEDIA_SESSION(self)->onerror_cb.fun) { + static const tsk_bool_t __is_fatal = tsk_true; + _tdav_session_av_raise_error_async(self, __is_fatal, reason); } - case trtp_srtp_dtls_event_type_started: - { - // start producer and consumer - if (self->rtp_manager && self->rtp_manager->is_started) { - if (self->consumer && !self->consumer->is_started) tmedia_consumer_start(self->consumer); - if (self->producer && !self->producer->is_started) tmedia_producer_start(self->producer); + break; + } + case trtp_srtp_dtls_event_type_handshake_succeed: { + break; + } + case trtp_srtp_dtls_event_type_started: { + // start producer and consumer + if (self->rtp_manager && self->rtp_manager->is_started) { + if (self->consumer && !self->consumer->is_started) { + tmedia_consumer_start(self->consumer); + } + if (self->producer && !self->producer->is_started) { + tmedia_producer_start(self->producer); } - break; } + break; + } } tsk_safeobj_unlock(self); tsk_object_unref(self); - + return 0; } #endif /* HAVE_SRTP */ @@ -1858,7 +1899,7 @@ static int _tdav_session_av_srtp_dtls_cb(const void* usrdata, enum trtp_srtp_dtl static int _tdav_session_av_red_cb(const void* usrdata, const struct trtp_rtp_packet_s* packet) { tdav_session_av_t* self = (tdav_session_av_t*)usrdata; - if(self->rtp_manager && self->rtp_manager->rtp.cb.fun){ + if(self->rtp_manager && self->rtp_manager->rtp.cb.fun) { return self->rtp_manager->rtp.cb.fun(self->rtp_manager->rtp.cb.usrdata, packet); } return 0; @@ -1866,32 +1907,32 @@ static int _tdav_session_av_red_cb(const void* usrdata, const struct trtp_rtp_pa int _tdav_session_av_dtls_set_remote_setup(struct tdav_session_av_s* self, tnet_dtls_setup_t setup, tsk_bool_t connection_new, tsk_bool_t is_ro_null) { - if(self){ + if(self) { TSK_DEBUG_INFO("dtls.remote.setup=%s", TNET_DTLS_SETUP_NAMES[(int)setup]); self->dtls.remote.setup = setup; self->dtls.remote.connection_new = connection_new; - switch(self->dtls.remote.setup){ - case tnet_dtls_setup_none: - default: - self->dtls.local.setup = tnet_dtls_setup_actpass; - self->dtls.local.connection_new = tsk_true; // RTP transport always unprepared for reINVITE/UPDATE -> new connection - break; - case tnet_dtls_setup_active: - self->dtls.local.setup = is_ro_null ? tnet_dtls_setup_actpass : tnet_dtls_setup_passive; - self->dtls.local.connection_new = tsk_true; - break; - case tnet_dtls_setup_passive: - self->dtls.local.setup = is_ro_null ? tnet_dtls_setup_actpass : tnet_dtls_setup_active; + switch(self->dtls.remote.setup) { + case tnet_dtls_setup_none: + default: + self->dtls.local.setup = tnet_dtls_setup_actpass; + self->dtls.local.connection_new = tsk_true; // RTP transport always unprepared for reINVITE/UPDATE -> new connection + break; + case tnet_dtls_setup_active: + self->dtls.local.setup = is_ro_null ? tnet_dtls_setup_actpass : tnet_dtls_setup_passive; + self->dtls.local.connection_new = tsk_true; + break; + case tnet_dtls_setup_passive: + self->dtls.local.setup = is_ro_null ? tnet_dtls_setup_actpass : tnet_dtls_setup_active; + self->dtls.local.connection_new = tsk_true; + break; + case tnet_dtls_setup_actpass: + if (self->dtls.local.setup == tnet_dtls_setup_actpass || self->dtls.local.setup == tnet_dtls_setup_none) { // change local setup only if actpass or none + self->dtls.local.setup = (self->dtls.local.setup == tnet_dtls_setup_actpass || self->dtls.local.setup == tnet_dtls_setup_active) + ? tnet_dtls_setup_active + : tnet_dtls_setup_passive; self->dtls.local.connection_new = tsk_true; - break; - case tnet_dtls_setup_actpass: - if (self->dtls.local.setup == tnet_dtls_setup_actpass || self->dtls.local.setup == tnet_dtls_setup_none) { // change local setup only if actpass or none - self->dtls.local.setup = (self->dtls.local.setup == tnet_dtls_setup_actpass || self->dtls.local.setup == tnet_dtls_setup_active) - ? tnet_dtls_setup_active - : tnet_dtls_setup_passive; - self->dtls.local.connection_new = tsk_true; - } - break; + } + break; } } return 0; @@ -1900,13 +1941,13 @@ int _tdav_session_av_dtls_set_remote_setup(struct tdav_session_av_s* self, tnet_ const tmedia_codec_t* tdav_session_av_get_ulpfec_codec(const tdav_session_av_t* self) { const tsk_list_item_t* item; - if(!self){ + if(!self) { TSK_DEBUG_ERROR("Invalid parameter"); return tsk_null; } - - tsk_list_foreach(item, TMEDIA_SESSION(self)->neg_codecs){ - if(TDAV_IS_ULPFEC_CODEC(item->data)){ + + tsk_list_foreach(item, TMEDIA_SESSION(self)->neg_codecs) { + if(TDAV_IS_ULPFEC_CODEC(item->data)) { return TMEDIA_CODEC(item->data); } } @@ -1915,11 +1956,11 @@ const tmedia_codec_t* tdav_session_av_get_ulpfec_codec(const tdav_session_av_t* int tdav_session_av_deinit(tdav_session_av_t* self) { - if(!self){ + if(!self) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - + /* deinit self (rtp manager should be destroyed after the producer) */ TSK_OBJECT_SAFE_FREE(self->consumer); TSK_OBJECT_SAFE_FREE(self->producer); @@ -1929,26 +1970,26 @@ int tdav_session_av_deinit(tdav_session_av_t* self) TSK_OBJECT_SAFE_FREE(self->local_sdp); TSK_FREE(self->remote_ip); TSK_FREE(self->local_ip); - + /* RED and ULPFEC codecs */ TSK_OBJECT_SAFE_FREE(self->red.codec); TSK_OBJECT_SAFE_FREE(self->ulpfec.codec); - + /* NAT Traversal context */ TSK_OBJECT_SAFE_FREE(self->natt_ctx); TSK_OBJECT_SAFE_FREE(self->ice_ctx); - + /* Last error */ - if(self->last_error.tid[0]){ + if(self->last_error.tid[0]) { tsk_thread_join(self->last_error.tid); } TSK_FREE(self->last_error.reason); - + tsk_safeobj_deinit(self); - + /* deinit base */ tmedia_session_deinit(TMEDIA_SESSION(self)); - + return 0; } @@ -1962,34 +2003,34 @@ int tdav_session_av_deinit(tdav_session_av_t* self) static const tsdp_header_A_t* _sdp_findA_at(const sdp_headerM_Or_Message* sdp, const char* field, tsk_size_t index) { - if(sdp){ - if(TSK_OBJECT_HEADER(sdp)->__def__ == tsdp_message_def_t){ + if(sdp) { + if(TSK_OBJECT_HEADER(sdp)->__def__ == tsdp_message_def_t) { return tsdp_message_get_headerA_at((const tsdp_message_t*)sdp, field, index); } - else if(TSK_OBJECT_HEADER(sdp)->__def__ == tsdp_header_M_def_t){ + else if(TSK_OBJECT_HEADER(sdp)->__def__ == tsdp_header_M_def_t) { return tsdp_header_M_findA_at((const tsdp_header_M_t*)sdp, field, index); } } - + TSK_DEBUG_ERROR("Invalid parameter"); return tsk_null; } static int _sdp_add_headerA(sdp_headerM_Or_Message* sdp, const char* field, const char* value) { - if(sdp && field){ - if(TSK_OBJECT_HEADER(sdp)->__def__ == tsdp_message_def_t){ + if(sdp && field) { + if(TSK_OBJECT_HEADER(sdp)->__def__ == tsdp_message_def_t) { return tsdp_message_add_headers((tsdp_message_t*)sdp, TSDP_HEADER_A_VA_ARGS(field, value), tsk_null); } - else if(TSK_OBJECT_HEADER(sdp)->__def__ == tsdp_header_M_def_t){ + else if(TSK_OBJECT_HEADER(sdp)->__def__ == tsdp_header_M_def_t) { return tsdp_header_M_add_headers((tsdp_header_M_t*)sdp, TSDP_HEADER_A_VA_ARGS(field, value), tsk_null); } } - + TSK_DEBUG_ERROR("Invalid parameter"); return -1; } @@ -1997,8 +2038,8 @@ static int _sdp_add_headerA(sdp_headerM_Or_Message* sdp, const char* field, cons static RTP_PROFILE_T _sdp_profile_from_string(const char* profile) { int32_t i; - for(i = 0; i < RTP_PROFILES_COUNT; ++i){ - if(tsk_striequals(RTP_PROFILES[i].name, profile)){ + for(i = 0; i < RTP_PROFILES_COUNT; ++i) { + if(tsk_striequals(RTP_PROFILES[i].name, profile)) { return RTP_PROFILES[i].type; } } @@ -2008,8 +2049,8 @@ static RTP_PROFILE_T _sdp_profile_from_string(const char* profile) static const char* _sdp_profile_to_string(RTP_PROFILE_T profile) { int32_t i; - for(i = 0; i < RTP_PROFILES_COUNT; ++i){ - if(RTP_PROFILES[i].type == profile){ + for(i = 0; i < RTP_PROFILES_COUNT; ++i) { + if(RTP_PROFILES[i].type == profile) { return RTP_PROFILES[i].name; } } @@ -2021,18 +2062,18 @@ _SDP_DECLARE_INDEX_OF(acap); static const sdp_acap_xt* _sdp_acaps_find_by_field(const sdp_acap_xt (*acaps)[SDP_CAPS_COUNT_MAX], const char* field, int32_t index) { int32_t i, j, k, size; - - if(!acaps || !field){ + + if(!acaps || !field) { TSK_DEBUG_ERROR("Invalid paramter"); return tsk_null; } - + i = 0, j = 0; size = (int32_t)tsk_strlen(field); - while((*acaps)[j].tag && j < SDP_CAPS_COUNT_MAX){ + while((*acaps)[j].tag && j < SDP_CAPS_COUNT_MAX) { k = _sdp_str_index_of((*acaps)[j].value, field); - if(k == 0 && (*acaps)[j].value[size] == ':'){ - if(i == index){ + if(k == 0 && (*acaps)[j].value[size] == ':') { + if(i == index) { return &(*acaps)[j]; } ++i; @@ -2047,52 +2088,52 @@ static int _sdp_acaps_from_sdp(const sdp_headerM_Or_Message* sdp, sdp_acap_xt (* tsk_size_t acaps_count, acaps_idx; const tsdp_header_A_t* A; int32_t tag, index, size; - - if(!sdp || !acaps){ + + if(!sdp || !acaps) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - - - if(reset){ + + + if(reset) { _sdp_acaps_reset(acaps); acaps_count = 0; } - else{ - if((acaps_count = _sdp_acaps_indexof(acaps, 0)) == -1){ + else { + if((acaps_count = _sdp_acaps_indexof(acaps, 0)) == -1) { TSK_DEBUG_ERROR("No room to append items"); return -1; } } - + acaps_idx = 0; - while((A = _sdp_findA_at(sdp, "acap", acaps_idx++))){ - if (!(size = (int32_t)tsk_strlen(A->value))){ + while((A = _sdp_findA_at(sdp, "acap", acaps_idx++))) { + if (!(size = (int32_t)tsk_strlen(A->value))) { goto next; } - if(sscanf(A->value, "%d", &tag) == EOF){ + if(sscanf(A->value, "%d", &tag) == EOF) { TSK_DEBUG_ERROR("sscanf(%s) failed", A->value); break; } - if(tag <= 0 || (tag + 1) > SDP_CAPS_COUNT_MAX){ + if(tag <= 0 || (tag + 1) > SDP_CAPS_COUNT_MAX) { TSK_DEBUG_WARN("Ignoring tag with value = %d", tag); goto next; } - + index = _sdp_integer_length(tag) + 1;/*SPACE*/ - if(index >= size){ + if(index >= size) { TSK_DEBUG_WARN("a=%s is empty", A->value); goto next; } - + (*acaps)[acaps_count].tag = tag; (*acaps)[acaps_count].value = &A->value[index]; - next: - if(++acaps_count >= SDP_CAPS_COUNT_MAX){ +next: + if(++acaps_count >= SDP_CAPS_COUNT_MAX) { break; } } - + return 0; } @@ -2104,60 +2145,60 @@ static int _sdp_tcaps_from_sdp(const sdp_headerM_Or_Message* sdp, sdp_tcap_xt (* const tsdp_header_A_t* A; int32_t tag, index, size, tag_fake; char tcap[256]; - - if(!sdp || !tcaps){ + + if(!sdp || !tcaps) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - - if(reset){ + + if(reset) { _sdp_tcaps_reset(tcaps); tcaps_count = 0; } - else{ - if((tcaps_count = _sdp_tcaps_indexof(tcaps, 0)) == -1){ + else { + if((tcaps_count = _sdp_tcaps_indexof(tcaps, 0)) == -1) { TSK_DEBUG_ERROR("No room to append items"); return -1; } - } - + } + profiles_count = 0; index = 0; tcaps_idx = 0; - while((A = _sdp_findA_at(sdp, "tcap", tcaps_idx++))){ - if (!(size = (int32_t)tsk_strlen(A->value))){ + while((A = _sdp_findA_at(sdp, "tcap", tcaps_idx++))) { + if (!(size = (int32_t)tsk_strlen(A->value))) { goto next; } - if(sscanf(&A->value[index], "%d", &tag) == EOF || (_sdp_integer_length(tag) + 1 >= size)){ + if(sscanf(&A->value[index], "%d", &tag) == EOF || (_sdp_integer_length(tag) + 1 >= size)) { TSK_DEBUG_ERROR("sscanf(%s) failed", A->value); break; } - if(tag <= 0 || (tag + 1) > SDP_CAPS_COUNT_MAX){ + if(tag <= 0 || (tag + 1) > SDP_CAPS_COUNT_MAX) { TSK_DEBUG_WARN("Ignoring tag with value = %d", tag); goto next; } - + index += _sdp_integer_length(tag) + 1/*SPACE*/; - + profiles_count = 0; tag_fake = tag; - while(sscanf(&A->value[index], "%255s", &tcap) != EOF){ - if(tag_fake < SDP_CAPS_COUNT_MAX){ + while(sscanf(&A->value[index], "%255s", &tcap) != EOF) { + if(tag_fake < SDP_CAPS_COUNT_MAX) { (*tcaps)[tcaps_count + profiles_count].tag = tag_fake; (*tcaps)[tcaps_count + profiles_count].profile = _sdp_profile_from_string(tcap); // split profiles } - if ((index += (int32_t)tsk_strlen(tcap) + 1/*SPACE*/) >= size){ + if ((index += (int32_t)tsk_strlen(tcap) + 1/*SPACE*/) >= size) { break; } ++tag_fake; ++profiles_count; } - next: - if(++tcaps_count >= SDP_CAPS_COUNT_MAX){ +next: + if(++tcaps_count >= SDP_CAPS_COUNT_MAX) { break; } } - + return 0; } @@ -2165,42 +2206,42 @@ static int _sdp_acfg_to_sdp(sdp_headerM_Or_Message* sdp, const sdp_acfg_xt *acfg { int32_t i_a_caps; char *acfg_str = tsk_null; - - if(!sdp || !acfg || acfg->tag <= 0){ + + if(!sdp || !acfg || acfg->tag <= 0) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - + // acfg: tag tsk_strcat_2(&acfg_str, "%d", acfg->tag); // acfg: t= - if(acfg_str && acfg->tcap.tag > 0){ + if(acfg_str && acfg->tcap.tag > 0) { tsk_strcat_2(&acfg_str, " t=%d", acfg->tcap.tag); } // acfg: a= - for (i_a_caps = 0; acfg_str && i_a_caps < SDP_CAPS_COUNT_MAX; ++i_a_caps){ - if(acfg->acaps[i_a_caps].tag <= 0){ + for (i_a_caps = 0; acfg_str && i_a_caps < SDP_CAPS_COUNT_MAX; ++i_a_caps) { + if(acfg->acaps[i_a_caps].tag <= 0) { break; } - if(i_a_caps == 0){ + if(i_a_caps == 0) { tsk_strcat_2(&acfg_str, " a=%d", acfg->acaps[i_a_caps].tag); } - else{ + else { tsk_strcat_2(&acfg_str, "%s%s%d%s", // e.g. |2 or ,6 or ,[2] acfg->acaps[i_a_caps].or ? "|" : ",", acfg->acaps[i_a_caps].optional ? "[" : "", acfg->acaps[i_a_caps].tag, acfg->acaps[i_a_caps].optional ? "]" : "" - ); + ); } } - + // a=acfg: - if(acfg_str){ + if(acfg_str) { _sdp_add_headerA(sdp, "acfg", acfg_str); TSK_FREE(acfg_str); } - + return 0; } @@ -2214,79 +2255,79 @@ static int _sdp_pcfgs_from_sdp(const sdp_headerM_Or_Message* sdp, sdp_acap_xt (* sdp_tcap_xt* tcap_curr; int ret; char pcfg[256], a[256]; - - if(!sdp || !acaps || !tcaps || !pcfgs){ + + if(!sdp || !acaps || !tcaps || !pcfgs) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - - if((ret = _sdp_tcaps_from_sdp(sdp, tcaps, reset))){ + + if((ret = _sdp_tcaps_from_sdp(sdp, tcaps, reset))) { return ret; } - if((ret = _sdp_acaps_from_sdp(sdp, acaps, reset))){ + if((ret = _sdp_acaps_from_sdp(sdp, acaps, reset))) { return ret; } - - if(reset){ + + if(reset) { _sdp_pcfgs_reset(pcfgs); pcfgs_count = 0; } - else{ - if((pcfgs_count = _sdp_pcfgs_indexof(pcfgs, 0)) == -1){ + else { + if((pcfgs_count = _sdp_pcfgs_indexof(pcfgs, 0)) == -1) { TSK_DEBUG_ERROR("No room to append items"); return -1; } } - + pcfgs_idx = 0; tcap_curr = tsk_null; - while((A = _sdp_findA_at(sdp, "pcfg", pcfgs_idx++))){ - if (!(size = (int32_t)tsk_strlen(A->value))){ + while((A = _sdp_findA_at(sdp, "pcfg", pcfgs_idx++))) { + if (!(size = (int32_t)tsk_strlen(A->value))) { goto next_A; } - if(sscanf(A->value, "%d", &tag) == EOF || (_sdp_integer_length(tag) + 1 >= size)){ + if(sscanf(A->value, "%d", &tag) == EOF || (_sdp_integer_length(tag) + 1 >= size)) { TSK_DEBUG_ERROR("sscanf(%s) failed", A->value); break; } - if(tag <= 0 || (tag + 1) > SDP_CAPS_COUNT_MAX){ + if(tag <= 0 || (tag + 1) > SDP_CAPS_COUNT_MAX) { TSK_DEBUG_WARN("Ignoring tag with value = %d", tag); goto next_A; } - + (*pcfgs)[pcfgs_count].tag = tag; - + index = _sdp_integer_length(tag) + 1/*SPACE*/; - - while(sscanf(&A->value[index], "%255s", &pcfg) != EOF){ - if(_sdp_str_starts_with(&A->value[index], "t=") && sscanf(pcfg, "t=%d", &t) != EOF){ - if(t <= 0 || t + 1 >= SDP_CAPS_COUNT_MAX){ + + while(sscanf(&A->value[index], "%255s", &pcfg) != EOF) { + if(_sdp_str_starts_with(&A->value[index], "t=") && sscanf(pcfg, "t=%d", &t) != EOF) { + if(t <= 0 || t + 1 >= SDP_CAPS_COUNT_MAX) { TSK_DEBUG_ERROR("t = %d ignored", t); goto next_pcfg; } // tcap is something like a=tcap:1 RTP/SAVPF RTP/SAVP RTP/AVPF // tcap [2] is "RTP/SAVP" -> not indexed by tag tcap_curr = &(*pcfgs)[pcfgs_count].tcap; - if((indexof = _sdp_tcaps_indexof(tcaps, t)) == -1){ + if((indexof = _sdp_tcaps_indexof(tcaps, t)) == -1) { TSK_DEBUG_ERROR("Failed to find 'tcap' with tag=%d", t); goto next_pcfg; } *tcap_curr = (*tcaps)[indexof]; } - else{ - if(_sdp_str_starts_with(&A->value[index], "a=") && sscanf(pcfg, "a=%255s", a) != EOF){ + else { + if(_sdp_str_starts_with(&A->value[index], "a=") && sscanf(pcfg, "a=%255s", a) != EOF) { char a_copy[sizeof(a)], *pch, *saveptr; tsk_size_t pcfg_acfgs_count = 0; sdp_acap_xt* acap; memcpy(a_copy, a, sizeof(a)); - + pch = tsk_strtok_r (a, ",[]|", &saveptr); - while(pch){ + while(pch) { a_tag = atoi(pch); - if(a_tag <= 0 || a_tag + 1 >= SDP_CAPS_COUNT_MAX){ + if(a_tag <= 0 || a_tag + 1 >= SDP_CAPS_COUNT_MAX) { TSK_DEBUG_ERROR("a = %d ignored", a_tag); goto next_a; } - if((indexof = _sdp_acaps_indexof(acaps, a_tag)) == -1){ + if((indexof = _sdp_acaps_indexof(acaps, a_tag)) == -1) { TSK_DEBUG_ERROR("Failed to find 'acap' with tag=%d", a_tag); goto next_a; } @@ -2294,23 +2335,23 @@ static int _sdp_pcfgs_from_sdp(const sdp_headerM_Or_Message* sdp, sdp_acap_xt (* *acap = (*acaps)[indexof]; acap->optional = (pch != a && a_copy[pch - a - 1] == '[') ? 1 : 0; acap->or = (pch != a && a_copy[pch - a - 1] == '|') ? 1 : 0; - next_a: +next_a: pch = tsk_strtok_r(tsk_null, ",[]|", &saveptr); } } tcap_curr = tsk_null; } - next_pcfg: - if ((index += (int32_t)tsk_strlen(pcfg) + 1/*SPACE*/) >= size){ +next_pcfg: + if ((index += (int32_t)tsk_strlen(pcfg) + 1/*SPACE*/) >= size) { break; } } - next_A: - if(++pcfgs_count >= SDP_CAPS_COUNT_MAX){ +next_A: + if(++pcfgs_count >= SDP_CAPS_COUNT_MAX) { break; } } - + return ret; } @@ -2319,77 +2360,77 @@ static int _sdp_pcfgs_to_sdp(sdp_headerM_Or_Message* sdp, const sdp_pcfg_xt (*pc int32_t i_pcfgs, i_a_caps, i_serialized_acaps; char *pcfg = tsk_null, *acap = tsk_null, *tcap = tsk_null; sdp_acaps_xt serialized_acaps; /* to avoid duplication */ - - if(!sdp || !pcfgs){ + + if(!sdp || !pcfgs) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - + // compact(a=tcap:) // tcap:1 RTP/AVP // tcap:2 RTP/SAVP // tcap:3 RTP/SAVPF // will be compacted as // tcap:1 RTP/AVP RTP/SAVP RTP/SAVPF - for (i_pcfgs = 0; i_pcfgs < SDP_CAPS_COUNT_MAX; ++i_pcfgs){ - if((*pcfgs)[i_pcfgs].tag <= 0 || (*pcfgs)[i_pcfgs].tcap.tag <= 0){ + for (i_pcfgs = 0; i_pcfgs < SDP_CAPS_COUNT_MAX; ++i_pcfgs) { + if((*pcfgs)[i_pcfgs].tag <= 0 || (*pcfgs)[i_pcfgs].tcap.tag <= 0) { break; } - if(!tcap){ + if(!tcap) { tsk_sprintf(&tcap, "1 %s", _sdp_profile_to_string((*pcfgs)[i_pcfgs].tcap.profile)); } - else{ + else { tsk_strcat_2(&tcap, " %s", _sdp_profile_to_string((*pcfgs)[i_pcfgs].tcap.profile)); } } - if(tcap){ + if(tcap) { _sdp_add_headerA(sdp, "tcap", tcap); TSK_FREE(tcap); } - + _sdp_acaps_reset(&serialized_acaps); i_serialized_acaps = 0; - - for (i_pcfgs = 0; i_pcfgs < SDP_CAPS_COUNT_MAX; ++i_pcfgs){ - if((*pcfgs)[i_pcfgs].tag <= 0){ + + for (i_pcfgs = 0; i_pcfgs < SDP_CAPS_COUNT_MAX; ++i_pcfgs) { + if((*pcfgs)[i_pcfgs].tag <= 0) { break; } // pcfg: tag tsk_strcat_2(&pcfg, "%d", (*pcfgs)[i_pcfgs].tag); // pcfg: t= - if((*pcfgs)[i_pcfgs].tcap.tag > 0){ + if((*pcfgs)[i_pcfgs].tcap.tag > 0) { tsk_strcat_2(&pcfg, " t=%d", (*pcfgs)[i_pcfgs].tcap.tag); } - + // pcfg: a= - for (i_a_caps = 0; i_a_caps < SDP_CAPS_COUNT_MAX; ++i_a_caps){ - if((*pcfgs)[i_pcfgs].acaps[i_a_caps].tag <= 0){ + for (i_a_caps = 0; i_a_caps < SDP_CAPS_COUNT_MAX; ++i_a_caps) { + if((*pcfgs)[i_pcfgs].acaps[i_a_caps].tag <= 0) { break; } - if(i_a_caps == 0){ + if(i_a_caps == 0) { tsk_strcat_2(&pcfg, " a=%d", (*pcfgs)[i_pcfgs].acaps[i_a_caps].tag); } - else{ + else { tsk_strcat_2(&pcfg, "%s%s%d%s", // e.g. |2 or ,6 or ,[2] (*pcfgs)[i_pcfgs].acaps[i_a_caps].or ? "|" : ",", (*pcfgs)[i_pcfgs].acaps[i_a_caps].optional ? "[" : "", (*pcfgs)[i_pcfgs].acaps[i_a_caps].tag, (*pcfgs)[i_pcfgs].acaps[i_a_caps].optional ? "]" : "" - ); + ); } // a=acap: - if(_sdp_acaps_indexof(&serialized_acaps, (*pcfgs)[i_pcfgs].acaps[i_a_caps].tag) == -1){ + if(_sdp_acaps_indexof(&serialized_acaps, (*pcfgs)[i_pcfgs].acaps[i_a_caps].tag) == -1) { tsk_sprintf(&acap, "%d %s", (*pcfgs)[i_pcfgs].acaps[i_a_caps].tag, (*pcfgs)[i_pcfgs].acaps[i_a_caps].value); - if(acap){ + if(acap) { _sdp_add_headerA(sdp, "acap", acap); TSK_FREE(acap); serialized_acaps[i_serialized_acaps++].tag = (*pcfgs)[i_pcfgs].acaps[i_a_caps].tag; } } } - + // a=pcfg: - if(pcfg){ + if(pcfg) { _sdp_add_headerA(sdp, "pcfg", pcfg); TSK_FREE(pcfg); } @@ -2401,44 +2442,46 @@ static int _sdp_pcfg_ensure(sdp_headerM_Or_Message* sdp, const sdp_pcfg_xt* pcfg { int32_t i, n; char field[256]; - - if(!sdp || !pcfg || pcfg->tag <=0){ + + if(!sdp || !pcfg || pcfg->tag <=0) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - - if(TSK_OBJECT_HEADER(sdp)->__def__ == tsdp_header_M_def_t && pcfg->tcap.profile != RTP_PROFILE_NONE){ + + if(TSK_OBJECT_HEADER(sdp)->__def__ == tsdp_header_M_def_t && pcfg->tcap.profile != RTP_PROFILE_NONE) { tsk_strupdate(&((tsdp_header_M_t*)sdp)->proto, _sdp_profile_to_string(pcfg->tcap.profile)); } - - for(i = 0; i < SDP_CAPS_COUNT_MAX && pcfg->acaps[i].tag > 0; ++i){ - if (sscanf(pcfg->acaps[i].value, "%255s%*s", field) != EOF && (n = (int32_t)tsk_strlen(field)) > 2){ + + for(i = 0; i < SDP_CAPS_COUNT_MAX && pcfg->acaps[i].tag > 0; ++i) { + if (sscanf(pcfg->acaps[i].value, "%255s%*s", field) != EOF && (n = (int32_t)tsk_strlen(field)) > 2) { field[n - 2] = '\0'; _sdp_add_headerA(sdp, field, &pcfg->acaps[i].value[n + 1/*SPACE*/]); } } - + return 0; } static int _sdp_pcfgs_cat(const sdp_pcfg_xt (*pcfgs_src)[SDP_CAPS_COUNT_MAX], sdp_pcfg_xt (*pcfgs_dst)[SDP_CAPS_COUNT_MAX]) { int32_t i, j; - if(!pcfgs_src || !pcfgs_dst){ + if(!pcfgs_src || !pcfgs_dst) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - + for(i = 0; i < SDP_CAPS_COUNT_MAX && (*pcfgs_dst)[i].tag > 0; ++i); - + j = 0; - while (i < SDP_CAPS_COUNT_MAX && j < SDP_CAPS_COUNT_MAX){ - if((*pcfgs_src)[j].tag > 0){ + while (i < SDP_CAPS_COUNT_MAX && j < SDP_CAPS_COUNT_MAX) { + if((*pcfgs_src)[j].tag > 0) { (*pcfgs_dst)[i++] = (*pcfgs_src)[j++]; } - else break; + else { + break; + } } - + return 0; } @@ -2449,23 +2492,22 @@ static int _sdp_pcfgs_cat(const sdp_pcfg_xt (*pcfgs_src)[SDP_CAPS_COUNT_MAX], sd static tsk_object_t* tdav_sdp_caps_ctor(tsk_object_t * self, va_list * app) { tdav_sdp_caps_t *caps = self; - if(caps){ + if(caps) { } return self; } static tsk_object_t* tdav_sdp_caps_dtor(tsk_object_t * self) -{ +{ tdav_sdp_caps_t *caps = self; - if(caps){ + if(caps) { } return self; } -static const tsk_object_def_t tdav_sdp_caps_def_s = -{ +static const tsk_object_def_t tdav_sdp_caps_def_s = { sizeof(tdav_sdp_caps_t), - tdav_sdp_caps_ctor, + tdav_sdp_caps_ctor, tdav_sdp_caps_dtor, - tsk_null, + tsk_null, }; static tdav_sdp_caps_t* tdav_sdp_caps_create() |