Commit 0e3af8f2 authored by Ghislain MARY's avatar Ghislain MARY
Browse files

Include g729 support in mediastreamer2 instead of using a plugin.

parent 4a3adb04
......@@ -90,7 +90,8 @@ option(ENABLE_BV16 "Build mediastreamer2 with the BV16 codec." YES)
option(ENABLE_OPUS "Build mediastreamer2 with the OPUS codec." YES)
option(ENABLE_SPEEX_CODEC "Build mediastreamer2 with the SPEEX codec." YES)
option(ENABLE_SPEEX_DSP "Build mediastreamer2 with the SPEEX DSP support." YES)
option(ENABLE_G729B_CNG "Build mediastremer2 with G729 annex B cng." NO)
option(ENABLE_G729 "Build mediastreamer2 with the G729 codec." YES)
option(ENABLE_G729B_CNG "Build mediastreamer2 with G729 annex B cng." NO)
cmake_dependent_option(ENABLE_RESAMPLE "Build mediastreamer2 with the resampling capability." YES "ENABLE_SPEEX_DSP" NO)
option(ENABLE_VIDEO "Build mediastreamer2 with video support." YES)
......@@ -320,11 +321,12 @@ if(ENABLE_SOUND AND NOT(WIN32 OR ENABLE_ALSA OR ENABLE_ARTSC OR ENABLE_MACSND OR
message(FATAL_ERROR "Could not find a support sound driver API. Use -DENABLE_SOUND=NO if you don't care about having sound.")
endif()
if(ENABLE_G729B_CNG)
if(ENABLE_G729 OR ENABLE_G729B_CNG)
find_package(Bcg729 1.0.1)
if(NOT BCG729_FOUND)
message(WARNING "Could not find bcg729 , mediastreamer2 will be compiled without G729 AnnexB in RFC3389 .")
set(ENABLE_G729_CNG OFF CACHE BOOL "Build mediastreamer2 with g729 CNG." FORCE)
message(WARNING "Could not find bcg729, mediastreamer2 will be compiled without G729 codec and G729 AnnexB in RFC3389.")
set(ENABLE_G729 OFF CACHE BOOL "Build mediastreamer2 with the G729 codec." FORCE)
set(ENABLE_G729_CNG OFF CACHE BOOL "Build mediastreamer2 with G729 Annex B cng." FORCE)
endif()
endif()
......@@ -539,7 +541,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/mediastreamer-config.h.cmake ${CMAKE_
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/mediastreamer-config.h PROPERTIES GENERATED ON)
add_definitions("-DHAVE_CONFIG_H")
set(MEDIASTREAMER2_CPPFLAGS ${ORTP_CPPFLAGS} ${BZRTP_CPPFLAGS} ${BCTOOLBOX_CPPFLAGS})
set(MEDIASTREAMER2_CPPFLAGS ${ORTP_CPPFLAGS} ${BZRTP_CPPFLAGS} ${BCTOOLBOX_CPPFLAGS} ${BCG729_CPPFLAGS})
if(ENABLE_STATIC)
list(APPEND MEDIASTREAMER2_CPPFLAGS "-DMS2_STATIC")
endif()
......
......@@ -1165,6 +1165,27 @@ fi
AM_CONDITIONAL(LIBBZRTP,test x$zrtp != xfalse)
dnl check for bcg729 presence to use for G729 codec
AC_ARG_ENABLE(g729,
[AS_HELP_STRING([--enable-g729], [Turn on or off usage of G729 codec (default=no)])],
[case "${enableval}" in
yes) g729=true ;;
no) g729=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-g729) ;;
esac],
[g729=false]
)
if test "$g729" = "true" ; then
PKG_CHECK_MODULES(LIBBCG729, libbcg729 >= 1.0)
LIBS="$LIBS $LIBBCG729_LIBS"
CFLAGS="$CFLAGS $LIBBCG729_CFLAGS"
else
echo "G729 codec is disabled."
fi
AM_CONDITIONAL(BUILD_G729,test x$g729 != xfalse)
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)])],
......@@ -1186,6 +1207,7 @@ if test "$g729bCN" = "true" ; then
else
echo "G729 AnnexB in RFC3389 is disabled."
fi
AM_CONDITIONAL(LIBBCG729,test x$g729bCN != xfalse)
dnl ##################################################
......
......@@ -159,7 +159,9 @@ typedef enum MSFilterId{
MS_BV16_ENC_ID,
MS_UDP_SEND_ID,
MS_PCAP_FILE_PLAYER_ID,
MS_OGL_ID
MS_OGL_ID,
MS_G729_DEC_ID,
MS_G729_ENC_ID
} MSFilterId;
#endif
......@@ -252,6 +252,9 @@ endif()
if(ENABLE_G726)
list(APPEND VOIP_SOURCE_FILES_C audiofilters/g726.c)
endif()
if(BCG729_FOUND AND ENABLE_G729)
list(APPEND VOIP_SOURCE_FILES_C audiofilters/g729.c)
endif()
if(GSM_FOUND)
list(APPEND VOIP_SOURCE_FILES_C audiofilters/gsm.c)
endif()
......@@ -617,8 +620,10 @@ endif()
if(TURBOJPEG_FOUND)
list(APPEND VOIP_LIBS ${TURBOJPEG_LIBRARIES})
endif()
if (BCGG729_FOUND)
add_definitions(-DHAVE_G729B=1)
if(BCG729_FOUND)
if(ENABLE_G729_CNG)
add_definitions("-DHAVE_G729B=1")
endif()
list(APPEND VOIP_LIBS ${BCG729_LIBRARIES})
endif()
set(MS2_VOIP_DEPENDENCIES ms2-git-version ms2-voipdescs-header)
......
......@@ -177,6 +177,10 @@ if BUILD_G726
libmediastreamer_voip_la_SOURCES+= audiofilters/g726.c
endif
if BUILD_G729
libmediastreamer_voip_la_SOURCES+= audiofilters/g729.c
endif
if BUILD_OPUS
libmediastreamer_voip_la_SOURCES+= audiofilters/msopus.c
endif
......
/*
g729.c
Copyright (C) 2011 Belledonne Communications, Grenoble, France
Author : Jehan Monnier
This program 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 2
of the License, or (at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "mediastreamer2/mscodecutils.h"
#include "mediastreamer2/msfilter.h"
#include "mediastreamer2/msticker.h"
#include "bcg729/decoder.h"
#include "bcg729/encoder.h"
/* signal and bitstream frame size in byte */
#define SIGNAL_FRAME_SIZE 160
#define BITSTREAM_FRAME_SIZE 10
#define NOISE_BITSTREAM_FRAME_SIZE 2
/* decoder struct: context for decoder channel and concealment */
struct bcg729Decoder_struct {
bcg729DecoderChannelContextStruct *decoderChannelContext;
MSConcealerContext *concealer;
};
static void msbcg729_decoder_init(MSFilter *f){
f->data = ms_new0(struct bcg729Decoder_struct,1);
}
static void msbcg729_decoder_preprocess(MSFilter *f){
struct bcg729Decoder_struct* obj= (struct bcg729Decoder_struct*) f->data;
obj->decoderChannelContext = initBcg729DecoderChannel(); /* initialize bcg729 decoder, return channel context */
obj->concealer = ms_concealer_context_new(UINT32_MAX);
}
static void msbcg729_decoder_process(MSFilter *f){
struct bcg729Decoder_struct* obj= (struct bcg729Decoder_struct*) f->data;
mblk_t *inputMessage, *outputMessage;
while((inputMessage=ms_queue_get(f->inputs[0]))) {
while(inputMessage->b_rptr<inputMessage->b_wptr) {
/* if remaining data in RTP payload have the size of a SID frame it must be one, see RFC3551 section 4.5.6 : any SID frame must be the last one of the RPT payload */
uint8_t SIDFrameFlag = ((inputMessage->b_wptr-inputMessage->b_rptr)==NOISE_BITSTREAM_FRAME_SIZE)?1:0;
outputMessage = allocb(SIGNAL_FRAME_SIZE,0);
mblk_meta_copy(inputMessage, outputMessage);
bcg729Decoder(obj->decoderChannelContext, inputMessage->b_rptr, (SIDFrameFlag==1)?NOISE_BITSTREAM_FRAME_SIZE:BITSTREAM_FRAME_SIZE, 0, SIDFrameFlag, 0, (int16_t *)(outputMessage->b_wptr));
outputMessage->b_wptr+=SIGNAL_FRAME_SIZE;
inputMessage->b_rptr += (SIDFrameFlag==1)?NOISE_BITSTREAM_FRAME_SIZE:BITSTREAM_FRAME_SIZE;
ms_queue_put(f->outputs[0],outputMessage);
ms_concealer_inc_sample_time(obj->concealer,f->ticker->time,10, 1);
}
freemsg(inputMessage);
}
if (ms_concealer_context_is_concealement_required(obj->concealer, f->ticker->time)) {
outputMessage = allocb(SIGNAL_FRAME_SIZE,0);
bcg729Decoder(obj->decoderChannelContext, NULL, 0, 1, 0, 0, (int16_t *)(outputMessage->b_wptr));
outputMessage->b_wptr+=SIGNAL_FRAME_SIZE;
mblk_set_plc_flag(outputMessage, 1);
ms_queue_put(f->outputs[0],outputMessage);
ms_concealer_inc_sample_time(obj->concealer,f->ticker->time,10, 0);
}
}
static void msbcg729_decoder_postprocess(MSFilter *f){
struct bcg729Decoder_struct* obj= (struct bcg729Decoder_struct*) f->data;
ms_concealer_context_destroy(obj->concealer);
closeBcg729DecoderChannel(obj->decoderChannelContext);
}
static void msbcg729_decoder_uninit(MSFilter *f){
ms_free(f->data);
}
static int msbcg729_decoder_have_plc(MSFilter *f, void *arg){
*((int *)arg) = 1;
return 0;
}
/*decoder specific method*/
static MSFilterMethod msbcg729_decoder_methods[]={
{ MS_DECODER_HAVE_PLC , msbcg729_decoder_have_plc },
{ 0 , NULL }
};
#define MS_BCG729_DEC_ID MS_G729_DEC_ID
#define MS_BCG729_DEC_NAME "MSBCG729Dec"
#define MS_BCG729_DEC_DESCRIPTION "G729 audio decoder filter"
#define MS_BCG729_DEC_CATEGORY MS_FILTER_DECODER
#define MS_BCG729_DEC_ENC_FMT "G729"
#define MS_BCG729_DEC_NINPUTS 1
#define MS_BCG729_DEC_NOUTPUTS 1
#define MS_BCG729_DEC_FLAGS MS_FILTER_IS_PUMP
#ifndef _MSC_VER
MSFilterDesc ms_bcg729_dec_desc={
.id=MS_BCG729_DEC_ID,
.name=MS_BCG729_DEC_NAME,
.text=MS_BCG729_DEC_DESCRIPTION,
.category=MS_BCG729_DEC_CATEGORY,
.enc_fmt=MS_BCG729_DEC_ENC_FMT,
.ninputs=MS_BCG729_DEC_NINPUTS, /*number of inputs*/
.noutputs=MS_BCG729_DEC_NOUTPUTS, /*number of outputs*/
.init=msbcg729_decoder_init,
.preprocess=msbcg729_decoder_preprocess,
.process=msbcg729_decoder_process,
.postprocess=msbcg729_decoder_postprocess,
.uninit=msbcg729_decoder_uninit,
.methods=msbcg729_decoder_methods,
.flags=MS_BCG729_DEC_FLAGS
};
#else
MSFilterDesc ms_bcg729_dec_desc={
MS_BCG729_DEC_ID,
MS_BCG729_DEC_NAME,
MS_BCG729_DEC_DESCRIPTION,
MS_BCG729_DEC_CATEGORY,
MS_BCG729_DEC_ENC_FMT,
MS_BCG729_DEC_NINPUTS,
MS_BCG729_DEC_NOUTPUTS,
msbcg729_decoder_init,
msbcg729_decoder_preprocess,
msbcg729_decoder_process,
msbcg729_decoder_postprocess,
msbcg729_decoder_uninit,
msbcg729_decoder_methods,
MS_BCG729_DEC_FLAGS
};
#endif
MS_FILTER_DESC_EXPORT(ms_bcg729_dec_desc)
#ifdef HAVE_ms_bufferizer_fill_current_metas
#define ms_bufferizer_fill_current_metas(b,m) ms_bufferizer_fill_current_metas(b,m)
#else
#define ms_bufferizer_fill_current_metas(b,m)
#endif
/*filter common method*/
struct bcg729Encoder_struct {
bcg729EncoderChannelContextStruct *encoderChannelContext;
MSBufferizer *bufferizer;
unsigned char ptime;
unsigned char max_ptime;
uint32_t ts;
uint8_t enableVAD;
};
static void msbcg729_encoder_init(MSFilter *f){
struct bcg729Encoder_struct* obj;
f->data = ms_new0(struct bcg729Encoder_struct,1);
obj = (struct bcg729Encoder_struct*) f->data;
obj->ptime=20;
obj->max_ptime=100;
obj->enableVAD=0;
}
static void msbcg729_encoder_preprocess(MSFilter *f){
struct bcg729Encoder_struct* obj= (struct bcg729Encoder_struct*) f->data;
obj->encoderChannelContext = initBcg729EncoderChannel(obj->enableVAD); /* initialize bcg729 encoder, return context */
obj->bufferizer=ms_bufferizer_new();
}
static void msbcg729_encoder_process(MSFilter *f){
struct bcg729Encoder_struct* obj= (struct bcg729Encoder_struct*) f->data;
mblk_t *inputMessage;
mblk_t *outputMessage=NULL;
uint8_t inputBuffer[160]; /* 2bytes per sample at 8000Hz -> 16 bytes per ms */
uint8_t bufferIndex=0;
/* get all input data into a buffer */
while((inputMessage=ms_queue_get(f->inputs[0]))!=NULL){
ms_bufferizer_put(obj->bufferizer,inputMessage);
}
/* process ptimes ms of data : (ptime in ms)/1000->ptime is seconds * 8000(sample rate) * 2(byte per sample) */
while(ms_bufferizer_get_avail(obj->bufferizer)>=obj->ptime*16){
uint16_t totalPacketDataLength = 0;
uint8_t bitStreamLength = 0;
outputMessage = allocb(obj->ptime,0); /* output bitStream is 80 bits long * number of samples */
/* 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 */
for (bufferIndex=0; (bufferIndex<obj->ptime) && (bitStreamLength!=2); bufferIndex+=10) {
ms_bufferizer_read(obj->bufferizer,inputBuffer,160);
bcg729Encoder(obj->encoderChannelContext, (int16_t *)inputBuffer, outputMessage->b_wptr, &bitStreamLength);
outputMessage->b_wptr+=bitStreamLength;
totalPacketDataLength+=bitStreamLength;
}
obj->ts+=bufferIndex*8;
/* do not enqueue the message if no data out (DTX untransmitted frames) */
if (totalPacketDataLength>0) {
mblk_set_timestamp_info(outputMessage,obj->ts);
ms_bufferizer_fill_current_metas(obj->bufferizer, outputMessage);
ms_queue_put(f->outputs[0],outputMessage);
}
}
}
static void msbcg729_encoder_postprocess(MSFilter *f){
struct bcg729Encoder_struct* obj= (struct bcg729Encoder_struct*) f->data;
ms_bufferizer_destroy(obj->bufferizer);
closeBcg729EncoderChannel(obj->encoderChannelContext);
}
static void msbcg729_encoder_uninit(MSFilter *f){
ms_free(f->data);
}
/*encoder specific method*/
static int msbcg729_encoder_add_fmtp(MSFilter *f, void *arg){
char buf[64];
struct bcg729Encoder_struct* obj= (struct bcg729Encoder_struct*) f->data;
const char *fmtp=(const char *)arg;
buf[0] ='\0';
if (fmtp_get_value(fmtp,"maxptime:",buf,sizeof(buf))){
obj->max_ptime=atoi(buf);
if (obj->max_ptime <10 || obj->max_ptime >100 ) {
ms_warning("MSBCG729Enc: unknown value [%i] for maxptime, use default value (100) instead",obj->max_ptime);
obj->max_ptime=100;
}
ms_message("MSBCG729Enc: got maxptime=%i",obj->max_ptime);
}
if (fmtp_get_value(fmtp,"ptime",buf,sizeof(buf))){
obj->ptime=atoi(buf);
if (obj->ptime > obj->max_ptime) {
obj->ptime=obj->max_ptime;
} else if (obj->ptime%10) {
//if the ptime is not a mulptiple of 10, go to the next multiple
obj->ptime = obj->ptime - obj->ptime%10 + 10;
}
ms_message("MSBCG729Enc: got ptime=%i",obj->ptime);
}
if (fmtp_get_value(fmtp,"annexb",buf,sizeof(buf))){
if (strncmp(buf, "yes",3) == 0) {
obj->enableVAD = 1;
ms_message("MSBCG729Enc: enable VAD/DTX - AnnexB");
}
}
/* parse annexB param here */
return 0;
}
static MSFilterMethod msbcg729_encoder_methods[]={
{ MS_FILTER_ADD_FMTP , msbcg729_encoder_add_fmtp },
{ 0, NULL}
};
#define MS_BCG729_ENC_ID MS_G729_ENC_ID
#define MS_BCG729_ENC_NAME "MSBCG729Enc"
#define MS_BCG729_ENC_DESCRIPTION "G729 audio encoder filter"
#define MS_BCG729_ENC_CATEGORY MS_FILTER_ENCODER
#define MS_BCG729_ENC_ENC_FMT "G729"
#define MS_BCG729_ENC_NINPUTS 1
#define MS_BCG729_ENC_NOUTPUTS 1
#define MS_BCG729_ENC_FLAGS 0
#ifndef _MSC_VER
MSFilterDesc ms_bcg729_enc_desc={
.id=MS_BCG729_ENC_ID,
.name=MS_BCG729_ENC_NAME,
.text=MS_BCG729_ENC_DESCRIPTION,
.category=MS_BCG729_ENC_CATEGORY,
.enc_fmt=MS_BCG729_ENC_ENC_FMT,
.ninputs=MS_BCG729_ENC_NINPUTS, /*number of inputs*/
.noutputs=MS_BCG729_ENC_NOUTPUTS, /*number of outputs*/
.init=msbcg729_encoder_init,
.preprocess=msbcg729_encoder_preprocess,
.process=msbcg729_encoder_process,
.postprocess=msbcg729_encoder_postprocess,
.uninit=msbcg729_encoder_uninit,
.methods=msbcg729_encoder_methods,
.flags=MS_BCG729_ENC_FLAGS
};
#else
MSFilterDesc ms_bcg729_enc_desc={
MS_BCG729_ENC_ID,
MS_BCG729_ENC_NAME,
MS_BCG729_ENC_DESCRIPTION,
MS_BCG729_ENC_CATEGORY,
MS_BCG729_ENC_ENC_FMT,
MS_BCG729_ENC_NINPUTS,
MS_BCG729_ENC_NOUTPUTS,
msbcg729_encoder_init,
msbcg729_encoder_preprocess,
msbcg729_encoder_process,
msbcg729_encoder_postprocess,
msbcg729_encoder_uninit,
msbcg729_encoder_methods,
MS_BCG729_ENC_FLAGS
};
#endif
MS_FILTER_DESC_EXPORT(ms_bcg729_enc_desc)
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