Commit 574ecf89 authored by johan's avatar johan

Add RFC3389 comfort noise payload utilisation via bcg729 annex B

- enabled by configure switch --enable-g729bCN
- request lib bcg729 version >= 1.0
parent 3d23e9d8
......@@ -1186,6 +1186,30 @@ fi
AC_SUBST(POLARSSL_CFLAGS)
AC_SUBST(POLARSSL_LIBS)
dnl check for bcg729 annexB presence to use for VAD/DTX (RFC3389 : Real-time Transport Protocol (RTP) Payload for Comfort Noise (CN))
AC_ARG_ENABLE(g729bCN,
[AS_HELP_STRING([--enable-g729bCN], [Turn on or off usage of G729AnnexB in RFC3389 implementation of Comfort Noise Payload (default=no)])],
[case "${enableval}" in
yes) g729bCN=true ;;
no) g729bCN=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-g729bCN) ;;
esac],
[g729bCN=false]
)
if test "$g729bCN" = "true" ; then
PKG_CHECK_MODULES(LIBBCG729, libbcg729 >= 1.0)
AC_DEFINE(HAVE_G729B, 1, [Defined when use of g729AnnexB Comfort Noise and RFC3389 support is compiled])
LIBS="$LIBS $LIBBCG729_LIBS"
CFLAGS="$CFLAGS $LIBBCG729_CFLAGS"
else
echo "G729 AnnexB in RFC3389 is disabled."
fi
AM_CONDITIONAL(LIBBCG729,test x$g729bCN != xfalse)
dnl ##################################################
dnl # Check for doxygen
dnl ##################################################
......
......@@ -22,6 +22,9 @@
#include <mediastreamer2/mscodecutils.h>
#include <mediastreamer2/msticker.h>
#include "mediastreamer2/msgenericplc.h"
#ifdef HAVE_G729B
#include "bcg729/decoder.h"
#endif
/*filter common method*/
typedef struct {
......@@ -31,12 +34,18 @@ typedef struct {
MSCngData cng_data;
bool_t cng_set;
bool_t cng_running;
#ifdef HAVE_G729B
bcg729DecoderChannelContextStruct *decoderChannelContext;
#endif
} generic_plc_struct;
const static unsigned int MAX_PLC_COUNT = UINT32_MAX;
static void generic_plc_init(MSFilter *f) {
generic_plc_struct *mgps = (generic_plc_struct*) ms_new0(generic_plc_struct, 1);
#ifdef HAVE_G729B
mgps->decoderChannelContext = initBcg729DecoderChannel(); /* initialize bcg729 decoder for CNG */
#endif
mgps->concealer = ms_concealer_context_new(MAX_PLC_COUNT);
mgps->nchannels = 1;
f->data = mgps;
......@@ -57,8 +66,25 @@ static void generic_plc_process(MSFilter *f) {
}
}
if (ms_concealer_context_is_concealement_required(mgps->concealer, f->ticker->time)) {
#ifdef HAVE_G729B
m = allocb(buff_size, 0);
/* Transmitted CNG data is in mgps->cng_data : give it to bcg729 decoder -> output in m->b_wptr */
if (mgps->cng_set) { /* received some CNG data */
mgps->cng_set=FALSE; /* reset flag */
mgps->cng_running=TRUE;
bcg729Decoder(mgps->decoderChannelContext, mgps->cng_data.data, mgps->cng_data.datasize, 0, 1, 1, (int16_t *)(m->b_wptr));
mblk_set_cng_flag(m, 1);
/* TODO: if ticker->interval is not 10 ms which is also G729 frame length, we must generate untransmitted frame CNG until we reach the requested data amount */
} else if (mgps->cng_running) { /* missing frame but CNG is ongoing: shall be an untransmitted frame */
bcg729Decoder(mgps->decoderChannelContext, NULL, 0, 1, 1, 1, (int16_t *)(m->b_wptr));
mblk_set_cng_flag(m, 1);
} else {
mblk_set_plc_flag(m, 1);
memset(m->b_wptr, 0, buff_size);
}
#else
m = allocb(buff_size, 0);
if (!mgps->cng_running && mgps->cng_set){
mgps->cng_running=TRUE;
mblk_set_cng_flag(m, 1);
......@@ -67,6 +93,8 @@ static void generic_plc_process(MSFilter *f) {
mblk_set_plc_flag(m, 1);
}
memset(m->b_wptr, 0, buff_size);
#endif
m->b_wptr += buff_size;
ms_queue_put(f->outputs[0], m);
ms_concealer_inc_sample_time(mgps->concealer, f->ticker->time, f->ticker->interval, FALSE);
......@@ -76,6 +104,9 @@ static void generic_plc_process(MSFilter *f) {
static void generic_plc_unit(MSFilter *f) {
generic_plc_struct *mgps = (generic_plc_struct*) f->data;
ms_concealer_context_destroy(mgps->concealer);
#ifdef HAVE_G729B
closeBcg729DecoderChannel(mgps->decoderChannelContext);
#endif
ms_free(mgps);
}
......
......@@ -26,6 +26,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "mediastreamer2/msutils.h"
#include "mediastreamer2/msvaddtx.h"
#ifdef HAVE_G729B
#include "bcg729/encoder.h"
#endif
#include <math.h>
static const float max_e = (32768* 0.7); /* 0.7 - is RMS factor */
......@@ -38,6 +42,8 @@ typedef struct _VadDtxContext{
float energy;
ortp_extremum max;
#else
bcg729EncoderChannelContextStruct *encoderChannelContext;
MSBufferizer *bufferizer;
#endif
}VadDtxContext;
......@@ -45,15 +51,24 @@ typedef struct _VadDtxContext{
static void vad_dtx_init(MSFilter *f){
VadDtxContext *ctx=ms_new0(VadDtxContext,1);
f->data=ctx;
#ifdef HAVE_G729B
ctx->encoderChannelContext = initBcg729EncoderChannel(1); /* init G729 encoder with VAD enabled */
ctx->bufferizer=ms_bufferizer_new();
#else
ortp_extremum_init(&ctx->max,2000);
#endif
}
static void vad_dtx_preprocess(MSFilter *f){
#ifndef HAVE_G729B
VadDtxContext *ctx=(VadDtxContext*)f->data;
ortp_extremum_reset(&ctx->max);
#endif
}
#ifndef HAVE_G729B
static void update_energy(VadDtxContext *v, int16_t *signal, int numsamples, uint64_t curtime) {
int i;
float acc = 0;
......@@ -68,11 +83,49 @@ static void update_energy(VadDtxContext *v, int16_t *signal, int numsamples, uin
ortp_extremum_record_max(&v->max,curtime,v->energy);
//ms_message("Energy=%f, current max=%f",v->energy, ortp_extremum_get_current(&v->max));
}
#endif
static void vad_dtx_process(MSFilter *f){
VadDtxContext *ctx=(VadDtxContext*)f->data;
mblk_t *m;
#ifdef HAVE_G729B
uint8_t inputBuffer[160]; /* 2bytes per sample at 8000Hz -> 16 bytes per ms */
/* get all input data into a buffer */
while((m=ms_queue_get(f->inputs[0]))!=NULL){
ms_queue_put(f->outputs[0],dupmsg(m)); /* forward the message to the next filter, duplicate it because putting it in the bufferizer destroys it */
ms_bufferizer_put(ctx->bufferizer,m);
}
/* process frames of 10 ms (160 bytes) at 8000kHz and 2 bytes per sample */
while(ms_bufferizer_get_avail(ctx->bufferizer)>=160){
uint8_t bitStreamLength = 0;
uint8_t bitStream[10]; /* store the g729 encoder output : 10 bytes(voice frame), 2 bytes (noise frame) or 0 byte (untransmitted frame) */
memset(bitStream, 0, 10*sizeof(uint8_t));
/* process buffer in 10 ms frames */
/* RFC3551 section 4.5.6 we must end the RTP payload of G729 frames when transmitting a SID frame : bitStreamLength == 2 */
ms_bufferizer_read(ctx->bufferizer,inputBuffer,160);
bcg729Encoder(ctx->encoderChannelContext, (int16_t *)inputBuffer, bitStream, &bitStreamLength);
if (bitStreamLength != 10) { /* this is a noise frame */
if (bitStreamLength == 2){ /* there is a NOISE frame to send */
MSCngData cngdata;
memset (&cngdata, 0, sizeof(MSCngData));
/* extract the rfc3389 parameters */
bcg729GetRFC3389Payload(ctx->encoderChannelContext, cngdata.data);
cngdata.datasize=11; /* noise parameters on 11 bytes */
ms_message("vad_dtx_process(): send SID frame. Notify filter [%p]", f);
ctx->silence_mode=1;
ms_filter_notify(f, MS_VAD_DTX_NO_VOICE, &cngdata);
}
} else { /* voice frame */
if (ctx->silence_mode){
/*ms_message("vad_dtx_process(): silence period finished.");*/
ctx->silence_mode=0;
ms_filter_notify(f, MS_VAD_DTX_VOICE, NULL);
}
}
}
#else
while((m=ms_queue_get(f->inputs[0]))!=NULL){
update_energy(ctx,(int16_t*)m->b_rptr, (m->b_wptr - m->b_rptr) / 2, f->ticker->time);
......@@ -94,11 +147,16 @@ static void vad_dtx_process(MSFilter *f){
}
ms_queue_put(f->outputs[0],m);
}
#endif
}
static void vad_dtx_postprocess(MSFilter *f){
//VadDtxContext *ctx=(VadDtxContext*)f->data;
#ifdef HAVE_G729B
VadDtxContext *ctx=(VadDtxContext*)f->data;
ms_bufferizer_destroy(ctx->bufferizer);
closeBcg729EncoderChannel(ctx->encoderChannelContext);
#endif
}
......
......@@ -316,6 +316,14 @@ bool_t ms_is_multicast(const char *address) {
bool_t mediastream_payload_type_changed(RtpSession *session, unsigned long data) {
MediaStream *stream = (MediaStream *)data;
int pt = rtp_session_get_recv_payload_type(stream->sessions.rtp_session);
int cn_pt = rtp_profile_find_payload_number(stream->sessions.rtp_session->snd.profile, "CN", 8000, 1);
/* if new payload type is Comfort Noise(CN), just do nothing */
if (pt == cn_pt) {
ms_message("Ignore paylaod type change to CN");
return FALSE;
}
return media_stream_change_decoder(stream, pt);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment