From 50dfb4359619563012997bc3ddafb7667741066c Mon Sep 17 00:00:00 2001 From: Mamadou DIOP Date: Tue, 23 Feb 2016 22:00:35 +0100 Subject: Add new QoS implementation Code formatting --- tinyDAV/src/audio/tdav_session_audio.c | 1613 ++++++++++++++++---------------- 1 file changed, 805 insertions(+), 808 deletions(-) (limited to 'tinyDAV/src/audio/tdav_session_audio.c') diff --git a/tinyDAV/src/audio/tdav_session_audio.c b/tinyDAV/src/audio/tdav_session_audio.c index f12e801..31c9b34 100755 --- a/tinyDAV/src/audio/tdav_session_audio.c +++ b/tinyDAV/src/audio/tdav_session_audio.c @@ -51,14 +51,13 @@ static void _tdav_session_audio_apply_gain(void* buffer, int len, int bps, int g static tmedia_resampler_t* _tdav_session_audio_resampler_create(int32_t bytes_per_sample, uint32_t in_freq, uint32_t out_freq, uint32_t frame_duration, uint32_t in_channels, uint32_t out_channels, uint32_t quality, void** resampler_buffer, tsk_size_t *resampler_buffer_size); /* DTMF event object */ -typedef struct tdav_session_audio_dtmfe_s -{ - TSK_DECLARE_OBJECT; +typedef struct tdav_session_audio_dtmfe_s { + TSK_DECLARE_OBJECT; - tsk_timer_id_t timer_id; - trtp_rtp_packet_t* packet; + tsk_timer_id_t timer_id; + trtp_rtp_packet_t* packet; - const tdav_session_audio_t* session; + const tdav_session_audio_t* session; } tdav_session_audio_dtmfe_t; extern const tsk_object_def_t *tdav_session_audio_dtmfe_def_t; @@ -66,230 +65,230 @@ extern const tsk_object_def_t *tdav_session_audio_dtmfe_def_t; // RTP/RTCP callback (From the network to the consumer) static int tdav_session_audio_rtp_cb(const void* callback_data, const struct trtp_rtp_packet_s* packet) { - tdav_session_audio_t* audio = (tdav_session_audio_t*)callback_data; - tmedia_codec_t* codec = tsk_null; - tdav_session_av_t* base = (tdav_session_av_t*)callback_data; - int ret = -1; - - if (!audio || !packet || !packet->header) { - TSK_DEBUG_ERROR("Invalid parameter"); - goto bail; - } - - if (audio->is_started && base->consumer && base->consumer->is_started) { - tsk_size_t out_size = 0; - - // Find the codec to use to decode the RTP payload - if (!audio->decoder.codec || audio->decoder.payload_type != packet->header->payload_type) { - tsk_istr_t format; - TSK_OBJECT_SAFE_FREE(audio->decoder.codec); - tsk_itoa(packet->header->payload_type, &format); - if (!(audio->decoder.codec = tmedia_codec_find_by_format(TMEDIA_SESSION(audio)->neg_codecs, format)) || !audio->decoder.codec->plugin || !audio->decoder.codec->plugin->decode){ - TSK_DEBUG_ERROR("%s is not a valid payload for this session", format); - ret = -2; - goto bail; - } - audio->decoder.payload_type = packet->header->payload_type; - } - // ref() the codec to be able to use it short time after stop(SAFE_FREE(codec)) - if (!(codec = tsk_object_ref(TSK_OBJECT(audio->decoder.codec)))) { - TSK_DEBUG_ERROR("Failed to get decoder codec"); - goto bail; - } - - // Open codec if not already done - if (!TMEDIA_CODEC(codec)->opened) { - tsk_safeobj_lock(base); - if ((ret = tmedia_codec_open(codec))) { - tsk_safeobj_unlock(base); - TSK_DEBUG_ERROR("Failed to open [%s] codec", codec->plugin->desc); - TSK_OBJECT_SAFE_FREE(audio->decoder.codec); - goto bail; - } - tsk_safeobj_unlock(base); - } - // Decode data - out_size = codec->plugin->decode(codec, packet->payload.data, packet->payload.size, &audio->decoder.buffer, &audio->decoder.buffer_size, packet->header); - if (out_size && audio->is_started) { // check "is_started" again ...to be sure stop() not called by another thread - void* buffer = audio->decoder.buffer; - tsk_size_t size = out_size; - - // resample if needed - if ((base->consumer->audio.out.rate && base->consumer->audio.out.rate != codec->in.rate) || (base->consumer->audio.out.channels && base->consumer->audio.out.channels != TMEDIA_CODEC_AUDIO(codec)->in.channels)) { - tsk_size_t resampler_result_size = 0; - int bytesPerSample = (base->consumer->audio.bits_per_sample >> 3); - - if (!audio->decoder.resampler.instance) { - TSK_DEBUG_INFO("Create audio resampler(%s) for consumer: rate=%d->%d, channels=%d->%d, bytesPerSample=%d", - codec->plugin->desc, - codec->in.rate, base->consumer->audio.out.rate, - TMEDIA_CODEC_AUDIO(codec)->in.channels, base->consumer->audio.out.channels, - bytesPerSample); - audio->decoder.resampler.instance = _tdav_session_audio_resampler_create( - bytesPerSample, - codec->in.rate, base->consumer->audio.out.rate, - base->consumer->audio.ptime, - TMEDIA_CODEC_AUDIO(codec)->in.channels, base->consumer->audio.out.channels, - TDAV_AUDIO_RESAMPLER_DEFAULT_QUALITY, - &audio->decoder.resampler.buffer, &audio->decoder.resampler.buffer_size - ); - } - if (!audio->decoder.resampler.instance) { - TSK_DEBUG_ERROR("No resampler to handle data"); - ret = -5; - goto bail; - } - if (!(resampler_result_size = tmedia_resampler_process(audio->decoder.resampler.instance, buffer, size / bytesPerSample, audio->decoder.resampler.buffer, audio->decoder.resampler.buffer_size / bytesPerSample))){ - TSK_DEBUG_ERROR("Failed to process audio resampler input buffer"); - ret = -6; - goto bail; - } - - buffer = audio->decoder.resampler.buffer; - size = audio->decoder.resampler.buffer_size; - } - - // adjust the gain - if (base->consumer->audio.gain) { - _tdav_session_audio_apply_gain(buffer, (int)size, base->consumer->audio.bits_per_sample, base->consumer->audio.gain); - } - // consume the frame - tmedia_consumer_consume(base->consumer, buffer, size, packet->header); - } - } - else { - TSK_DEBUG_INFO("Session audio not ready"); - } - - // everything is ok - ret = 0; + tdav_session_audio_t* audio = (tdav_session_audio_t*)callback_data; + tmedia_codec_t* codec = tsk_null; + tdav_session_av_t* base = (tdav_session_av_t*)callback_data; + int ret = -1; + + if (!audio || !packet || !packet->header) { + TSK_DEBUG_ERROR("Invalid parameter"); + goto bail; + } + + if (audio->is_started && base->consumer && base->consumer->is_started) { + tsk_size_t out_size = 0; + + // Find the codec to use to decode the RTP payload + if (!audio->decoder.codec || audio->decoder.payload_type != packet->header->payload_type) { + tsk_istr_t format; + TSK_OBJECT_SAFE_FREE(audio->decoder.codec); + tsk_itoa(packet->header->payload_type, &format); + if (!(audio->decoder.codec = tmedia_codec_find_by_format(TMEDIA_SESSION(audio)->neg_codecs, format)) || !audio->decoder.codec->plugin || !audio->decoder.codec->plugin->decode) { + TSK_DEBUG_ERROR("%s is not a valid payload for this session", format); + ret = -2; + goto bail; + } + audio->decoder.payload_type = packet->header->payload_type; + } + // ref() the codec to be able to use it short time after stop(SAFE_FREE(codec)) + if (!(codec = tsk_object_ref(TSK_OBJECT(audio->decoder.codec)))) { + TSK_DEBUG_ERROR("Failed to get decoder codec"); + goto bail; + } + + // Open codec if not already done + if (!TMEDIA_CODEC(codec)->opened) { + tsk_safeobj_lock(base); + if ((ret = tmedia_codec_open(codec))) { + tsk_safeobj_unlock(base); + TSK_DEBUG_ERROR("Failed to open [%s] codec", codec->plugin->desc); + TSK_OBJECT_SAFE_FREE(audio->decoder.codec); + goto bail; + } + tsk_safeobj_unlock(base); + } + // Decode data + out_size = codec->plugin->decode(codec, packet->payload.data, packet->payload.size, &audio->decoder.buffer, &audio->decoder.buffer_size, packet->header); + if (out_size && audio->is_started) { // check "is_started" again ...to be sure stop() not called by another thread + void* buffer = audio->decoder.buffer; + tsk_size_t size = out_size; + + // resample if needed + if ((base->consumer->audio.out.rate && base->consumer->audio.out.rate != codec->in.rate) || (base->consumer->audio.out.channels && base->consumer->audio.out.channels != TMEDIA_CODEC_AUDIO(codec)->in.channels)) { + tsk_size_t resampler_result_size = 0; + int bytesPerSample = (base->consumer->audio.bits_per_sample >> 3); + + if (!audio->decoder.resampler.instance) { + TSK_DEBUG_INFO("Create audio resampler(%s) for consumer: rate=%d->%d, channels=%d->%d, bytesPerSample=%d", + codec->plugin->desc, + codec->in.rate, base->consumer->audio.out.rate, + TMEDIA_CODEC_AUDIO(codec)->in.channels, base->consumer->audio.out.channels, + bytesPerSample); + audio->decoder.resampler.instance = _tdav_session_audio_resampler_create( + bytesPerSample, + codec->in.rate, base->consumer->audio.out.rate, + base->consumer->audio.ptime, + TMEDIA_CODEC_AUDIO(codec)->in.channels, base->consumer->audio.out.channels, + TDAV_AUDIO_RESAMPLER_DEFAULT_QUALITY, + &audio->decoder.resampler.buffer, &audio->decoder.resampler.buffer_size + ); + } + if (!audio->decoder.resampler.instance) { + TSK_DEBUG_ERROR("No resampler to handle data"); + ret = -5; + goto bail; + } + if (!(resampler_result_size = tmedia_resampler_process(audio->decoder.resampler.instance, buffer, size / bytesPerSample, audio->decoder.resampler.buffer, audio->decoder.resampler.buffer_size / bytesPerSample))) { + TSK_DEBUG_ERROR("Failed to process audio resampler input buffer"); + ret = -6; + goto bail; + } + + buffer = audio->decoder.resampler.buffer; + size = audio->decoder.resampler.buffer_size; + } + + // adjust the gain + if (base->consumer->audio.gain) { + _tdav_session_audio_apply_gain(buffer, (int)size, base->consumer->audio.bits_per_sample, base->consumer->audio.gain); + } + // consume the frame + tmedia_consumer_consume(base->consumer, buffer, size, packet->header); + } + } + else { + TSK_DEBUG_INFO("Session audio not ready"); + } + + // everything is ok + ret = 0; bail: - tsk_object_unref(TSK_OBJECT(codec)); - return ret; + tsk_object_unref(TSK_OBJECT(codec)); + return ret; } // Producer callback (From the producer to the network). Will encode() data before sending static int tdav_session_audio_producer_enc_cb(const void* callback_data, const void* buffer, tsk_size_t size) { - int ret = 0; - - tdav_session_audio_t* audio = (tdav_session_audio_t*)callback_data; - tdav_session_av_t* base = (tdav_session_av_t*)callback_data; - - if (!audio) { - TSK_DEBUG_ERROR("Null session"); - return 0; - } - - // do nothing if session is held - // when the session is held the end user will get feedback he also has possibilities to put the consumer and producer on pause - if (TMEDIA_SESSION(audio)->lo_held) { - return 0; - } - - // get best negotiated codec if not already done - // the encoder codec could be null when session is renegotiated without re-starting (e.g. hold/resume) - if (!audio->encoder.codec) { - const tmedia_codec_t* codec; - tsk_safeobj_lock(base); - if (!(codec = tdav_session_av_get_best_neg_codec(base))) { - TSK_DEBUG_ERROR("No codec matched"); - tsk_safeobj_unlock(base); - return -2; - } - audio->encoder.codec = tsk_object_ref(TSK_OBJECT(codec)); - tsk_safeobj_unlock(base); - } - - if (audio->is_started && base->rtp_manager && base->rtp_manager->is_started) { - /* encode */ - tsk_size_t out_size = 0; - - // Open codec if not already done - if (!audio->encoder.codec->opened) { - tsk_safeobj_lock(base); - if ((ret = tmedia_codec_open(audio->encoder.codec))) { - tsk_safeobj_unlock(base); - TSK_DEBUG_ERROR("Failed to open [%s] codec", audio->encoder.codec->plugin->desc); - return -4; - } - tsk_safeobj_unlock(base); - } - // check if we're sending DTMF or not - if (audio->is_sending_dtmf_events) { - if (base->rtp_manager) { - // increment the timestamp - base->rtp_manager->rtp.timestamp += TMEDIA_CODEC_PCM_FRAME_SIZE_AUDIO_ENCODING(audio->encoder.codec)/*duration*/; - } - TSK_DEBUG_INFO("Skiping audio frame as we're sending DTMF..."); - return 0; - } - - // resample if needed - if (base->producer->audio.rate != audio->encoder.codec->out.rate || base->producer->audio.channels != TMEDIA_CODEC_AUDIO(audio->encoder.codec)->out.channels){ - tsk_size_t resampler_result_size = 0; - int bytesPerSample = (base->producer->audio.bits_per_sample >> 3); - - if (!audio->encoder.resampler.instance){ - TSK_DEBUG_INFO("Create audio resampler(%s) for producer: rate=%d->%d, channels=%d->%d, bytesPerSample=%d", - audio->encoder.codec->plugin->desc, - base->producer->audio.rate, audio->encoder.codec->out.rate, - base->producer->audio.channels, TMEDIA_CODEC_AUDIO(audio->encoder.codec)->out.channels, - bytesPerSample); - audio->encoder.resampler.instance = _tdav_session_audio_resampler_create( - bytesPerSample, - base->producer->audio.rate, audio->encoder.codec->out.rate, - base->producer->audio.ptime, - base->producer->audio.channels, TMEDIA_CODEC_AUDIO(audio->encoder.codec)->out.channels, - TDAV_AUDIO_RESAMPLER_DEFAULT_QUALITY, - &audio->encoder.resampler.buffer, &audio->encoder.resampler.buffer_size - ); - } - if (!audio->encoder.resampler.instance){ - TSK_DEBUG_ERROR("No resampler to handle data"); - ret = -1; - goto done; - } - if (!(resampler_result_size = tmedia_resampler_process(audio->encoder.resampler.instance, buffer, size / bytesPerSample, audio->encoder.resampler.buffer, audio->encoder.resampler.buffer_size / bytesPerSample))){ - TSK_DEBUG_ERROR("Failed to process audio resampler input buffer"); - ret = -1; - goto done; - } - - buffer = audio->encoder.resampler.buffer; - size = audio->encoder.resampler.buffer_size; - } - - // Denoise (VAD, AGC, Noise suppression, ...) - // Must be done after resampling - if (audio->denoise){ - tsk_bool_t silence_or_noise = tsk_false; - if (audio->denoise->echo_supp_enabled){ - ret = tmedia_denoise_process_record(TMEDIA_DENOISE(audio->denoise), (void*)buffer, (uint32_t)size, &silence_or_noise); - } - } - // adjust the gain - // Must be done after resampling - if (base->producer->audio.gain){ - _tdav_session_audio_apply_gain((void*)buffer, (int)size, base->producer->audio.bits_per_sample, base->producer->audio.gain); - } - - // Encode data - if ((audio->encoder.codec = tsk_object_ref(audio->encoder.codec))){ /* Thread safeness (SIP reINVITE or UPDATE could update the encoder) */ - out_size = audio->encoder.codec->plugin->encode(audio->encoder.codec, buffer, size, &audio->encoder.buffer, &audio->encoder.buffer_size); - if (out_size){ - trtp_manager_send_rtp(base->rtp_manager, audio->encoder.buffer, out_size, TMEDIA_CODEC_FRAME_DURATION_AUDIO_ENCODING(audio->encoder.codec), tsk_false/*Marker*/, tsk_true/*lastPacket*/); - } - tsk_object_unref(audio->encoder.codec); - } - else{ - TSK_DEBUG_WARN("No encoder"); - } - } + int ret = 0; + + tdav_session_audio_t* audio = (tdav_session_audio_t*)callback_data; + tdav_session_av_t* base = (tdav_session_av_t*)callback_data; + + if (!audio) { + TSK_DEBUG_ERROR("Null session"); + return 0; + } + + // do nothing if session is held + // when the session is held the end user will get feedback he also has possibilities to put the consumer and producer on pause + if (TMEDIA_SESSION(audio)->lo_held) { + return 0; + } + + // get best negotiated codec if not already done + // the encoder codec could be null when session is renegotiated without re-starting (e.g. hold/resume) + if (!audio->encoder.codec) { + const tmedia_codec_t* codec; + tsk_safeobj_lock(base); + if (!(codec = tdav_session_av_get_best_neg_codec(base))) { + TSK_DEBUG_ERROR("No codec matched"); + tsk_safeobj_unlock(base); + return -2; + } + audio->encoder.codec = tsk_object_ref(TSK_OBJECT(codec)); + tsk_safeobj_unlock(base); + } + + if (audio->is_started && base->rtp_manager && base->rtp_manager->is_started) { + /* encode */ + tsk_size_t out_size = 0; + + // Open codec if not already done + if (!audio->encoder.codec->opened) { + tsk_safeobj_lock(base); + if ((ret = tmedia_codec_open(audio->encoder.codec))) { + tsk_safeobj_unlock(base); + TSK_DEBUG_ERROR("Failed to open [%s] codec", audio->encoder.codec->plugin->desc); + return -4; + } + tsk_safeobj_unlock(base); + } + // check if we're sending DTMF or not + if (audio->is_sending_dtmf_events) { + if (base->rtp_manager) { + // increment the timestamp + base->rtp_manager->rtp.timestamp += TMEDIA_CODEC_PCM_FRAME_SIZE_AUDIO_ENCODING(audio->encoder.codec)/*duration*/; + } + TSK_DEBUG_INFO("Skiping audio frame as we're sending DTMF..."); + return 0; + } + + // resample if needed + if (base->producer->audio.rate != audio->encoder.codec->out.rate || base->producer->audio.channels != TMEDIA_CODEC_AUDIO(audio->encoder.codec)->out.channels) { + tsk_size_t resampler_result_size = 0; + int bytesPerSample = (base->producer->audio.bits_per_sample >> 3); + + if (!audio->encoder.resampler.instance) { + TSK_DEBUG_INFO("Create audio resampler(%s) for producer: rate=%d->%d, channels=%d->%d, bytesPerSample=%d", + audio->encoder.codec->plugin->desc, + base->producer->audio.rate, audio->encoder.codec->out.rate, + base->producer->audio.channels, TMEDIA_CODEC_AUDIO(audio->encoder.codec)->out.channels, + bytesPerSample); + audio->encoder.resampler.instance = _tdav_session_audio_resampler_create( + bytesPerSample, + base->producer->audio.rate, audio->encoder.codec->out.rate, + base->producer->audio.ptime, + base->producer->audio.channels, TMEDIA_CODEC_AUDIO(audio->encoder.codec)->out.channels, + TDAV_AUDIO_RESAMPLER_DEFAULT_QUALITY, + &audio->encoder.resampler.buffer, &audio->encoder.resampler.buffer_size + ); + } + if (!audio->encoder.resampler.instance) { + TSK_DEBUG_ERROR("No resampler to handle data"); + ret = -1; + goto done; + } + if (!(resampler_result_size = tmedia_resampler_process(audio->encoder.resampler.instance, buffer, size / bytesPerSample, audio->encoder.resampler.buffer, audio->encoder.resampler.buffer_size / bytesPerSample))) { + TSK_DEBUG_ERROR("Failed to process audio resampler input buffer"); + ret = -1; + goto done; + } + + buffer = audio->encoder.resampler.buffer; + size = audio->encoder.resampler.buffer_size; + } + + // Denoise (VAD, AGC, Noise suppression, ...) + // Must be done after resampling + if (audio->denoise) { + tsk_bool_t silence_or_noise = tsk_false; + if (audio->denoise->echo_supp_enabled) { + ret = tmedia_denoise_process_record(TMEDIA_DENOISE(audio->denoise), (void*)buffer, (uint32_t)size, &silence_or_noise); + } + } + // adjust the gain + // Must be done after resampling + if (base->producer->audio.gain) { + _tdav_session_audio_apply_gain((void*)buffer, (int)size, base->producer->audio.bits_per_sample, base->producer->audio.gain); + } + + // Encode data + if ((audio->encoder.codec = tsk_object_ref(audio->encoder.codec))) { /* Thread safeness (SIP reINVITE or UPDATE could update the encoder) */ + out_size = audio->encoder.codec->plugin->encode(audio->encoder.codec, buffer, size, &audio->encoder.buffer, &audio->encoder.buffer_size); + if (out_size) { + trtp_manager_send_rtp(base->rtp_manager, audio->encoder.buffer, out_size, TMEDIA_CODEC_FRAME_DURATION_AUDIO_ENCODING(audio->encoder.codec), tsk_false/*Marker*/, tsk_true/*lastPacket*/); + } + tsk_object_unref(audio->encoder.codec); + } + else { + TSK_DEBUG_WARN("No encoder"); + } + } done: - return ret; + return ret; } @@ -297,512 +296,514 @@ done: static int tdav_session_audio_set(tmedia_session_t* self, const tmedia_param_t* param) { - int ret = 0; - tdav_session_audio_t* audio; - - if (!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if (tdav_session_av_set(TDAV_SESSION_AV(self), param) == tsk_true){ - return 0; - } - - audio = (tdav_session_audio_t*)self; - - if (param->plugin_type == tmedia_ppt_consumer){ - TSK_DEBUG_ERROR("Not expected consumer_set(%s)", param->key); - } - else if (param->plugin_type == tmedia_ppt_producer){ - TSK_DEBUG_ERROR("Not expected producer_set(%s)", param->key); - } - else{ - if (param->value_type == tmedia_pvt_int32){ - if (tsk_striequals(param->key, "echo-supp")){ - if (audio->denoise){ - audio->denoise->echo_supp_enabled = (TSK_TO_INT32((uint8_t*)param->value) != 0); - } - } - else if (tsk_striequals(param->key, "echo-tail")){ - if (audio->denoise){ - return tmedia_denoise_set(audio->denoise, param); - } - } - } - } - - return ret; + int ret = 0; + tdav_session_audio_t* audio; + + if (!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if (tdav_session_av_set(TDAV_SESSION_AV(self), param) == tsk_true) { + return 0; + } + + audio = (tdav_session_audio_t*)self; + + if (param->plugin_type == tmedia_ppt_consumer) { + TSK_DEBUG_ERROR("Not expected consumer_set(%s)", param->key); + } + else if (param->plugin_type == tmedia_ppt_producer) { + TSK_DEBUG_ERROR("Not expected producer_set(%s)", param->key); + } + else { + if (param->value_type == tmedia_pvt_int32) { + if (tsk_striequals(param->key, "echo-supp")) { + if (audio->denoise) { + audio->denoise->echo_supp_enabled = (TSK_TO_INT32((uint8_t*)param->value) != 0); + } + } + else if (tsk_striequals(param->key, "echo-tail")) { + if (audio->denoise) { + return tmedia_denoise_set(audio->denoise, param); + } + } + } + } + + return ret; } static int tdav_session_audio_get(tmedia_session_t* self, tmedia_param_t* param) { - if (!self || !param){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - // try with the base class to see if this option is supported or not - if (tdav_session_av_get(TDAV_SESSION_AV(self), param) == tsk_true){ - return 0; - } - else { - // the codec information is held by the session even if the user is authorized to request it for the consumer/producer - if (param->value_type == tmedia_pvt_pobject){ - if (param->plugin_type == tmedia_ppt_consumer){ - TSK_DEBUG_ERROR("Not implemented"); - return -4; - } - else if (param->plugin_type == tmedia_ppt_producer){ - if (tsk_striequals("codec", param->key)) { - const tmedia_codec_t* codec; - if (!(codec = TDAV_SESSION_AUDIO(self)->encoder.codec)){ - codec = tdav_session_av_get_best_neg_codec((const tdav_session_av_t*)self); // up to the caller to release the object - } - *((tsk_object_t**)param->value) = tsk_object_ref(TSK_OBJECT(codec)); - return 0; - } - } - else if (param->plugin_type == tmedia_ppt_session) { - if (tsk_striequals(param->key, "codec-encoder")) { - *((tsk_object_t**)param->value) = tsk_object_ref(TDAV_SESSION_AUDIO(self)->encoder.codec); // up to the caller to release the object - return 0; - } - } - } - } - - TSK_DEBUG_WARN("This session doesn't support get(%s)", param->key); - return -2; + if (!self || !param) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + // try with the base class to see if this option is supported or not + if (tdav_session_av_get(TDAV_SESSION_AV(self), param) == tsk_true) { + return 0; + } + else { + // the codec information is held by the session even if the user is authorized to request it for the consumer/producer + if (param->value_type == tmedia_pvt_pobject) { + if (param->plugin_type == tmedia_ppt_consumer) { + TSK_DEBUG_ERROR("Not implemented"); + return -4; + } + else if (param->plugin_type == tmedia_ppt_producer) { + if (tsk_striequals("codec", param->key)) { + const tmedia_codec_t* codec; + if (!(codec = TDAV_SESSION_AUDIO(self)->encoder.codec)) { + codec = tdav_session_av_get_best_neg_codec((const tdav_session_av_t*)self); // up to the caller to release the object + } + *((tsk_object_t**)param->value) = tsk_object_ref(TSK_OBJECT(codec)); + return 0; + } + } + else if (param->plugin_type == tmedia_ppt_session) { + if (tsk_striequals(param->key, "codec-encoder")) { + *((tsk_object_t**)param->value) = tsk_object_ref(TDAV_SESSION_AUDIO(self)->encoder.codec); // up to the caller to release the object + return 0; + } + } + } + } + + TSK_DEBUG_WARN("This session doesn't support get(%s)", param->key); + return -2; } static int tdav_session_audio_prepare(tmedia_session_t* self) { - tdav_session_av_t* base = (tdav_session_av_t*)(self); - int ret; + tdav_session_av_t* base = (tdav_session_av_t*)(self); + int ret; - if ((ret = tdav_session_av_prepare(base))){ - TSK_DEBUG_ERROR("tdav_session_av_prepare(audio) failed"); - return ret; - } + if ((ret = tdav_session_av_prepare(base))) { + TSK_DEBUG_ERROR("tdav_session_av_prepare(audio) failed"); + return ret; + } - if (base->rtp_manager){ - ret = trtp_manager_set_rtp_callback(base->rtp_manager, tdav_session_audio_rtp_cb, base); - } + if (base->rtp_manager) { + ret = trtp_manager_set_rtp_callback(base->rtp_manager, tdav_session_audio_rtp_cb, base); + } - return ret; + return ret; } static int tdav_session_audio_start(tmedia_session_t* self) { - int ret; - tdav_session_audio_t* audio; - const tmedia_codec_t* codec; - tdav_session_av_t* base; - - if (!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - audio = (tdav_session_audio_t*)self; - base = (tdav_session_av_t*)self; - - if (audio->is_started) { - TSK_DEBUG_INFO("Audio session already started"); - return 0; - } - - if (!(codec = tdav_session_av_get_best_neg_codec(base))){ - TSK_DEBUG_ERROR("No codec matched"); - return -2; - } - - TSK_OBJECT_SAFE_FREE(audio->encoder.codec); - audio->encoder.codec = tsk_object_ref((tsk_object_t*)codec); - - if ((ret = tdav_session_av_start(base, codec))){ - TSK_DEBUG_ERROR("tdav_session_av_start(audio) failed"); - return ret; - } - - if (base->rtp_manager){ - /* Denoise (AEC, Noise Suppression, AGC) - * tmedia_denoise_process_record() is called after resampling and before encoding which means sampling rate is equal to codec's rate - * tmedia_denoise_echo_playback() is called before playback which means sampling rate is equal to consumer's rate - */ - if (audio->denoise){ - uint32_t record_frame_size_samples = TMEDIA_CODEC_PCM_FRAME_SIZE_AUDIO_ENCODING(audio->encoder.codec); - uint32_t record_sampling_rate = TMEDIA_CODEC_RATE_ENCODING(audio->encoder.codec); - uint32_t record_channels = TMEDIA_CODEC_CHANNELS_AUDIO_ENCODING(audio->encoder.codec); - - uint32_t playback_frame_size_samples = (base->consumer && base->consumer->audio.ptime && base->consumer->audio.out.rate && base->consumer->audio.out.channels) - ? ((base->consumer->audio.ptime * base->consumer->audio.out.rate) / 1000) * base->consumer->audio.out.channels - : TMEDIA_CODEC_PCM_FRAME_SIZE_AUDIO_DECODING(audio->encoder.codec); - uint32_t playback_sampling_rate = (base->consumer && base->consumer->audio.out.rate) - ? base->consumer->audio.out.rate - : TMEDIA_CODEC_RATE_DECODING(audio->encoder.codec); - uint32_t playback_channels = (base->consumer && base->consumer->audio.out.channels) - ? base->consumer->audio.out.channels - : TMEDIA_CODEC_CHANNELS_AUDIO_DECODING(audio->encoder.codec); - - TSK_DEBUG_INFO("Audio denoiser to be opened(record_frame_size_samples=%u, record_sampling_rate=%u, record_channels=%u, playback_frame_size_samples=%u, playback_sampling_rate=%u, playback_channels=%u)", - record_frame_size_samples, record_sampling_rate, record_channels, playback_frame_size_samples, playback_sampling_rate, playback_channels); - - // close() - tmedia_denoise_close(audio->denoise); - // open() with new values - tmedia_denoise_open(audio->denoise, - record_frame_size_samples, record_sampling_rate, TSK_CLAMP(1, record_channels, 2), - playback_frame_size_samples, playback_sampling_rate, TSK_CLAMP(1, playback_channels, 2)); - } - } - - audio->is_started = (ret == 0); - - return ret; + int ret; + tdav_session_audio_t* audio; + const tmedia_codec_t* codec; + tdav_session_av_t* base; + + if (!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + audio = (tdav_session_audio_t*)self; + base = (tdav_session_av_t*)self; + + if (audio->is_started) { + TSK_DEBUG_INFO("Audio session already started"); + return 0; + } + + if (!(codec = tdav_session_av_get_best_neg_codec(base))) { + TSK_DEBUG_ERROR("No codec matched"); + return -2; + } + + TSK_OBJECT_SAFE_FREE(audio->encoder.codec); + audio->encoder.codec = tsk_object_ref((tsk_object_t*)codec); + + if ((ret = tdav_session_av_start(base, codec))) { + TSK_DEBUG_ERROR("tdav_session_av_start(audio) failed"); + return ret; + } + + if (base->rtp_manager) { + /* Denoise (AEC, Noise Suppression, AGC) + * tmedia_denoise_process_record() is called after resampling and before encoding which means sampling rate is equal to codec's rate + * tmedia_denoise_echo_playback() is called before playback which means sampling rate is equal to consumer's rate + */ + if (audio->denoise) { + uint32_t record_frame_size_samples = TMEDIA_CODEC_PCM_FRAME_SIZE_AUDIO_ENCODING(audio->encoder.codec); + uint32_t record_sampling_rate = TMEDIA_CODEC_RATE_ENCODING(audio->encoder.codec); + uint32_t record_channels = TMEDIA_CODEC_CHANNELS_AUDIO_ENCODING(audio->encoder.codec); + + uint32_t playback_frame_size_samples = (base->consumer && base->consumer->audio.ptime && base->consumer->audio.out.rate && base->consumer->audio.out.channels) + ? ((base->consumer->audio.ptime * base->consumer->audio.out.rate) / 1000) * base->consumer->audio.out.channels + : TMEDIA_CODEC_PCM_FRAME_SIZE_AUDIO_DECODING(audio->encoder.codec); + uint32_t playback_sampling_rate = (base->consumer && base->consumer->audio.out.rate) + ? base->consumer->audio.out.rate + : TMEDIA_CODEC_RATE_DECODING(audio->encoder.codec); + uint32_t playback_channels = (base->consumer && base->consumer->audio.out.channels) + ? base->consumer->audio.out.channels + : TMEDIA_CODEC_CHANNELS_AUDIO_DECODING(audio->encoder.codec); + + TSK_DEBUG_INFO("Audio denoiser to be opened(record_frame_size_samples=%u, record_sampling_rate=%u, record_channels=%u, playback_frame_size_samples=%u, playback_sampling_rate=%u, playback_channels=%u)", + record_frame_size_samples, record_sampling_rate, record_channels, playback_frame_size_samples, playback_sampling_rate, playback_channels); + + // close() + tmedia_denoise_close(audio->denoise); + // open() with new values + tmedia_denoise_open(audio->denoise, + record_frame_size_samples, record_sampling_rate, TSK_CLAMP(1, record_channels, 2), + playback_frame_size_samples, playback_sampling_rate, TSK_CLAMP(1, playback_channels, 2)); + } + } + + audio->is_started = (ret == 0); + + return ret; } static int tdav_session_audio_stop(tmedia_session_t* self) { - tdav_session_audio_t* audio = TDAV_SESSION_AUDIO(self); - tdav_session_av_t* base = TDAV_SESSION_AV(self); - int ret = tdav_session_av_stop(base); - audio->is_started = tsk_false; - TSK_OBJECT_SAFE_FREE(audio->encoder.codec); - TSK_OBJECT_SAFE_FREE(audio->decoder.codec); - - // close the jitter buffer and denoiser to be sure it will be reopened and reinitialized if reINVITE or UPDATE - // this is a "must" when the initial and updated sessions use codecs with different rate - if (audio->jitterbuffer && audio->jitterbuffer->opened) { - ret = tmedia_jitterbuffer_close(audio->jitterbuffer); - } - if (audio->denoise && audio->denoise->opened) { - ret = tmedia_denoise_close(audio->denoise); - } - return ret; + tdav_session_audio_t* audio = TDAV_SESSION_AUDIO(self); + tdav_session_av_t* base = TDAV_SESSION_AV(self); + int ret = tdav_session_av_stop(base); + audio->is_started = tsk_false; + TSK_OBJECT_SAFE_FREE(audio->encoder.codec); + TSK_OBJECT_SAFE_FREE(audio->decoder.codec); + + // close the jitter buffer and denoiser to be sure it will be reopened and reinitialized if reINVITE or UPDATE + // this is a "must" when the initial and updated sessions use codecs with different rate + if (audio->jitterbuffer && audio->jitterbuffer->opened) { + ret = tmedia_jitterbuffer_close(audio->jitterbuffer); + } + if (audio->denoise && audio->denoise->opened) { + ret = tmedia_denoise_close(audio->denoise); + } + return ret; } static int tdav_session_audio_send_dtmf(tmedia_session_t* self, uint8_t event) { - tdav_session_audio_t* audio; - tdav_session_av_t* base; - tmedia_codec_t* codec; - int ret, rate = 8000, ptime = 20; - uint16_t duration; - tdav_session_audio_dtmfe_t *dtmfe, *copy; - int format = 101; - - if (!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - audio = (tdav_session_audio_t*)self; - base = (tdav_session_av_t*)self; - - // Find the DTMF codec to use to use the RTP payload - if ((codec = tmedia_codec_find_by_format(TMEDIA_SESSION(audio)->codecs, TMEDIA_CODEC_FORMAT_DTMF))){ - rate = (int)codec->out.rate; - format = atoi(codec->neg_format ? codec->neg_format : codec->format); - TSK_OBJECT_SAFE_FREE(codec); - } - - /* do we have an RTP manager? */ - if (!base->rtp_manager){ - TSK_DEBUG_ERROR("No RTP manager associated to this session"); - return -2; - } - - /* Create Events list */ - if (!audio->dtmf_events){ - audio->dtmf_events = tsk_list_create(); - } - - /* Create global reference to the timer manager */ - if (!audio->timer.handle_mgr_global){ - if (!(audio->timer.handle_mgr_global = tsk_timer_mgr_global_ref())){ - TSK_DEBUG_ERROR("Failed to create Global Timer Manager"); - return -3; - } - } - - /* Start the timer manager */ - if (!audio->timer.started){ - if ((ret = tsk_timer_manager_start(audio->timer.handle_mgr_global))){ - TSK_DEBUG_ERROR("Failed to start Global Timer Manager"); - return ret; - } - audio->timer.started = tsk_true; - } - - - /* RFC 4733 - 5. Examples - - +-------+-----------+------+--------+------+--------+--------+------+ - | Time | Event | M | Time- | Seq | Event | Dura- | E | - | (ms) | | bit | stamp | No | Code | tion | bit | - +-------+-----------+------+--------+------+--------+--------+------+ - | 0 | "9" | | | | | | | - | | starts | | | | | | | - | 50 | RTP | "1" | 0 | 1 | 9 | 400 | "0" | - | | packet 1 | | | | | | | - | | sent | | | | | | | - | 100 | RTP | "0" | 0 | 2 | 9 | 800 | "0" | - | | packet 2 | | | | | | | - | | sent | | | | | | | - | 150 | RTP | "0" | 0 | 3 | 9 | 1200 | "0" | - | | packet 3 | | | | | | | - | | sent | | | | | | | - | 200 | RTP | "0" | 0 | 4 | 9 | 1600 | "0" | - | | packet 4 | | | | | | | - | | sent | | | | | | | - | 200 | "9" ends | | | | | | | - | 250 | RTP | "0" | 0 | 5 | 9 | 1600 | "1" | - | | packet 4 | | | | | | | - | | first | | | | | | | - | | retrans- | | | | | | | - | | mission | | | | | | | - | 300 | RTP | "0" | 0 | 6 | 9 | 1600 | "1" | - | | packet 4 | | | | | | | - | | second | | | | | | | - | | retrans- | | | | | | | - | | mission | | | | | | | - ===================================================================== - | 880 | First "1" | | | | | | | - | | starts | | | | | | | - | 930 | RTP | "1" | 7040 | 7 | 1 | 400 | "0" | - | | packet 5 | | | | | | | - | | sent | | | | | | | - */ - - // ref()(thread safeness) - audio = tsk_object_ref(audio); - - // says we're sending DTMF digits to avoid mixing with audio (SRTP won't let this happen because of senquence numbers) - // flag will be turned OFF when the list is empty - audio->is_sending_dtmf_events = tsk_true; - - duration = TMEDIA_CODEC_PCM_FRAME_SIZE_AUDIO_ENCODING(audio->encoder.codec); - - // lock() list - tsk_list_lock(audio->dtmf_events); - - copy = dtmfe = _tdav_session_audio_dtmfe_create(audio, event, duration * 1, ++base->rtp_manager->rtp.seq_num, base->rtp_manager->rtp.timestamp, (uint8_t)format, tsk_true, tsk_false); - tsk_list_push_back_data(audio->dtmf_events, (void**)&dtmfe); - tsk_timer_mgr_global_schedule(ptime * 0, _tdav_session_audio_dtmfe_timercb, copy); - copy = dtmfe = _tdav_session_audio_dtmfe_create(audio, event, duration * 2, ++base->rtp_manager->rtp.seq_num, base->rtp_manager->rtp.timestamp, (uint8_t)format, tsk_false, tsk_false); - tsk_list_push_back_data(audio->dtmf_events, (void**)&dtmfe); - tsk_timer_mgr_global_schedule(ptime * 1, _tdav_session_audio_dtmfe_timercb, copy); - copy = dtmfe = _tdav_session_audio_dtmfe_create(audio, event, duration * 3, ++base->rtp_manager->rtp.seq_num, base->rtp_manager->rtp.timestamp, (uint8_t)format, tsk_false, tsk_false); - tsk_list_push_back_data(audio->dtmf_events, (void**)&dtmfe); - tsk_timer_mgr_global_schedule(ptime * 2, _tdav_session_audio_dtmfe_timercb, copy); - copy = dtmfe = _tdav_session_audio_dtmfe_create(audio, event, duration * 4, ++base->rtp_manager->rtp.seq_num, base->rtp_manager->rtp.timestamp, (uint8_t)format, tsk_false, tsk_false); - tsk_list_push_back_data(audio->dtmf_events, (void**)&dtmfe); - tsk_timer_mgr_global_schedule(ptime * 3, _tdav_session_audio_dtmfe_timercb, copy); - - copy = dtmfe = _tdav_session_audio_dtmfe_create(audio, event, duration * 4, ++base->rtp_manager->rtp.seq_num, base->rtp_manager->rtp.timestamp, (uint8_t)format, tsk_false, tsk_true); - tsk_list_push_back_data(audio->dtmf_events, (void**)&dtmfe); - tsk_timer_mgr_global_schedule(ptime * 4, _tdav_session_audio_dtmfe_timercb, copy); - copy = dtmfe = _tdav_session_audio_dtmfe_create(audio, event, duration * 4, ++base->rtp_manager->rtp.seq_num, base->rtp_manager->rtp.timestamp, (uint8_t)format, tsk_false, tsk_true); - tsk_list_push_back_data(audio->dtmf_events, (void**)&dtmfe); - tsk_timer_mgr_global_schedule(ptime * 5, _tdav_session_audio_dtmfe_timercb, copy); - - // unlock() list - tsk_list_unlock(audio->dtmf_events); - - // increment timestamp - base->rtp_manager->rtp.timestamp += duration; - - // unref()(thread safeness) - audio = tsk_object_unref(audio); - - return 0; + tdav_session_audio_t* audio; + tdav_session_av_t* base; + tmedia_codec_t* codec; + int ret, rate = 8000, ptime = 20; + uint16_t duration; + tdav_session_audio_dtmfe_t *dtmfe, *copy; + int format = 101; + + if (!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + audio = (tdav_session_audio_t*)self; + base = (tdav_session_av_t*)self; + + // Find the DTMF codec to use to use the RTP payload + if ((codec = tmedia_codec_find_by_format(TMEDIA_SESSION(audio)->codecs, TMEDIA_CODEC_FORMAT_DTMF))) { + rate = (int)codec->out.rate; + format = atoi(codec->neg_format ? codec->neg_format : codec->format); + TSK_OBJECT_SAFE_FREE(codec); + } + + /* do we have an RTP manager? */ + if (!base->rtp_manager) { + TSK_DEBUG_ERROR("No RTP manager associated to this session"); + return -2; + } + + /* Create Events list */ + if (!audio->dtmf_events) { + audio->dtmf_events = tsk_list_create(); + } + + /* Create global reference to the timer manager */ + if (!audio->timer.handle_mgr_global) { + if (!(audio->timer.handle_mgr_global = tsk_timer_mgr_global_ref())) { + TSK_DEBUG_ERROR("Failed to create Global Timer Manager"); + return -3; + } + } + + /* Start the timer manager */ + if (!audio->timer.started) { + if ((ret = tsk_timer_manager_start(audio->timer.handle_mgr_global))) { + TSK_DEBUG_ERROR("Failed to start Global Timer Manager"); + return ret; + } + audio->timer.started = tsk_true; + } + + + /* RFC 4733 - 5. Examples + + +-------+-----------+------+--------+------+--------+--------+------+ + | Time | Event | M | Time- | Seq | Event | Dura- | E | + | (ms) | | bit | stamp | No | Code | tion | bit | + +-------+-----------+------+--------+------+--------+--------+------+ + | 0 | "9" | | | | | | | + | | starts | | | | | | | + | 50 | RTP | "1" | 0 | 1 | 9 | 400 | "0" | + | | packet 1 | | | | | | | + | | sent | | | | | | | + | 100 | RTP | "0" | 0 | 2 | 9 | 800 | "0" | + | | packet 2 | | | | | | | + | | sent | | | | | | | + | 150 | RTP | "0" | 0 | 3 | 9 | 1200 | "0" | + | | packet 3 | | | | | | | + | | sent | | | | | | | + | 200 | RTP | "0" | 0 | 4 | 9 | 1600 | "0" | + | | packet 4 | | | | | | | + | | sent | | | | | | | + | 200 | "9" ends | | | | | | | + | 250 | RTP | "0" | 0 | 5 | 9 | 1600 | "1" | + | | packet 4 | | | | | | | + | | first | | | | | | | + | | retrans- | | | | | | | + | | mission | | | | | | | + | 300 | RTP | "0" | 0 | 6 | 9 | 1600 | "1" | + | | packet 4 | | | | | | | + | | second | | | | | | | + | | retrans- | | | | | | | + | | mission | | | | | | | + ===================================================================== + | 880 | First "1" | | | | | | | + | | starts | | | | | | | + | 930 | RTP | "1" | 7040 | 7 | 1 | 400 | "0" | + | | packet 5 | | | | | | | + | | sent | | | | | | | + */ + + // ref()(thread safeness) + audio = tsk_object_ref(audio); + + // says we're sending DTMF digits to avoid mixing with audio (SRTP won't let this happen because of senquence numbers) + // flag will be turned OFF when the list is empty + audio->is_sending_dtmf_events = tsk_true; + + duration = TMEDIA_CODEC_PCM_FRAME_SIZE_AUDIO_ENCODING(audio->encoder.codec); + + // lock() list + tsk_list_lock(audio->dtmf_events); + + copy = dtmfe = _tdav_session_audio_dtmfe_create(audio, event, duration * 1, ++base->rtp_manager->rtp.seq_num, base->rtp_manager->rtp.timestamp, (uint8_t)format, tsk_true, tsk_false); + tsk_list_push_back_data(audio->dtmf_events, (void**)&dtmfe); + tsk_timer_mgr_global_schedule(ptime * 0, _tdav_session_audio_dtmfe_timercb, copy); + copy = dtmfe = _tdav_session_audio_dtmfe_create(audio, event, duration * 2, ++base->rtp_manager->rtp.seq_num, base->rtp_manager->rtp.timestamp, (uint8_t)format, tsk_false, tsk_false); + tsk_list_push_back_data(audio->dtmf_events, (void**)&dtmfe); + tsk_timer_mgr_global_schedule(ptime * 1, _tdav_session_audio_dtmfe_timercb, copy); + copy = dtmfe = _tdav_session_audio_dtmfe_create(audio, event, duration * 3, ++base->rtp_manager->rtp.seq_num, base->rtp_manager->rtp.timestamp, (uint8_t)format, tsk_false, tsk_false); + tsk_list_push_back_data(audio->dtmf_events, (void**)&dtmfe); + tsk_timer_mgr_global_schedule(ptime * 2, _tdav_session_audio_dtmfe_timercb, copy); + copy = dtmfe = _tdav_session_audio_dtmfe_create(audio, event, duration * 4, ++base->rtp_manager->rtp.seq_num, base->rtp_manager->rtp.timestamp, (uint8_t)format, tsk_false, tsk_false); + tsk_list_push_back_data(audio->dtmf_events, (void**)&dtmfe); + tsk_timer_mgr_global_schedule(ptime * 3, _tdav_session_audio_dtmfe_timercb, copy); + + copy = dtmfe = _tdav_session_audio_dtmfe_create(audio, event, duration * 4, ++base->rtp_manager->rtp.seq_num, base->rtp_manager->rtp.timestamp, (uint8_t)format, tsk_false, tsk_true); + tsk_list_push_back_data(audio->dtmf_events, (void**)&dtmfe); + tsk_timer_mgr_global_schedule(ptime * 4, _tdav_session_audio_dtmfe_timercb, copy); + copy = dtmfe = _tdav_session_audio_dtmfe_create(audio, event, duration * 4, ++base->rtp_manager->rtp.seq_num, base->rtp_manager->rtp.timestamp, (uint8_t)format, tsk_false, tsk_true); + tsk_list_push_back_data(audio->dtmf_events, (void**)&dtmfe); + tsk_timer_mgr_global_schedule(ptime * 5, _tdav_session_audio_dtmfe_timercb, copy); + + // unlock() list + tsk_list_unlock(audio->dtmf_events); + + // increment timestamp + base->rtp_manager->rtp.timestamp += duration; + + // unref()(thread safeness) + audio = tsk_object_unref(audio); + + return 0; } static int tdav_session_audio_pause(tmedia_session_t* self) { - return tdav_session_av_pause(TDAV_SESSION_AV(self)); + return tdav_session_av_pause(TDAV_SESSION_AV(self)); } static const tsdp_header_M_t* tdav_session_audio_get_lo(tmedia_session_t* self) { - tsk_bool_t updated = tsk_false; - const tsdp_header_M_t* ret; - tdav_session_av_t* base = TDAV_SESSION_AV(self); + tsk_bool_t updated = tsk_false; + const tsdp_header_M_t* ret; + tdav_session_av_t* base = TDAV_SESSION_AV(self); - if (!(ret = tdav_session_av_get_lo(base, &updated))){ - TSK_DEBUG_ERROR("tdav_session_av_get_lo(audio) failed"); - return tsk_null; - } + if (!(ret = tdav_session_av_get_lo(base, &updated))) { + TSK_DEBUG_ERROR("tdav_session_av_get_lo(audio) failed"); + return tsk_null; + } - if (updated){ - tsk_safeobj_lock(base); - TSK_OBJECT_SAFE_FREE(TDAV_SESSION_AUDIO(self)->encoder.codec); - tsk_safeobj_unlock(base); - } + if (updated) { + tsk_safeobj_lock(base); + TSK_OBJECT_SAFE_FREE(TDAV_SESSION_AUDIO(self)->encoder.codec); + tsk_safeobj_unlock(base); + } - return ret; + return ret; } static int tdav_session_audio_set_ro(tmedia_session_t* self, const tsdp_header_M_t* m) { - int ret; - tsk_bool_t updated = tsk_false; - tdav_session_av_t* base = TDAV_SESSION_AV(self); - - if ((ret = tdav_session_av_set_ro(base, m, &updated))){ - TSK_DEBUG_ERROR("tdav_session_av_set_ro(audio) failed"); - return ret; - } - - if (updated) { - tsk_safeobj_lock(base); - // reset audio jitter buffer (new Offer probably comes with new seq_nums or timestamps) - if (base->consumer) { - ret = tdav_consumer_audio_reset(TDAV_CONSUMER_AUDIO(base->consumer)); - } - // destroy encoder to force requesting new one - TSK_OBJECT_SAFE_FREE(TDAV_SESSION_AUDIO(self)->encoder.codec); - tsk_safeobj_unlock(base); - } - - return ret; + int ret; + tsk_bool_t updated = tsk_false; + tdav_session_av_t* base = TDAV_SESSION_AV(self); + + if ((ret = tdav_session_av_set_ro(base, m, &updated))) { + TSK_DEBUG_ERROR("tdav_session_av_set_ro(audio) failed"); + return ret; + } + + if (updated) { + tsk_safeobj_lock(base); + // reset audio jitter buffer (new Offer probably comes with new seq_nums or timestamps) + if (base->consumer) { + ret = tdav_consumer_audio_reset(TDAV_CONSUMER_AUDIO(base->consumer)); + } + // destroy encoder to force requesting new one + TSK_OBJECT_SAFE_FREE(TDAV_SESSION_AUDIO(self)->encoder.codec); + tsk_safeobj_unlock(base); + } + + return ret; } /* apply gain */ static void _tdav_session_audio_apply_gain(void* buffer, int len, int bps, int gain) { - register int i; - int max_val; - - max_val = (1 << (bps - 1 - gain)) - 1; - - if (bps == 8) { - int8_t *buff = buffer; - for (i = 0; i < len; i++) { - if (buff[i] > -max_val && buff[i] < max_val) - buff[i] = buff[i] << gain; - } - } - else if (bps == 16) { - int16_t *buff = buffer; - for (i = 0; i < len / 2; i++) { - if (buff[i] > -max_val && buff[i] < max_val) - buff[i] = buff[i] << gain; - } - } + register int i; + int max_val; + + max_val = (1 << (bps - 1 - gain)) - 1; + + if (bps == 8) { + int8_t *buff = buffer; + for (i = 0; i < len; i++) { + if (buff[i] > -max_val && buff[i] < max_val) { + buff[i] = buff[i] << gain; + } + } + } + else if (bps == 16) { + int16_t *buff = buffer; + for (i = 0; i < len / 2; i++) { + if (buff[i] > -max_val && buff[i] < max_val) { + buff[i] = buff[i] << gain; + } + } + } } /* Internal function used to create new DTMF event */ static tdav_session_audio_dtmfe_t* _tdav_session_audio_dtmfe_create(const tdav_session_audio_t* session, uint8_t event, uint16_t duration, uint32_t seq, uint32_t timestamp, uint8_t format, tsk_bool_t M, tsk_bool_t E) { - tdav_session_audio_dtmfe_t* dtmfe; - const tdav_session_av_t* base = (const tdav_session_av_t*)session; - static uint8_t volume = 10; - static uint32_t ssrc = 0x5234A8; - - uint8_t pay[4] = { 0 }; - - /* RFC 4733 - 2.3. Payload Format - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | event |E|R| volume | duration | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - - if (!(dtmfe = tsk_object_new(tdav_session_audio_dtmfe_def_t))){ - TSK_DEBUG_ERROR("Failed to create new DTMF event"); - return tsk_null; - } - dtmfe->session = session; - - if (!(dtmfe->packet = trtp_rtp_packet_create((session && base->rtp_manager) ? base->rtp_manager->rtp.ssrc.local : ssrc, seq, timestamp, format, M))){ - TSK_DEBUG_ERROR("Failed to create DTMF RTP packet"); - TSK_OBJECT_SAFE_FREE(dtmfe); - return tsk_null; - } - - pay[0] = event; - pay[1] |= ((E << 7) | (volume & 0x3F)); - pay[2] = (duration >> 8); - pay[3] = (duration & 0xFF); - - /* set data */ - if ((dtmfe->packet->payload.data = tsk_calloc(sizeof(pay), sizeof(uint8_t)))){ - memcpy(dtmfe->packet->payload.data, pay, sizeof(pay)); - dtmfe->packet->payload.size = sizeof(pay); - } - - return dtmfe; + tdav_session_audio_dtmfe_t* dtmfe; + const tdav_session_av_t* base = (const tdav_session_av_t*)session; + static uint8_t volume = 10; + static uint32_t ssrc = 0x5234A8; + + uint8_t pay[4] = { 0 }; + + /* RFC 4733 - 2.3. Payload Format + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | event |E|R| volume | duration | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + if (!(dtmfe = tsk_object_new(tdav_session_audio_dtmfe_def_t))) { + TSK_DEBUG_ERROR("Failed to create new DTMF event"); + return tsk_null; + } + dtmfe->session = session; + + if (!(dtmfe->packet = trtp_rtp_packet_create((session && base->rtp_manager) ? base->rtp_manager->rtp.ssrc.local : ssrc, seq, timestamp, format, M))) { + TSK_DEBUG_ERROR("Failed to create DTMF RTP packet"); + TSK_OBJECT_SAFE_FREE(dtmfe); + return tsk_null; + } + + pay[0] = event; + pay[1] |= ((E << 7) | (volume & 0x3F)); + pay[2] = (duration >> 8); + pay[3] = (duration & 0xFF); + + /* set data */ + if ((dtmfe->packet->payload.data = tsk_calloc(sizeof(pay), sizeof(uint8_t)))) { + memcpy(dtmfe->packet->payload.data, pay, sizeof(pay)); + dtmfe->packet->payload.size = sizeof(pay); + } + + return dtmfe; } static int _tdav_session_audio_dtmfe_timercb(const void* arg, tsk_timer_id_t timer_id) { - tdav_session_audio_dtmfe_t* dtmfe = (tdav_session_audio_dtmfe_t*)arg; - tdav_session_audio_t *audio; + tdav_session_audio_dtmfe_t* dtmfe = (tdav_session_audio_dtmfe_t*)arg; + tdav_session_audio_t *audio; - if (!dtmfe || !dtmfe->session || !dtmfe->session->dtmf_events){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } + if (!dtmfe || !dtmfe->session || !dtmfe->session->dtmf_events) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } - /* Send the data */ - TSK_DEBUG_INFO("Sending DTMF event..."); - trtp_manager_send_rtp_packet(TDAV_SESSION_AV(dtmfe->session)->rtp_manager, dtmfe->packet, tsk_false); + /* Send the data */ + TSK_DEBUG_INFO("Sending DTMF event..."); + trtp_manager_send_rtp_packet(TDAV_SESSION_AV(dtmfe->session)->rtp_manager, dtmfe->packet, tsk_false); - audio = tsk_object_ref(TSK_OBJECT(dtmfe->session)); - tsk_list_lock(audio->dtmf_events); - /* Remove and delete the event from the queue */ - tsk_list_remove_item_by_data(audio->dtmf_events, dtmfe); - /* Check if there are pending events */ - audio->is_sending_dtmf_events = !TSK_LIST_IS_EMPTY(audio->dtmf_events); - tsk_list_unlock(audio->dtmf_events); - tsk_object_unref(audio); + audio = tsk_object_ref(TSK_OBJECT(dtmfe->session)); + tsk_list_lock(audio->dtmf_events); + /* Remove and delete the event from the queue */ + tsk_list_remove_item_by_data(audio->dtmf_events, dtmfe); + /* Check if there are pending events */ + audio->is_sending_dtmf_events = !TSK_LIST_IS_EMPTY(audio->dtmf_events); + tsk_list_unlock(audio->dtmf_events); + tsk_object_unref(audio); - return 0; + return 0; } static tmedia_resampler_t* _tdav_session_audio_resampler_create(int32_t bytes_per_sample, uint32_t in_freq, uint32_t out_freq, uint32_t frame_duration, uint32_t in_channels, uint32_t out_channels, uint32_t quality, void** resampler_buffer, tsk_size_t *resampler_buffer_size) { - uint32_t resampler_buff_size; - tmedia_resampler_t* resampler; - int ret; - - if (out_channels > 2 || in_channels > 2) { - TSK_DEBUG_ERROR("Invalid parameter: out_channels=%u, in_channels=%u", out_channels, in_channels); - return tsk_null; - } - - resampler_buff_size = (((out_freq * frame_duration) / 1000) * bytes_per_sample) << (out_channels == 2 ? 1 : 0); - - if (!(resampler = tmedia_resampler_create())) { - TSK_DEBUG_ERROR("Failed to create audio resampler"); - return tsk_null; - } - else { - if ((ret = tmedia_resampler_open(resampler, in_freq, out_freq, frame_duration, in_channels, out_channels, quality, 16))) { - TSK_DEBUG_ERROR("Failed to open audio resampler (%d, %d, %d, %d, %d,%d) with retcode=%d", in_freq, out_freq, frame_duration, in_channels, out_channels, quality, ret); - TSK_OBJECT_SAFE_FREE(resampler); - goto done; - } - } - // create temp resampler buffer - if ((*resampler_buffer = tsk_realloc(*resampler_buffer, resampler_buff_size))) { - *resampler_buffer_size = resampler_buff_size; - } - else { - *resampler_buffer_size = 0; - TSK_DEBUG_ERROR("Failed to allocate resampler buffer with size = %d", resampler_buff_size); - TSK_OBJECT_SAFE_FREE(resampler); - goto done; - } + uint32_t resampler_buff_size; + tmedia_resampler_t* resampler; + int ret; + + if (out_channels > 2 || in_channels > 2) { + TSK_DEBUG_ERROR("Invalid parameter: out_channels=%u, in_channels=%u", out_channels, in_channels); + return tsk_null; + } + + resampler_buff_size = (((out_freq * frame_duration) / 1000) * bytes_per_sample) << (out_channels == 2 ? 1 : 0); + + if (!(resampler = tmedia_resampler_create())) { + TSK_DEBUG_ERROR("Failed to create audio resampler"); + return tsk_null; + } + else { + if ((ret = tmedia_resampler_open(resampler, in_freq, out_freq, frame_duration, in_channels, out_channels, quality, 16))) { + TSK_DEBUG_ERROR("Failed to open audio resampler (%d, %d, %d, %d, %d,%d) with retcode=%d", in_freq, out_freq, frame_duration, in_channels, out_channels, quality, ret); + TSK_OBJECT_SAFE_FREE(resampler); + goto done; + } + } + // create temp resampler buffer + if ((*resampler_buffer = tsk_realloc(*resampler_buffer, resampler_buff_size))) { + *resampler_buffer_size = resampler_buff_size; + } + else { + *resampler_buffer_size = 0; + TSK_DEBUG_ERROR("Failed to allocate resampler buffer with size = %d", resampler_buff_size); + TSK_OBJECT_SAFE_FREE(resampler); + goto done; + } done: - return resampler; + return resampler; } //================================================================================================= @@ -811,142 +812,139 @@ done: /* constructor */ static tsk_object_t* tdav_session_audio_ctor(tsk_object_t * self, va_list * app) { - tdav_session_audio_t *audio = self; - if (audio){ - int ret; - tdav_session_av_t *base = TDAV_SESSION_AV(self); - - /* init() base */ - if ((ret = tdav_session_av_init(base, tmedia_audio)) != 0){ - TSK_DEBUG_ERROR("tdav_session_av_init(audio) failed"); - return tsk_null; - } - - /* init() self */ - if (base->producer){ - tmedia_producer_set_enc_callback(base->producer, tdav_session_audio_producer_enc_cb, audio); - } - if (base->consumer){ - // It's important to create the denoiser and jitter buffer here as dynamic plugins (from shared libs) don't have access to the registry - if (!(audio->denoise = tmedia_denoise_create())){ - TSK_DEBUG_WARN("No Audio denoiser found"); - } - else{ - // IMPORTANT: This means that the consumer must be child of "tdav_consumer_audio_t" object - tdav_consumer_audio_set_denoise(TDAV_CONSUMER_AUDIO(base->consumer), audio->denoise); - } - - if (!(audio->jitterbuffer = tmedia_jitterbuffer_create(tmedia_audio))){ - TSK_DEBUG_ERROR("Failed to create jitter buffer"); - } - else{ - ret = tmedia_jitterbuffer_init(TMEDIA_JITTER_BUFFER(audio->jitterbuffer)); - tdav_consumer_audio_set_jitterbuffer(TDAV_CONSUMER_AUDIO(base->consumer), audio->jitterbuffer); - } - } - } - return self; + tdav_session_audio_t *audio = self; + if (audio) { + int ret; + tdav_session_av_t *base = TDAV_SESSION_AV(self); + + /* init() base */ + if ((ret = tdav_session_av_init(base, tmedia_audio)) != 0) { + TSK_DEBUG_ERROR("tdav_session_av_init(audio) failed"); + return tsk_null; + } + + /* init() self */ + if (base->producer) { + tmedia_producer_set_enc_callback(base->producer, tdav_session_audio_producer_enc_cb, audio); + } + if (base->consumer) { + // It's important to create the denoiser and jitter buffer here as dynamic plugins (from shared libs) don't have access to the registry + if (!(audio->denoise = tmedia_denoise_create())) { + TSK_DEBUG_WARN("No Audio denoiser found"); + } + else { + // IMPORTANT: This means that the consumer must be child of "tdav_consumer_audio_t" object + tdav_consumer_audio_set_denoise(TDAV_CONSUMER_AUDIO(base->consumer), audio->denoise); + } + + if (!(audio->jitterbuffer = tmedia_jitterbuffer_create(tmedia_audio))) { + TSK_DEBUG_ERROR("Failed to create jitter buffer"); + } + else { + ret = tmedia_jitterbuffer_init(TMEDIA_JITTER_BUFFER(audio->jitterbuffer)); + tdav_consumer_audio_set_jitterbuffer(TDAV_CONSUMER_AUDIO(base->consumer), audio->jitterbuffer); + } + } + } + return self; } /* destructor */ static tsk_object_t* tdav_session_audio_dtor(tsk_object_t * self) { - tdav_session_audio_t *audio = self; - TSK_DEBUG_INFO("*** tdav_session_audio_t destroyed ***"); - if (audio){ - tdav_session_audio_stop((tmedia_session_t*)audio); - // Do it in this order (deinit self first) - - /* Timer manager */ - if (audio->timer.started){ - if (audio->dtmf_events){ - /* Cancel all events */ - tsk_list_item_t* item; - tsk_list_foreach(item, audio->dtmf_events){ - tsk_timer_mgr_global_cancel(((tdav_session_audio_dtmfe_t*)item->data)->timer_id); - } - } - } - - tsk_timer_mgr_global_unref(&audio->timer.handle_mgr_global); - - /* CleanUp the DTMF events */ - TSK_OBJECT_SAFE_FREE(audio->dtmf_events); - - TSK_OBJECT_SAFE_FREE(audio->denoise); - TSK_OBJECT_SAFE_FREE(audio->jitterbuffer); - - TSK_OBJECT_SAFE_FREE(audio->encoder.codec); - TSK_FREE(audio->encoder.buffer); - TSK_OBJECT_SAFE_FREE(audio->decoder.codec); - TSK_FREE(audio->decoder.buffer); - - // free resamplers - TSK_FREE(audio->encoder.resampler.buffer); - TSK_OBJECT_SAFE_FREE(audio->encoder.resampler.instance); - TSK_FREE(audio->decoder.resampler.buffer); - TSK_OBJECT_SAFE_FREE(audio->decoder.resampler.instance); - - /* deinit base */ - tdav_session_av_deinit(TDAV_SESSION_AV(self)); - - TSK_DEBUG_INFO("*** Audio session destroyed ***"); - } - - return self; + tdav_session_audio_t *audio = self; + TSK_DEBUG_INFO("*** tdav_session_audio_t destroyed ***"); + if (audio) { + tdav_session_audio_stop((tmedia_session_t*)audio); + // Do it in this order (deinit self first) + + /* Timer manager */ + if (audio->timer.started) { + if (audio->dtmf_events) { + /* Cancel all events */ + tsk_list_item_t* item; + tsk_list_foreach(item, audio->dtmf_events) { + tsk_timer_mgr_global_cancel(((tdav_session_audio_dtmfe_t*)item->data)->timer_id); + } + } + } + + tsk_timer_mgr_global_unref(&audio->timer.handle_mgr_global); + + /* CleanUp the DTMF events */ + TSK_OBJECT_SAFE_FREE(audio->dtmf_events); + + TSK_OBJECT_SAFE_FREE(audio->denoise); + TSK_OBJECT_SAFE_FREE(audio->jitterbuffer); + + TSK_OBJECT_SAFE_FREE(audio->encoder.codec); + TSK_FREE(audio->encoder.buffer); + TSK_OBJECT_SAFE_FREE(audio->decoder.codec); + TSK_FREE(audio->decoder.buffer); + + // free resamplers + TSK_FREE(audio->encoder.resampler.buffer); + TSK_OBJECT_SAFE_FREE(audio->encoder.resampler.instance); + TSK_FREE(audio->decoder.resampler.buffer); + TSK_OBJECT_SAFE_FREE(audio->decoder.resampler.instance); + + /* deinit base */ + tdav_session_av_deinit(TDAV_SESSION_AV(self)); + + TSK_DEBUG_INFO("*** Audio session destroyed ***"); + } + + return self; } /* object definition */ -static const tsk_object_def_t tdav_session_audio_def_s = -{ - sizeof(tdav_session_audio_t), - tdav_session_audio_ctor, - tdav_session_audio_dtor, - tmedia_session_cmp, +static const tsk_object_def_t tdav_session_audio_def_s = { + sizeof(tdav_session_audio_t), + tdav_session_audio_ctor, + tdav_session_audio_dtor, + tmedia_session_cmp, }; /* plugin definition*/ -static const tmedia_session_plugin_def_t tdav_session_audio_plugin_def_s = -{ - &tdav_session_audio_def_s, - - tmedia_audio, - "audio", - - tdav_session_audio_set, - tdav_session_audio_get, - tdav_session_audio_prepare, - tdav_session_audio_start, - tdav_session_audio_pause, - tdav_session_audio_stop, - - /* Audio part */ - { - tdav_session_audio_send_dtmf - }, - - tdav_session_audio_get_lo, - tdav_session_audio_set_ro +static const tmedia_session_plugin_def_t tdav_session_audio_plugin_def_s = { + &tdav_session_audio_def_s, + + tmedia_audio, + "audio", + + tdav_session_audio_set, + tdav_session_audio_get, + tdav_session_audio_prepare, + tdav_session_audio_start, + tdav_session_audio_pause, + tdav_session_audio_stop, + + /* Audio part */ + { + tdav_session_audio_send_dtmf + }, + + tdav_session_audio_get_lo, + tdav_session_audio_set_ro }; const tmedia_session_plugin_def_t *tdav_session_audio_plugin_def_t = &tdav_session_audio_plugin_def_s; -static const tmedia_session_plugin_def_t tdav_session_bfcpaudio_plugin_def_s = -{ - &tdav_session_audio_def_s, - - tmedia_bfcp_audio, - "audio", - - tdav_session_audio_set, - tdav_session_audio_get, - tdav_session_audio_prepare, - tdav_session_audio_start, - tdav_session_audio_pause, - tdav_session_audio_stop, - - /* Audio part */ - { - tdav_session_audio_send_dtmf - }, - - tdav_session_audio_get_lo, - tdav_session_audio_set_ro +static const tmedia_session_plugin_def_t tdav_session_bfcpaudio_plugin_def_s = { + &tdav_session_audio_def_s, + + tmedia_bfcp_audio, + "audio", + + tdav_session_audio_set, + tdav_session_audio_get, + tdav_session_audio_prepare, + tdav_session_audio_start, + tdav_session_audio_pause, + tdav_session_audio_stop, + + /* Audio part */ + { + tdav_session_audio_send_dtmf + }, + + tdav_session_audio_get_lo, + tdav_session_audio_set_ro }; const tmedia_session_plugin_def_t *tdav_session_bfcpaudio_plugin_def_t = &tdav_session_bfcpaudio_plugin_def_s; @@ -957,35 +955,34 @@ const tmedia_session_plugin_def_t *tdav_session_bfcpaudio_plugin_def_t = &tdav_s // static tsk_object_t* tdav_session_audio_dtmfe_ctor(tsk_object_t * self, va_list * app) { - tdav_session_audio_dtmfe_t *event = self; - if (event){ - event->timer_id = TSK_INVALID_TIMER_ID; - } - return self; + tdav_session_audio_dtmfe_t *event = self; + if (event) { + event->timer_id = TSK_INVALID_TIMER_ID; + } + return self; } static tsk_object_t* tdav_session_audio_dtmfe_dtor(tsk_object_t * self) { - tdav_session_audio_dtmfe_t *event = self; - if (event){ - TSK_OBJECT_SAFE_FREE(event->packet); - } + tdav_session_audio_dtmfe_t *event = self; + if (event) { + TSK_OBJECT_SAFE_FREE(event->packet); + } - return self; + return self; } static int tdav_session_audio_dtmfe_cmp(const tsk_object_t *_e1, const tsk_object_t *_e2) { - int ret; - tsk_subsat_int32_ptr(_e1, _e2, &ret); - return ret; + int ret; + tsk_subsat_int32_ptr(_e1, _e2, &ret); + return ret; } -static const tsk_object_def_t tdav_session_audio_dtmfe_def_s = -{ - sizeof(tdav_session_audio_dtmfe_t), - tdav_session_audio_dtmfe_ctor, - tdav_session_audio_dtmfe_dtor, - tdav_session_audio_dtmfe_cmp, +static const tsk_object_def_t tdav_session_audio_dtmfe_def_s = { + sizeof(tdav_session_audio_dtmfe_t), + tdav_session_audio_dtmfe_ctor, + tdav_session_audio_dtmfe_dtor, + tdav_session_audio_dtmfe_cmp, }; const tsk_object_def_t *tdav_session_audio_dtmfe_def_t = &tdav_session_audio_dtmfe_def_s; -- cgit v1.1