doubango/tinyDAV/src/audio/tdav_speex_jitterbuffer.c
c732d49e
 #if HAVE_CRT
 #define _CRTDBG_MAP_ALLOC 
 #include <stdlib.h> 
 #include <crtdbg.h>
 #endif //HAVE_CRT
 /*
 * Copyright (C) 2017, University of the Basque Country (UPV/EHU)
 * Contact for licensing options: <licensing-mcpttclient(at)mcopenplatform(dot)com>
 *
 * The original file was part of Open Source Doubango Framework
 * Copyright (C) 2010-2011 Mamadou Diop.
 * Copyright (C) 2012 Doubango Telecom <http://doubango.org>
 *
 * This file is part of Open Source Doubango Framework.
 *
 * DOUBANGO is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * DOUBANGO is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with DOUBANGO.
 *
 */
 
 
 /**@file tdav_speex_jitterbuffer.c
  * @brief Speex Audio jitterbuffer Plugin
  */
 #include "tinydav/audio/tdav_speex_jitterbuffer.h"
 #include "tinyrtp/rtp/trtp_rtp_header.h"
 
 #if HAVE_SPEEX_DSP && HAVE_SPEEX_JB
 
 // rfc3551 - 4.5 Audio Encodings: all frames length are multiple of 10ms
 
 #include "tinymedia/tmedia_defaults.h"
 
 #include "tsk_memory.h"
 #include "tsk_debug.h"
 
 #include <speex/speex_jitter.h>
 
 /** Speex JitterBuffer*/
 typedef struct tdav_speex_jitterBuffer_s
 {
 	TMEDIA_DECLARE_JITTER_BUFFER;
 
 	JitterBuffer* state;
 	uint32_t rate;
 	uint32_t frame_duration;
 	uint32_t channels;
 	uint32_t x_data_size; // expected data size
 	uint16_t fake_seqnum; // if ptime mismatch then, reassembled pkt will have invalid seqnum
 	struct {
 		uint8_t* ptr;
 		tsk_size_t size;
 		tsk_size_t index;
 	} buff;
 
 	uint64_t num_pkt_in; // Number of incoming pkts since the last reset
 	uint64_t num_pkt_miss; // Number of times we got consecutive "JITTER_BUFFER_MISSING" results
 	uint64_t num_pkt_miss_max; // Max value for "num_pkt_miss" before reset()ing the jitter buffer
 }
 tdav_speex_jitterbuffer_t;
 
 static int tdav_speex_jitterbuffer_set(tmedia_jitterbuffer_t *self, const tmedia_param_t* param)
 {
 	TSK_DEBUG_ERROR("Not implemented");
 	return -2;
 }
 
 static int tdav_speex_jitterbuffer_open(tmedia_jitterbuffer_t* self, uint32_t frame_duration, uint32_t rate, uint32_t channels)
 {
 	tdav_speex_jitterbuffer_t *jitterbuffer = (tdav_speex_jitterbuffer_t *)self;
 	spx_int32_t tmp;
175b478c
 	int auto_adjust=1;
 	int buffer_size=200;
c732d49e
 	TSK_DEBUG_INFO("Open speex jb (ptime=%u, rate=%u)", frame_duration, rate);
 
175b478c
 	if (!(jitterbuffer->state = jitter_buffer_init((int)frame_duration,auto_adjust/*,buffer_size*/))) {
c732d49e
 		TSK_DEBUG_ERROR("jitter_buffer_init() failed");
 		return -2;
 	}
175b478c
 
c732d49e
 	jitterbuffer->rate = rate;
 	jitterbuffer->frame_duration = frame_duration;
 	jitterbuffer->channels = channels;
 	jitterbuffer->x_data_size = ((frame_duration * jitterbuffer->rate) / 500) << (channels == 2 ? 1 : 0);
 
 	jitterbuffer->num_pkt_in = 0;
 	jitterbuffer->num_pkt_miss = 0;
 	jitterbuffer->num_pkt_miss_max = (1000 / frame_duration) * 2; // 2 seconds missing --> "Houston, we have a problem"
 
 	jitter_buffer_ctl(jitterbuffer->state, JITTER_BUFFER_GET_MARGIN, &tmp);
 	TSK_DEBUG_INFO("Default Jitter buffer margin=%d", tmp);
 	jitter_buffer_ctl(jitterbuffer->state, JITTER_BUFFER_GET_MAX_LATE_RATE, &tmp);
 	TSK_DEBUG_INFO("Default Jitter max late rate=%d", tmp);
 
 	if ((tmp = tmedia_defaults_get_jb_margin()) >= 0) {
 		jitter_buffer_ctl(jitterbuffer->state, JITTER_BUFFER_SET_MARGIN, &tmp);
 		TSK_DEBUG_INFO("New Jitter buffer margin=%d", tmp);
 	}
 	if ((tmp = tmedia_defaults_get_jb_max_late_rate()) >= 0) {
 		jitter_buffer_ctl(jitterbuffer->state, JITTER_BUFFER_SET_MAX_LATE_RATE, &tmp);
 		TSK_DEBUG_INFO("New Jitter buffer max late rate=%d", tmp);
 	}
 
175b478c
 
c732d49e
 	return 0;
 }
 
 static int tdav_speex_jitterbuffer_tick(tmedia_jitterbuffer_t* self)
 {
 	tdav_speex_jitterbuffer_t *jitterbuffer = (tdav_speex_jitterbuffer_t *)self;
 	if (!jitterbuffer->state) {
 		TSK_DEBUG_ERROR("Invalid state");
 		return -1;
 	}
 	jitter_buffer_tick(jitterbuffer->state);
 	return 0;
 }
 
 static int tdav_speex_jitterbuffer_put(tmedia_jitterbuffer_t* self, void* data, tsk_size_t data_size, const tsk_object_t* proto_hdr)
 {
 	tdav_speex_jitterbuffer_t *jb = (tdav_speex_jitterbuffer_t *)self;
 	const trtp_rtp_header_t* rtp_hdr;
 	JitterBufferPacket jb_packet;
 	static uint16_t seq_num = 0;
 
 	if (!data || !data_size || !proto_hdr) {
 		TSK_DEBUG_ERROR("Invalid parameter");
 		return -1;
 	}
 
 	if (!jb->state) {
 		TSK_DEBUG_ERROR("Invalid state");
 		return -2;
 	}
 
 	rtp_hdr = TRTP_RTP_HEADER(proto_hdr);
 
 	jb_packet.user_data = 0;
 	jb_packet.span = jb->frame_duration;
 	jb_packet.len = jb->x_data_size;
 
 	if (jb->x_data_size == data_size) { /* ptime match */
 		jb_packet.data = data;
 		jb_packet.sequence = rtp_hdr->seq_num;
 		jb_packet.timestamp = (rtp_hdr->seq_num * jb_packet.span);
 		jitter_buffer_put(jb->state, &jb_packet);
 	}
 	else { /* ptime mismatch */
 		tsk_size_t i;
 		jb_packet.sequence = 0; // Ignore
 		if ((jb->buff.index + data_size) > jb->buff.size) {
 			if (!(jb->buff.ptr = tsk_realloc(jb->buff.ptr, (jb->buff.index + data_size)))) {
 				jb->buff.size = 0;
 				jb->buff.index = 0;
 				return 0;
 			}
 			jb->buff.size = (jb->buff.index + data_size);
 		}
 
 		memcpy(&jb->buff.ptr[jb->buff.index], data, data_size);
 		jb->buff.index += data_size;
 
 		if (jb->buff.index >= jb->x_data_size) {
 			tsk_size_t copied = 0;
 			for (i = 0; (i + jb->x_data_size) <= jb->buff.index; i += jb->x_data_size) {
 				jb_packet.data = (char*)&jb->buff.ptr[i];
 				jb_packet.timestamp = (++jb->fake_seqnum * jb_packet.span);// reassembled pkt will have fake seqnum
 				jitter_buffer_put(jb->state, &jb_packet);
 				copied += jb->x_data_size;
 			}
 			if (copied == jb->buff.index) {
 				// all copied
 				jb->buff.index = 0;
 			}
 			else {
 				memmove(&jb->buff.ptr[0], &jb->buff.ptr[copied], (jb->buff.index - copied));
 				jb->buff.index -= copied;
 			}
 		}
 	}
 	++jb->num_pkt_in;
 
 	return 0;
 }
 
 static tsk_size_t tdav_speex_jitterbuffer_get(tmedia_jitterbuffer_t* self, void* out_data, tsk_size_t out_size)
 {
 	tdav_speex_jitterbuffer_t *jb = (tdav_speex_jitterbuffer_t *)self;
 	JitterBufferPacket jb_packet;
 	int ret, miss = 0;
 	tsk_size_t ret_size = 0;
 
175b478c
 
c732d49e
 	if (!out_data || !out_size) {
 		TSK_DEBUG_ERROR("Invalid parameter");
 		return 0;
 	}
 	if (!jb->state) {
 		TSK_DEBUG_ERROR("Invalid state");
 		return 0;
 	}
 	if (jb->x_data_size != out_size) { // consumer must request PTIME data
 		TSK_DEBUG_WARN("%d not expected as frame size. %u<>%u", out_size, jb->frame_duration, (out_size * 500) / jb->rate);
 		return 0;
 	}
 
 	jb_packet.data = out_data;
 	jb_packet.len = (spx_uint32_t)out_size;
175b478c
 	ret = jitter_buffer_get(jb->state, &jb_packet, jb->frame_duration/*(out_size * 500)/jb->rate*/, tsk_null);
 
c732d49e
 
175b478c
 	if (ret != JITTER_BUFFER_OK) {
c732d49e
 		++jb->num_pkt_miss;
 		switch (ret) {
 		case JITTER_BUFFER_MISSING:
 			/*TSK_DEBUG_INFO("JITTER_BUFFER_MISSING - %d", ret);*/
 			if (jb->num_pkt_miss > jb->num_pkt_miss_max /*too much missing pkts*/ && jb->num_pkt_in > jb->num_pkt_miss_max/*we're really receiving pkts*/) {
 				jb->num_pkt_miss = 0;
 				self->plugin->reset(self);
 				TSK_DEBUG_WARN("Too much missing audio pkts");
 			}
 			break;
 		case JITTER_BUFFER_INSERTION:
 			/*TSK_DEBUG_INFO("JITTER_BUFFER_INSERTION - %d", ret);*/
 			break;
 		default:
 			TSK_DEBUG_INFO("jitter_buffer_get() failed - %d", ret);
 			break;
 		}
 		// jitter_buffer_update_delay(jb->state, &jb_packet, NULL);
 		//return 0;
 	}
 	else {
 		jb->num_pkt_miss = 0; // reset
 		ret_size = jb_packet.len;
 	}
 	//jitter_buffer_update_delay(jb->state, &jb_packet, NULL);
 
 	return ret_size;
 }
 
 static int tdav_speex_jitterbuffer_reset(tmedia_jitterbuffer_t* self)
 {
 	tdav_speex_jitterbuffer_t *jb = (tdav_speex_jitterbuffer_t *)self;
 	if (jb->state) {
 		jitter_buffer_reset(jb->state);
 	}
 	jb->num_pkt_in = 0;
 	jb->num_pkt_miss = 0;
 	return 0;
 }
 
 static int tdav_speex_jitterbuffer_close(tmedia_jitterbuffer_t* self)
 {
 	tdav_speex_jitterbuffer_t *jitterbuffer = (tdav_speex_jitterbuffer_t *)self;
 	if (jitterbuffer->state) {
 		jitter_buffer_destroy(jitterbuffer->state);
 		jitterbuffer->state = tsk_null;
 	}
 	return 0;
 }
 
 
 
 //
 //	Speex jitterbufferr Plugin definition
 //
 
 /* constructor */
 static tsk_object_t* tdav_speex_jitterbuffer_ctor(tsk_object_t * self, va_list * app)
 {
 	tdav_speex_jitterbuffer_t *jitterbuffer = self;
 	TSK_DEBUG_INFO("Create SpeexDSP jitter buffer");
 	if (jitterbuffer){
 		/* init base */
 		tmedia_jitterbuffer_init(TMEDIA_JITTER_BUFFER(jitterbuffer));
 		/* init self */
 	}
 	return self;
 }
 /* destructor */
 static tsk_object_t* tdav_speex_jitterbuffer_dtor(tsk_object_t * self)
 {
 	tdav_speex_jitterbuffer_t *jb = self;
 	if (jb){
 		/* deinit base */
 		tmedia_jitterbuffer_deinit(TMEDIA_JITTER_BUFFER(jb));
 		/* deinit self */
 		if (jb->state){
 			jitter_buffer_destroy(jb->state);
 			jb->state = tsk_null;
 		}
 		TSK_FREE(jb->buff.ptr);
 
 		TSK_DEBUG_INFO("*** SpeexDSP jb destroyed ***");
 	}
 
 	return self;
 }
 /* object definition */
 static const tsk_object_def_t tdav_speex_jitterbuffer_def_s =
 {
 	sizeof(tdav_speex_jitterbuffer_t),
 	tdav_speex_jitterbuffer_ctor,
 	tdav_speex_jitterbuffer_dtor,
 	tsk_null,
 };
 /* plugin definition*/
 static const tmedia_jitterbuffer_plugin_def_t tdav_speex_jitterbuffer_plugin_def_s =
 {
 	&tdav_speex_jitterbuffer_def_s,
 	tmedia_audio,
 	"Audio JitterBuffer based on Speex",
 
 	tdav_speex_jitterbuffer_set,
 	tdav_speex_jitterbuffer_open,
 	tdav_speex_jitterbuffer_tick,
 	tdav_speex_jitterbuffer_put,
 	tdav_speex_jitterbuffer_get,
 	tdav_speex_jitterbuffer_reset,
 	tdav_speex_jitterbuffer_close,
 };
 const tmedia_jitterbuffer_plugin_def_t *tdav_speex_jitterbuffer_plugin_def_t = &tdav_speex_jitterbuffer_plugin_def_s;
 
 
 #endif /* HAVE_SPEEX_DSP */