Re #2029: Support for G.729 backend implementation from bcg729.
git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@5630 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
parent
55e2570a9b
commit
10882ddde2
98
aconfigure
98
aconfigure
|
@ -627,6 +627,7 @@ ac_webrtc_cflags
|
|||
ac_webrtc_instset
|
||||
ac_no_webrtc
|
||||
ac_no_yuv
|
||||
ac_no_bcg729
|
||||
opus_present
|
||||
opus_h_present
|
||||
ac_no_opus
|
||||
|
@ -826,6 +827,8 @@ with_silk
|
|||
enable_silk
|
||||
with_opus
|
||||
enable_opus
|
||||
with_bcg729
|
||||
enable_bcg729
|
||||
enable_libyuv
|
||||
enable_libwebrtc
|
||||
'
|
||||
|
@ -1506,6 +1509,7 @@ Optional Features:
|
|||
--disable-opus Exclude OPUS support from the build (default:
|
||||
autodetect)
|
||||
|
||||
--disable-bcg729 Disable bcg729 (default: not disabled)
|
||||
--disable-libyuv Exclude libyuv in the build
|
||||
--disable-libwebrtc Exclude libwebrtc in the build
|
||||
|
||||
|
@ -1558,6 +1562,7 @@ Optional Packages:
|
|||
Specify alternate libvo-amrwbenc prefix
|
||||
--with-silk=DIR Specify alternate SILK prefix
|
||||
--with-opus=DIR Specify alternate OPUS prefix
|
||||
--with-bcg729=DIR Specify alternate bcg729 prefix
|
||||
|
||||
Some influential environment variables:
|
||||
CC C compiler command
|
||||
|
@ -8472,6 +8477,99 @@ fi
|
|||
|
||||
|
||||
|
||||
# Check whether --with-bcg729 was given.
|
||||
if test "${with_bcg729+set}" = set; then :
|
||||
withval=$with_bcg729;
|
||||
else
|
||||
with_bcg729=no
|
||||
|
||||
fi
|
||||
|
||||
|
||||
if test "x$ac_cross_compile" != "x" -a "x$with_bcg729" = "xno"; then
|
||||
enable_bcg729=no
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --enable-bcg729 was given.
|
||||
if test "${enable_bcg729+set}" = set; then :
|
||||
enableval=$enable_bcg729;
|
||||
if test "$enable_bcg729" = "no"; then
|
||||
ac_no_bcg729=1
|
||||
$as_echo "#define PJMEDIA_HAS_BCG729 0" >>confdefs.h
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Checking if bcg729 is disabled... yes" >&5
|
||||
$as_echo "Checking if bcg729 is disabled... yes" >&6; }
|
||||
fi
|
||||
|
||||
else
|
||||
|
||||
if test "x$with_bcg729" != "xno" -a "x$with_bcg729" != "x"; then
|
||||
BCG729_PREFIX=$with_bcg729
|
||||
BCG729_CFLAGS="-I$BCG729_PREFIX/include"
|
||||
BCG729_LDFLAGS="-L$BCG729_PREFIX/lib"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Using bcg729 prefix... $with_bcg729" >&5
|
||||
$as_echo "Using bcg729 prefix... $with_bcg729" >&6; }
|
||||
else
|
||||
BCG729_CFLAGS=""
|
||||
BCG729_LDFLAGS=""
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking bcg729 usability" >&5
|
||||
$as_echo_n "checking bcg729 usability... " >&6; }
|
||||
|
||||
BCG729_LIBS="-lbcg729"
|
||||
|
||||
SAVED_LIBS="$LIBS"
|
||||
SAVED_LDFLAGS="$LDFLAGS"
|
||||
SAVED_CFLAGS="$CFLAGS"
|
||||
|
||||
LIBS="$BCG729_LIBS $LIBS"
|
||||
LDFLAGS="$BCG729_LDFLAGS $LDFLAGS"
|
||||
CFLAGS="$BCG729_CFLAGS $CFLAGS"
|
||||
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#include <bcg729/encoder.h>
|
||||
#include <bcg729/decoder.h>
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
initBcg729EncoderChannel(0);
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
|
||||
$as_echo "#define PJMEDIA_HAS_BCG729 1" >>confdefs.h
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
|
||||
$as_echo "ok" >&6; }
|
||||
|
||||
else
|
||||
|
||||
ac_no_bcg729=1
|
||||
$as_echo "#define PJMEDIA_HAS_BCG729 0" >>confdefs.h
|
||||
|
||||
LIBS="$SAVED_LIBS"
|
||||
LDFLAGS="$SAVED_LDFLAGS"
|
||||
CFLAGS="$SAVED_CFLAGS"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
|
||||
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
# Check whether --enable-libyuv was given.
|
||||
if test "${enable_libyuv+set}" = set; then :
|
||||
enableval=$enable_libyuv; if test "$enable_libyuv" = "no"; then
|
||||
|
|
|
@ -1787,6 +1787,75 @@ AC_ARG_ENABLE(opus,
|
|||
fi
|
||||
])
|
||||
|
||||
dnl # bcg729 prefix
|
||||
AC_ARG_WITH(bcg729,
|
||||
AS_HELP_STRING([--with-bcg729=DIR],
|
||||
[Specify alternate bcg729 prefix]),
|
||||
[],
|
||||
[with_bcg729=no]
|
||||
)
|
||||
|
||||
dnl # Do not use default bcg729 installation if we are cross-compiling
|
||||
if test "x$ac_cross_compile" != "x" -a "x$with_bcg729" = "xno"; then
|
||||
enable_bcg729=no
|
||||
fi
|
||||
|
||||
dnl # bcg729
|
||||
AC_SUBST(ac_no_bcg729)
|
||||
AC_ARG_ENABLE(bcg729,
|
||||
AS_HELP_STRING([--disable-bcg729],
|
||||
[Disable bcg729 (default: not disabled)]),
|
||||
[
|
||||
if test "$enable_bcg729" = "no"; then
|
||||
[ac_no_bcg729=1]
|
||||
AC_DEFINE(PJMEDIA_HAS_BCG729,0)
|
||||
AC_MSG_RESULT([Checking if bcg729 is disabled... yes])
|
||||
fi
|
||||
],
|
||||
[
|
||||
if test "x$with_bcg729" != "xno" -a "x$with_bcg729" != "x"; then
|
||||
BCG729_PREFIX=$with_bcg729
|
||||
BCG729_CFLAGS="-I$BCG729_PREFIX/include"
|
||||
BCG729_LDFLAGS="-L$BCG729_PREFIX/lib"
|
||||
AC_MSG_RESULT([Using bcg729 prefix... $with_bcg729])
|
||||
else
|
||||
BCG729_CFLAGS=""
|
||||
BCG729_LDFLAGS=""
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([bcg729 usability])
|
||||
|
||||
BCG729_LIBS="-lbcg729"
|
||||
|
||||
SAVED_LIBS="$LIBS"
|
||||
SAVED_LDFLAGS="$LDFLAGS"
|
||||
SAVED_CFLAGS="$CFLAGS"
|
||||
|
||||
LIBS="$BCG729_LIBS $LIBS"
|
||||
LDFLAGS="$BCG729_LDFLAGS $LDFLAGS"
|
||||
CFLAGS="$BCG729_CFLAGS $CFLAGS"
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <bcg729/encoder.h>
|
||||
#include <bcg729/decoder.h>
|
||||
]],
|
||||
[initBcg729EncoderChannel(0);]
|
||||
)],
|
||||
[
|
||||
AC_DEFINE(PJMEDIA_HAS_BCG729,1)
|
||||
AC_MSG_RESULT(ok)
|
||||
],
|
||||
[
|
||||
[ac_no_bcg729=1]
|
||||
AC_DEFINE(PJMEDIA_HAS_BCG729,0)
|
||||
LIBS="$SAVED_LIBS"
|
||||
LDFLAGS="$SAVED_LDFLAGS"
|
||||
CFLAGS="$SAVED_CFLAGS"
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
|
||||
])
|
||||
|
||||
|
||||
dnl # Include libyuv
|
||||
AC_SUBST(ac_no_yuv)
|
||||
AC_ARG_ENABLE(libyuv,
|
||||
|
|
|
@ -71,6 +71,7 @@ AC_NO_G722_CODEC=@ac_no_g722_codec@
|
|||
AC_NO_G7221_CODEC=@ac_no_g7221_codec@
|
||||
AC_NO_OPENCORE_AMRNB=@ac_no_opencore_amrnb@
|
||||
AC_NO_OPENCORE_AMRWB=@ac_no_opencore_amrwb@
|
||||
AC_NO_BCG729=@ac_no_bcg729@
|
||||
|
||||
export CODEC_OBJS=
|
||||
|
||||
|
@ -139,6 +140,10 @@ export CODEC_OBJS += opencore_amr.o
|
|||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(AC_NO_BCG729),)
|
||||
export CODEC_OBJS += bcg729.o
|
||||
endif
|
||||
|
||||
|
||||
#
|
||||
# SRTP
|
||||
|
|
|
@ -194,8 +194,9 @@
|
|||
<!-- Override the PlatformToolset -->
|
||||
<PropertyGroup>
|
||||
<PlatformToolset>$(BuildToolset)</PlatformToolset>
|
||||
<CharacterSet Condition="'$(API_Family)'!='WinDesktop'"></CharacterSet>
|
||||
</PropertyGroup>
|
||||
<CharacterSet Condition="'$(API_Family)'!='WinDesktop'">
|
||||
</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
|
@ -510,6 +511,7 @@
|
|||
<ItemGroup>
|
||||
<ClCompile Include="..\src\pjmedia-codec\amr_sdp_match.c" />
|
||||
<ClCompile Include="..\src\pjmedia-codec\audio_codecs.c" />
|
||||
<ClCompile Include="..\src\pjmedia-codec\bcg729.c" />
|
||||
<ClCompile Include="..\src\pjmedia-codec\ffmpeg_vid_codecs.c" />
|
||||
<ClCompile Include="..\src\pjmedia-codec\g722.c" />
|
||||
<ClCompile Include="..\src\pjmedia-codec\g7221.c" />
|
||||
|
@ -534,6 +536,7 @@
|
|||
<ClInclude Include="..\include\pjmedia-codec\amr_helper.h" />
|
||||
<ClInclude Include="..\include\pjmedia-codec\amr_sdp_match.h" />
|
||||
<ClInclude Include="..\include\pjmedia-codec\audio_codecs.h" />
|
||||
<ClInclude Include="..\include\pjmedia-codec\bcg729.h" />
|
||||
<ClInclude Include="..\include\pjmedia-codec\config.h" />
|
||||
<ClInclude Include="..\include\pjmedia-codec\ffmpeg_vid_codecs.h" />
|
||||
<ClInclude Include="..\include\pjmedia-codec\g722.h" />
|
||||
|
|
|
@ -74,6 +74,9 @@
|
|||
<ClCompile Include="..\src\pjmedia-codec\opus.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\pjmedia-codec\bcg729.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\src\pjmedia-codec\g722\g722_dec.h">
|
||||
|
@ -145,5 +148,8 @@
|
|||
<ClInclude Include="..\include\pjmedia-codec\opus.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\include\pjmedia-codec\bcg729.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -40,6 +40,7 @@
|
|||
#include <pjmedia-codec/passthrough.h>
|
||||
#include <pjmedia-codec/silk.h>
|
||||
#include <pjmedia-codec/opus.h>
|
||||
#include <pjmedia-codec/bcg729.h>
|
||||
|
||||
|
||||
#endif /* __PJMEDIA_CODEC_PJMEDIA_CODEC_H__ */
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
* Copyright (C) 2017 Teluu Inc. (http://www.teluu.com)
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef __PJMEDIA_CODEC_BCG729_H__
|
||||
#define __PJMEDIA_CODEC_BCG729_H__
|
||||
|
||||
/**
|
||||
* @file bcg729.h
|
||||
* @brief BCG729 codec.
|
||||
*/
|
||||
|
||||
#include <pjmedia-codec/types.h>
|
||||
|
||||
/**
|
||||
* @defgroup PJMED_BCG729 BCG729 Codec
|
||||
* @ingroup PJMEDIA_CODEC_CODECS
|
||||
* @brief Implementation of BCG729 codecs.
|
||||
* @{
|
||||
*
|
||||
* This section describes functions to initialize and register BCG729 codec
|
||||
* factory to the codec manager. After the codec factory has been registered,
|
||||
* application can use @ref PJMEDIA_CODEC API to manipulate the codec.
|
||||
*
|
||||
* This codec factory contains G.729 codec.
|
||||
*
|
||||
* \section pjmedia_codec_bcg729 BCG729
|
||||
*
|
||||
* BCG729 is compliant with ITU-T G.729 and Annexes A, B specifications.
|
||||
*
|
||||
* BCGG729 supports 16-bit PCM audio signal with sampling rate 8000Hz,
|
||||
* frame length 10ms, and resulting in bitrate 8000bps.
|
||||
*
|
||||
* \subsection codec_setting Codec Settings
|
||||
*
|
||||
* General codec settings for this codec such as VAD and PLC can be
|
||||
* manipulated through the <tt>setting</tt> field in #pjmedia_codec_param.
|
||||
* Please see the documentation of #pjmedia_codec_param for more info.
|
||||
*
|
||||
* Note that G.729 VAD status should be signalled in SDP, see more
|
||||
* description below.
|
||||
*
|
||||
* \subsubsection annexb Annex B
|
||||
*
|
||||
* The capability of VAD/DTX is specified in Annex B.
|
||||
*
|
||||
* By default, Annex B is enabled. This default setting of Annex B can
|
||||
* be modified using #pjmedia_codec_mgr_set_default_param().
|
||||
*
|
||||
* In #pjmedia_codec_param, Annex B is configured via VAD setting and
|
||||
* format parameter "annexb" in the SDP "a=fmtp" attribute in
|
||||
* decoding fmtp field. Valid values are "yes" and "no",
|
||||
* the implementation default is "yes". When this parameter is omitted
|
||||
* in the SDP, the value will be "yes" (RFC 4856 Section 2.1.9).
|
||||
*
|
||||
* Here is an example of modifying default setting of Annex B to
|
||||
* be disabled using #pjmedia_codec_mgr_set_default_param():
|
||||
\code
|
||||
pjmedia_codec_param param;
|
||||
|
||||
pjmedia_codec_mgr_get_default_param(.., ¶m);
|
||||
...
|
||||
// Set VAD
|
||||
param.setting.vad = 0;
|
||||
// Set SDP format parameter
|
||||
param.setting.dec_fmtp.cnt = 1;
|
||||
param.setting.dec_fmtp.param[0].name = pj_str("annexb");
|
||||
param.setting.dec_fmtp.param[0].val = pj_str("no");
|
||||
...
|
||||
pjmedia_codec_mgr_set_default_param(.., ¶m);
|
||||
\endcode
|
||||
*
|
||||
* \note
|
||||
* The difference of Annex B status in SDP offer/answer may be considered as
|
||||
* incompatible codec in SDP negotiation.
|
||||
*
|
||||
*/
|
||||
|
||||
PJ_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* Initialize and register BCG729 codec factory to pjmedia endpoint.
|
||||
*
|
||||
* @param endpt The pjmedia endpoint.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pjmedia_codec_bcg729_init(pjmedia_endpt *endpt);
|
||||
|
||||
/**
|
||||
* Unregister BCG729 codec factory from pjmedia endpoint and deinitialize
|
||||
* the BCG729 codec library.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pjmedia_codec_bcg729_deinit(void);
|
||||
|
||||
|
||||
PJ_END_DECL
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* __PJMEDIA_CODEC_BCG729_H__ */
|
||||
|
|
@ -469,6 +469,17 @@
|
|||
# define PJMEDIA_CODEC_OPUS_DEFAULT_CBR PJ_FALSE
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Enable G.729 codec using BCG729 backend.
|
||||
*
|
||||
* Default: 0
|
||||
*/
|
||||
#ifndef PJMEDIA_HAS_BCG729
|
||||
# define PJMEDIA_HAS_BCG729 0
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Specify if FFMPEG codecs are available.
|
||||
*
|
||||
|
|
|
@ -89,6 +89,11 @@
|
|||
#undef PJMEDIA_HAS_OPUS_CODEC
|
||||
#endif
|
||||
|
||||
/* G.729 codec with BCG729 backend */
|
||||
#ifndef PJMEDIA_HAS_BCG729
|
||||
#undef PJMEDIA_HAS_BCG729
|
||||
#endif
|
||||
|
||||
#endif /* __PJMEDIA_CODEC_CONFIG_AUTO_H_ */
|
||||
|
||||
|
||||
|
|
|
@ -128,6 +128,13 @@ pjmedia_codec_register_audio_codecs(pjmedia_endpt *endpt,
|
|||
return status;
|
||||
#endif
|
||||
|
||||
#if PJMEDIA_HAS_BCG729
|
||||
/* Register BCG729 */
|
||||
status = pjmedia_codec_bcg729_init(endpt);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
#endif
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,622 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
* Copyright (C) 2017 Teluu Inc. (http://www.teluu.com)
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <pjmedia-codec/bcg729.h>
|
||||
#include <pjmedia/codec.h>
|
||||
#include <pjmedia/endpoint.h>
|
||||
#include <pjmedia/errno.h>
|
||||
#include <pjmedia/port.h>
|
||||
#include <pj/pool.h>
|
||||
#include <pj/string.h>
|
||||
#include <pj/assert.h>
|
||||
#include <pj/log.h>
|
||||
|
||||
#if defined(PJMEDIA_HAS_BCG729) && (PJMEDIA_HAS_BCG729!=0)
|
||||
|
||||
#include <bcg729/encoder.h>
|
||||
#include <bcg729/decoder.h>
|
||||
|
||||
#define THIS_FILE "bcg729.c"
|
||||
|
||||
/* Prototypes for BCG729 factory */
|
||||
static pj_status_t bcg729_test_alloc(pjmedia_codec_factory *factory,
|
||||
const pjmedia_codec_info *id);
|
||||
static pj_status_t bcg729_default_attr(pjmedia_codec_factory *factory,
|
||||
const pjmedia_codec_info *id,
|
||||
pjmedia_codec_param *attr);
|
||||
static pj_status_t bcg729_enum_codecs (pjmedia_codec_factory *factory,
|
||||
unsigned *count,
|
||||
pjmedia_codec_info codecs[]);
|
||||
static pj_status_t bcg729_alloc_codec(pjmedia_codec_factory *factory,
|
||||
const pjmedia_codec_info *id,
|
||||
pjmedia_codec **p_codec);
|
||||
static pj_status_t bcg729_dealloc_codec(pjmedia_codec_factory *factory,
|
||||
pjmedia_codec *codec);
|
||||
|
||||
/* Prototypes for BCG729 implementation. */
|
||||
static pj_status_t bcg729_codec_init(pjmedia_codec *codec,
|
||||
pj_pool_t *pool );
|
||||
static pj_status_t bcg729_codec_open(pjmedia_codec *codec,
|
||||
pjmedia_codec_param *attr);
|
||||
static pj_status_t bcg729_codec_close(pjmedia_codec *codec);
|
||||
static pj_status_t bcg729_codec_modify(pjmedia_codec *codec,
|
||||
const pjmedia_codec_param *attr);
|
||||
static pj_status_t bcg729_codec_parse(pjmedia_codec *codec,
|
||||
void *pkt,
|
||||
pj_size_t pkt_size,
|
||||
const pj_timestamp *timestamp,
|
||||
unsigned *frame_cnt,
|
||||
pjmedia_frame frames[]);
|
||||
static pj_status_t bcg729_codec_encode(pjmedia_codec *codec,
|
||||
const struct pjmedia_frame *input,
|
||||
unsigned output_buf_len,
|
||||
struct pjmedia_frame *output);
|
||||
static pj_status_t bcg729_codec_decode(pjmedia_codec *codec,
|
||||
const struct pjmedia_frame *input,
|
||||
unsigned output_buf_len,
|
||||
struct pjmedia_frame *output);
|
||||
static pj_status_t bcg729_codec_recover(pjmedia_codec *codec,
|
||||
unsigned output_buf_len,
|
||||
struct pjmedia_frame *output);
|
||||
|
||||
/* Codec const. */
|
||||
#define G729_TAG "G729"
|
||||
#define G729_CLOCK_RATE 8000
|
||||
#define G729_CHANNEL_COUNT 1
|
||||
#define G729_SAMPLES_PER_FRAME 80
|
||||
#define G729_DEFAULT_BIT_RATE 8000
|
||||
#define G729_MAX_BIT_RATE 11800
|
||||
#define G729_FRAME_PER_PACKET 2
|
||||
#define G729_FRAME_SIZE 10
|
||||
|
||||
/* Definition for BCG729 codec operations. */
|
||||
static pjmedia_codec_op bcg729_op =
|
||||
{
|
||||
&bcg729_codec_init,
|
||||
&bcg729_codec_open,
|
||||
&bcg729_codec_close,
|
||||
&bcg729_codec_modify,
|
||||
&bcg729_codec_parse,
|
||||
&bcg729_codec_encode,
|
||||
&bcg729_codec_decode,
|
||||
&bcg729_codec_recover
|
||||
};
|
||||
|
||||
/* Definition for BCG729 codec factory operations. */
|
||||
static pjmedia_codec_factory_op bcg729_factory_op =
|
||||
{
|
||||
&bcg729_test_alloc,
|
||||
&bcg729_default_attr,
|
||||
&bcg729_enum_codecs,
|
||||
&bcg729_alloc_codec,
|
||||
&bcg729_dealloc_codec,
|
||||
&pjmedia_codec_bcg729_deinit
|
||||
};
|
||||
|
||||
|
||||
/* BCG729 factory private data */
|
||||
static struct bcg729_factory
|
||||
{
|
||||
pjmedia_codec_factory base;
|
||||
pjmedia_endpt *endpt;
|
||||
pj_pool_t *pool;
|
||||
pj_mutex_t *mutex;
|
||||
} bcg729_factory;
|
||||
|
||||
|
||||
/* BCG729 codec private data. */
|
||||
typedef struct bcg729_private
|
||||
{
|
||||
pj_pool_t *pool; /**< Pool for each instance. */
|
||||
|
||||
bcg729EncoderChannelContextStruct *encoder;
|
||||
bcg729DecoderChannelContextStruct *decoder;
|
||||
|
||||
pj_bool_t vad_enabled;
|
||||
pj_bool_t plc_enabled;
|
||||
} bcg729_private;
|
||||
|
||||
|
||||
PJ_DEF(pj_status_t) pjmedia_codec_bcg729_init(pjmedia_endpt *endpt)
|
||||
{
|
||||
pjmedia_codec_mgr *codec_mgr;
|
||||
pj_status_t status;
|
||||
|
||||
if (bcg729_factory.endpt != NULL) {
|
||||
/* Already initialized. */
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* Init factory */
|
||||
pj_bzero(&bcg729_factory, sizeof(bcg729_factory));
|
||||
bcg729_factory.base.op = &bcg729_factory_op;
|
||||
bcg729_factory.base.factory_data = NULL;
|
||||
bcg729_factory.endpt = endpt;
|
||||
|
||||
/* Create pool */
|
||||
bcg729_factory.pool = pjmedia_endpt_create_pool(endpt, "bcg729", 4000,
|
||||
4000);
|
||||
if (!bcg729_factory.pool)
|
||||
return PJ_ENOMEM;
|
||||
|
||||
/* Create mutex. */
|
||||
status = pj_mutex_create_simple(bcg729_factory.pool, "bcg729",
|
||||
&bcg729_factory.mutex);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
/* Get the codec manager. */
|
||||
codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
|
||||
if (!codec_mgr) {
|
||||
status = PJ_EINVALIDOP;
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
/* Register codec factory to endpoint. */
|
||||
status = pjmedia_codec_mgr_register_factory(codec_mgr,
|
||||
&bcg729_factory.base);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
PJ_LOG(4,(THIS_FILE, "BCG729 codec initialized"));
|
||||
return PJ_SUCCESS;
|
||||
|
||||
on_error:
|
||||
if (bcg729_factory.mutex) {
|
||||
pj_mutex_destroy(bcg729_factory.mutex);
|
||||
bcg729_factory.mutex = NULL;
|
||||
}
|
||||
if (bcg729_factory.pool) {
|
||||
pj_pool_release(bcg729_factory.pool);
|
||||
bcg729_factory.pool = NULL;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unregister BCG729 codec factory from pjmedia endpoint and deinitialize
|
||||
* the BCG729 codec library.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pjmedia_codec_bcg729_deinit(void)
|
||||
{
|
||||
pjmedia_codec_mgr *codec_mgr;
|
||||
pj_status_t status;
|
||||
|
||||
if (bcg729_factory.endpt == NULL) {
|
||||
/* Not registered. */
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* Lock mutex. */
|
||||
pj_mutex_lock(bcg729_factory.mutex);
|
||||
|
||||
/* Get the codec manager. */
|
||||
codec_mgr = pjmedia_endpt_get_codec_mgr(bcg729_factory.endpt);
|
||||
if (!codec_mgr) {
|
||||
bcg729_factory.endpt = NULL;
|
||||
pj_mutex_unlock(bcg729_factory.mutex);
|
||||
return PJ_EINVALIDOP;
|
||||
}
|
||||
|
||||
/* Unregister bcg729 codec factory. */
|
||||
status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
|
||||
&bcg729_factory.base);
|
||||
bcg729_factory.endpt = NULL;
|
||||
|
||||
/* Destroy mutex. */
|
||||
pj_mutex_unlock(bcg729_factory.mutex);
|
||||
pj_mutex_destroy(bcg729_factory.mutex);
|
||||
bcg729_factory.mutex = NULL;
|
||||
|
||||
/* Release pool. */
|
||||
pj_pool_release(bcg729_factory.pool);
|
||||
bcg729_factory.pool = NULL;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check if factory can allocate the specified codec.
|
||||
*/
|
||||
static pj_status_t bcg729_test_alloc(pjmedia_codec_factory *factory,
|
||||
const pjmedia_codec_info *info )
|
||||
{
|
||||
pj_str_t g729_tag = pj_str(G729_TAG);
|
||||
PJ_UNUSED_ARG(factory);
|
||||
PJ_ASSERT_RETURN(factory==&bcg729_factory.base, PJ_EINVAL);
|
||||
|
||||
/* Type MUST be audio. */
|
||||
if (info->type != PJMEDIA_TYPE_AUDIO)
|
||||
return PJMEDIA_CODEC_EUNSUP;
|
||||
|
||||
/* Check encoding name. */
|
||||
if (pj_stricmp(&info->encoding_name, &g729_tag) != 0)
|
||||
return PJMEDIA_CODEC_EUNSUP;
|
||||
|
||||
/* Channel count must be one */
|
||||
if (info->channel_cnt != G729_CHANNEL_COUNT)
|
||||
return PJMEDIA_CODEC_EUNSUP;
|
||||
|
||||
/* Check clock-rate */
|
||||
if (info->clock_rate != G729_CLOCK_RATE)
|
||||
return PJMEDIA_CODEC_EUNSUP;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Generate default attribute.
|
||||
*/
|
||||
static pj_status_t bcg729_default_attr(pjmedia_codec_factory *factory,
|
||||
const pjmedia_codec_info *id,
|
||||
pjmedia_codec_param *attr )
|
||||
{
|
||||
PJ_ASSERT_RETURN(factory==&bcg729_factory.base, PJ_EINVAL);
|
||||
|
||||
if (id->pt != PJMEDIA_RTP_PT_G729)
|
||||
return PJMEDIA_CODEC_EUNSUP;
|
||||
|
||||
pj_bzero(attr, sizeof(pjmedia_codec_param));
|
||||
attr->info.pt = PJMEDIA_RTP_PT_G729;
|
||||
attr->info.channel_cnt = G729_CHANNEL_COUNT;
|
||||
attr->info.clock_rate = G729_CLOCK_RATE;
|
||||
attr->info.avg_bps = G729_DEFAULT_BIT_RATE;
|
||||
attr->info.max_bps = G729_MAX_BIT_RATE;
|
||||
|
||||
attr->info.pcm_bits_per_sample = G729_FRAME_PER_PACKET * 8;
|
||||
attr->info.frm_ptime = (pj_uint16_t)
|
||||
(G729_SAMPLES_PER_FRAME * 1000 /
|
||||
G729_CHANNEL_COUNT /
|
||||
G729_CLOCK_RATE);
|
||||
attr->setting.frm_per_pkt = G729_FRAME_PER_PACKET;
|
||||
|
||||
/* Default flags. */
|
||||
attr->setting.plc = 1;
|
||||
attr->setting.penh= 0;
|
||||
attr->setting.vad = 1;
|
||||
attr->setting.cng = attr->setting.vad;
|
||||
|
||||
if (attr->setting.vad == 0) {
|
||||
attr->setting.dec_fmtp.cnt = 1;
|
||||
pj_strset2(&attr->setting.dec_fmtp.param[0].name, "annexb");
|
||||
pj_strset2(&attr->setting.dec_fmtp.param[0].val, "no");
|
||||
}
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Enum codecs supported by this factory.
|
||||
*/
|
||||
static pj_status_t bcg729_enum_codecs(pjmedia_codec_factory *factory,
|
||||
unsigned *count,
|
||||
pjmedia_codec_info codecs[])
|
||||
{
|
||||
PJ_ASSERT_RETURN(factory==&bcg729_factory.base, PJ_EINVAL);
|
||||
PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
|
||||
|
||||
pj_bzero(&codecs[0], sizeof(pjmedia_codec_info));
|
||||
codecs[0].encoding_name = pj_str(G729_TAG);
|
||||
codecs[0].pt = PJMEDIA_RTP_PT_G729;
|
||||
codecs[0].type = PJMEDIA_TYPE_AUDIO;
|
||||
codecs[0].clock_rate = G729_CLOCK_RATE;
|
||||
codecs[0].channel_cnt = G729_CHANNEL_COUNT;
|
||||
|
||||
*count = 1;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Allocate a new BCG729 codec instance.
|
||||
*/
|
||||
static pj_status_t bcg729_alloc_codec(pjmedia_codec_factory *factory,
|
||||
const pjmedia_codec_info *id,
|
||||
pjmedia_codec **p_codec)
|
||||
{
|
||||
pj_pool_t *pool;
|
||||
pjmedia_codec *codec;
|
||||
bcg729_private *bcg729_data;
|
||||
|
||||
PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
|
||||
PJ_ASSERT_RETURN(factory == &bcg729_factory.base, PJ_EINVAL);
|
||||
|
||||
pj_mutex_lock(bcg729_factory.mutex);
|
||||
|
||||
/* Create pool for codec instance */
|
||||
pool = pjmedia_endpt_create_pool(bcg729_factory.endpt, "bcg729", 512, 512);
|
||||
|
||||
/* Allocate codec */
|
||||
codec = PJ_POOL_ZALLOC_T(pool, pjmedia_codec);
|
||||
codec->op = &bcg729_op;
|
||||
codec->factory = factory;
|
||||
codec->codec_data = PJ_POOL_ZALLOC_T(pool, bcg729_private);
|
||||
bcg729_data = (bcg729_private*) codec->codec_data;
|
||||
bcg729_data->pool = pool;
|
||||
|
||||
pj_mutex_unlock(bcg729_factory.mutex);
|
||||
|
||||
*p_codec = codec;
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Free codec.
|
||||
*/
|
||||
static pj_status_t bcg729_dealloc_codec(pjmedia_codec_factory *factory,
|
||||
pjmedia_codec *codec )
|
||||
{
|
||||
bcg729_private *bcg729_data;
|
||||
|
||||
PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
|
||||
PJ_ASSERT_RETURN(factory == &bcg729_factory.base, PJ_EINVAL);
|
||||
|
||||
bcg729_data = (bcg729_private*)codec->codec_data;
|
||||
|
||||
/* Close codec, if it's not closed. */
|
||||
if (bcg729_data->encoder || bcg729_data->decoder) {
|
||||
bcg729_codec_close(codec);
|
||||
}
|
||||
|
||||
pj_pool_release(bcg729_data->pool);
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Init codec.
|
||||
*/
|
||||
static pj_status_t bcg729_codec_init(pjmedia_codec *codec,
|
||||
pj_pool_t *pool )
|
||||
{
|
||||
PJ_UNUSED_ARG(codec);
|
||||
PJ_UNUSED_ARG(pool);
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Open codec.
|
||||
*/
|
||||
static pj_status_t bcg729_codec_open(pjmedia_codec *codec,
|
||||
pjmedia_codec_param *attr )
|
||||
{
|
||||
bcg729_private *bcg729_data;
|
||||
unsigned i;
|
||||
|
||||
PJ_ASSERT_RETURN(codec && attr, PJ_EINVAL);
|
||||
|
||||
bcg729_data = (bcg729_private*) codec->codec_data;
|
||||
|
||||
/* Already open? */
|
||||
if (bcg729_data->encoder && bcg729_data->decoder)
|
||||
return PJ_SUCCESS;
|
||||
|
||||
bcg729_data->vad_enabled = (attr->setting.vad != 0);
|
||||
bcg729_data->plc_enabled = (attr->setting.plc != 0);
|
||||
|
||||
/* Check if G729 Annex B is signaled to be disabled */
|
||||
for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
|
||||
if (pj_stricmp2(&attr->setting.enc_fmtp.param[i].name, "annexb")==0)
|
||||
{
|
||||
if (pj_stricmp2(&attr->setting.enc_fmtp.param[i].val, "no")==0)
|
||||
{
|
||||
attr->setting.vad = 0;
|
||||
bcg729_data->vad_enabled = PJ_FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bcg729_data->encoder = initBcg729EncoderChannel(
|
||||
bcg729_data->vad_enabled?1:0);
|
||||
if (!bcg729_data->encoder)
|
||||
return PJMEDIA_CODEC_EFAILED;
|
||||
|
||||
bcg729_data->decoder = initBcg729DecoderChannel();
|
||||
if (!bcg729_data->decoder)
|
||||
return PJMEDIA_CODEC_EFAILED;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Close codec.
|
||||
*/
|
||||
static pj_status_t bcg729_codec_close( pjmedia_codec *codec )
|
||||
{
|
||||
bcg729_private *bcg729_data;
|
||||
|
||||
PJ_ASSERT_RETURN(codec, PJ_EINVAL);
|
||||
|
||||
bcg729_data = (bcg729_private *)codec->codec_data;
|
||||
|
||||
if (bcg729_data->encoder) {
|
||||
closeBcg729EncoderChannel(bcg729_data->encoder);
|
||||
bcg729_data->encoder = NULL;
|
||||
}
|
||||
if (bcg729_data->decoder) {
|
||||
closeBcg729DecoderChannel(bcg729_data->decoder);
|
||||
bcg729_data->decoder = NULL;
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get frames in the packet.
|
||||
*/
|
||||
static pj_status_t bcg729_codec_parse(pjmedia_codec *codec,
|
||||
void *pkt,
|
||||
pj_size_t pkt_size,
|
||||
const pj_timestamp *ts,
|
||||
unsigned *frame_cnt,
|
||||
pjmedia_frame frames[])
|
||||
{
|
||||
unsigned count = 0;
|
||||
PJ_UNUSED_ARG(codec);
|
||||
|
||||
PJ_ASSERT_RETURN(codec && ts && frames && frame_cnt, PJ_EINVAL);
|
||||
|
||||
while (pkt_size >= G729_FRAME_SIZE && count < *frame_cnt) {
|
||||
frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
|
||||
frames[count].buf = pkt;
|
||||
frames[count].size = G729_FRAME_SIZE;
|
||||
frames[count].timestamp.u64 = ts->u64 + count * G729_SAMPLES_PER_FRAME;
|
||||
|
||||
pkt = ((char*)pkt) + 10;
|
||||
pkt_size -= 10;
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
*frame_cnt = count;
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Modify codec settings.
|
||||
*/
|
||||
static pj_status_t bcg729_codec_modify(pjmedia_codec *codec,
|
||||
const pjmedia_codec_param *attr )
|
||||
{
|
||||
PJ_UNUSED_ARG(codec);
|
||||
PJ_UNUSED_ARG(attr);
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Encode frame.
|
||||
*/
|
||||
static pj_status_t bcg729_codec_encode(pjmedia_codec *codec,
|
||||
const struct pjmedia_frame *input,
|
||||
unsigned output_buf_len,
|
||||
struct pjmedia_frame *output)
|
||||
{
|
||||
bcg729_private *bcg729_data;
|
||||
pj_int16_t *pcm_in;
|
||||
unsigned nsamples;
|
||||
pj_uint8_t stream_len;
|
||||
|
||||
PJ_ASSERT_RETURN(codec && input && output_buf_len && output, PJ_EINVAL);
|
||||
|
||||
bcg729_data = (bcg729_private*)codec->codec_data;
|
||||
pcm_in = (pj_int16_t*)input->buf;
|
||||
|
||||
/* Check frame in size */
|
||||
nsamples = input->size >> 1;
|
||||
output->size = 0;
|
||||
|
||||
/* Encode */
|
||||
while (nsamples >= G729_SAMPLES_PER_FRAME) {
|
||||
bcg729Encoder(bcg729_data->encoder, pcm_in,
|
||||
(unsigned char*)output->buf + output->size, &stream_len);
|
||||
|
||||
pcm_in += G729_SAMPLES_PER_FRAME;
|
||||
nsamples -= G729_SAMPLES_PER_FRAME;
|
||||
|
||||
if (stream_len == 0) {
|
||||
/* Untransmitted */
|
||||
break;
|
||||
} else {
|
||||
output->size += stream_len;
|
||||
if (stream_len == 2) {
|
||||
/* SID */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output->type = PJMEDIA_FRAME_TYPE_AUDIO;
|
||||
output->timestamp = input->timestamp;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static pj_status_t bcg729_codec_decode(pjmedia_codec *codec,
|
||||
const struct pjmedia_frame *input,
|
||||
unsigned output_buf_len,
|
||||
struct pjmedia_frame *output)
|
||||
{
|
||||
bcg729_private *bcg729_data;
|
||||
|
||||
PJ_ASSERT_RETURN(codec && input && output_buf_len && output, PJ_EINVAL);
|
||||
|
||||
bcg729_data = (struct bcg729_private*) codec->codec_data;
|
||||
|
||||
bcg729Decoder(bcg729_data->decoder,
|
||||
(unsigned char*)input->buf,
|
||||
G729_FRAME_SIZE,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
(short*)output->buf);
|
||||
|
||||
output->size = G729_SAMPLES_PER_FRAME * G729_FRAME_PER_PACKET;
|
||||
output->type = PJMEDIA_FRAME_TYPE_AUDIO;
|
||||
output->timestamp = input->timestamp;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Recover lost frame.
|
||||
*/
|
||||
static pj_status_t bcg729_codec_recover(pjmedia_codec *codec,
|
||||
unsigned output_buf_len,
|
||||
struct pjmedia_frame *output)
|
||||
{
|
||||
bcg729_private *bcg729_data;
|
||||
|
||||
PJ_ASSERT_RETURN(codec && output_buf_len && output, PJ_EINVAL);
|
||||
|
||||
bcg729_data = (struct bcg729_private*) codec->codec_data;
|
||||
|
||||
output->size = G729_SAMPLES_PER_FRAME * G729_FRAME_PER_PACKET;
|
||||
output->type = PJMEDIA_FRAME_TYPE_AUDIO;
|
||||
|
||||
if (bcg729_data->plc_enabled) {
|
||||
bcg729Decoder(bcg729_data->decoder,
|
||||
NULL,
|
||||
G729_FRAME_SIZE,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
(short*)output->buf);
|
||||
} else {
|
||||
pjmedia_zero_samples((pj_int16_t*)output->buf, G729_SAMPLES_PER_FRAME);
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
#endif /* PJMEDIA_HAS_BCG729 */
|
Loading…
Reference in New Issue