Fixed #1904: Support for Opus codec

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@5239 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
Sauw Ming 2016-02-04 06:11:58 +00:00
parent f748884498
commit d3ece1d774
13 changed files with 1513 additions and 1 deletions

View File

@ -623,6 +623,9 @@ LIBOBJS
ac_main_obj
ac_host
ac_linux_poll
opus_present
opus_h_present
ac_no_opus
silk_present
silk_h_present
ac_no_silk
@ -816,6 +819,8 @@ with_opencore_amrwbenc
enable_opencore_amr
with_silk
enable_silk
with_opus
enable_opus
'
ac_precious_vars='build_alias
host_alias
@ -1482,6 +1487,9 @@ Optional Features:
--disable-silk Exclude SILK support from the build (default:
autodetect)
--disable-opus Exclude OPUS support from the build (default:
autodetect)
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
@ -1523,6 +1531,7 @@ Optional Packages:
--with-opencore-amrwbenc=DIR
Specify alternate libvo-amrwbenc prefix
--with-silk=DIR Specify alternate SILK prefix
--with-opus=DIR Specify alternate OPUS prefix
Some influential environment variables:
CC C compiler command
@ -8226,6 +8235,107 @@ $as_echo "SILK library found, SILK support enabled" >&6; }
fi
if test "x$ac_cross_compile" != "x" -a "x$with_opus" = "xno"; then
enable_opus=no
fi
# Check whether --with-opus was given.
if test "${with_opus+set}" = set; then :
withval=$with_opus;
else
with_opus=no
fi
# Check whether --enable-opus was given.
if test "${enable_opus+set}" = set; then :
enableval=$enable_opus;
if test "$enable_opus" = "no"; then
ac_no_opus=1
$as_echo "#define PJMEDIA_HAS_OPUS_CODEC 0" >>confdefs.h
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Checking if OPUS support is disabled... yes" >&5
$as_echo "Checking if OPUS support is disabled... yes" >&6; }
fi
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: checking for OPUS installations.." >&5
$as_echo "checking for OPUS installations.." >&6; }
if test "x$with_opus" != "xno" -a "x$with_opus" != "x"; then
CFLAGS="$CFLAGS -I$with_opus/include"
CPPFLAGS="$CPPFLAGS -I$with_opus/include"
LDFLAGS="$LDFLAGS -L$with_opus/lib"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Using OPUS prefix... $with_opus" >&5
$as_echo "Using OPUS prefix... $with_opus" >&6; }
fi
ac_fn_c_check_header_mongrel "$LINENO" "opus/opus.h" "ac_cv_header_opus_opus_h" "$ac_includes_default"
if test "x$ac_cv_header_opus_opus_h" = xyes; then :
opus_h_present=1
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for opus_repacketizer_get_size in -lopus" >&5
$as_echo_n "checking for opus_repacketizer_get_size in -lopus... " >&6; }
if ${ac_cv_lib_opus_opus_repacketizer_get_size+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-lopus $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char opus_repacketizer_get_size ();
int
main ()
{
return opus_repacketizer_get_size ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_opus_opus_repacketizer_get_size=yes
else
ac_cv_lib_opus_opus_repacketizer_get_size=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_opus_opus_repacketizer_get_size" >&5
$as_echo "$ac_cv_lib_opus_opus_repacketizer_get_size" >&6; }
if test "x$ac_cv_lib_opus_opus_repacketizer_get_size" = xyes; then :
opus_present=1 && LIBS="$LIBS -lopus"
fi
if test "x$opus_h_present" = "x1" -a "x$opus_present" = "x1"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: OPUS library found, OPUS support enabled" >&5
$as_echo "OPUS library found, OPUS support enabled" >&6; }
$as_echo "#define PJMEDIA_HAS_OPUS_CODEC 1" >>confdefs.h
else
ac_no_opus=1
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: OPUS library not found, OPUS support disabled" >&5
$as_echo "OPUS library not found, OPUS support disabled" >&6; }
$as_echo "#define PJMEDIA_HAS_OPUS_CODEC 0" >>confdefs.h
fi
fi

View File

@ -1761,6 +1761,54 @@ AC_ARG_ENABLE(silk,
fi
])
dnl # Do not use default OPUS installation if we are cross-compiling
if test "x$ac_cross_compile" != "x" -a "x$with_opus" = "xno"; then
enable_opus=no
fi
dnl # OPUS prefix
AC_ARG_WITH(opus,
AC_HELP_STRING([--with-opus=DIR],
[Specify alternate OPUS prefix]),
[],
[with_opus=no]
)
dnl # Include OPUS support
AC_SUBST(ac_no_opus)
AC_ARG_ENABLE(opus,
AC_HELP_STRING([--disable-opus],
[Exclude OPUS support from the build (default: autodetect)])
,
[
if test "$enable_opus" = "no"; then
[ac_no_opus=1]
AC_DEFINE(PJMEDIA_HAS_OPUS_CODEC,0)
AC_MSG_RESULT([Checking if OPUS support is disabled... yes])
fi
],
[
AC_MSG_RESULT([checking for OPUS installations..])
if test "x$with_opus" != "xno" -a "x$with_opus" != "x"; then
CFLAGS="$CFLAGS -I$with_opus/include"
CPPFLAGS="$CPPFLAGS -I$with_opus/include"
LDFLAGS="$LDFLAGS -L$with_opus/lib"
AC_MSG_RESULT([Using OPUS prefix... $with_opus])
fi
AC_SUBST(opus_h_present)
AC_SUBST(opus_present)
AC_CHECK_HEADER(opus/opus.h,[opus_h_present=1])
AC_CHECK_LIB(opus,opus_repacketizer_get_size,[opus_present=1 && LIBS="$LIBS -lopus"])
if test "x$opus_h_present" = "x1" -a "x$opus_present" = "x1"; then
AC_MSG_RESULT([OPUS library found, OPUS support enabled])
AC_DEFINE(PJMEDIA_HAS_OPUS_CODEC,1)
else
[ac_no_opus=1]
AC_MSG_RESULT([OPUS library not found, OPUS support disabled])
AC_DEFINE(PJMEDIA_HAS_OPUS_CODEC,0)
fi
])
dnl ##########################################
dnl #

View File

@ -138,7 +138,7 @@ export PJMEDIA_CODEC_SRCDIR = ../src/pjmedia-codec
export PJMEDIA_CODEC_OBJS += audio_codecs.o ffmpeg_vid_codecs.o openh264.o \
h263_packetizer.o h264_packetizer.o \
$(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
ipp_codecs.o silk.o $(CODEC_OBJS) \
ipp_codecs.o silk.o opus.o $(CODEC_OBJS) \
g7221_sdp_match.o amr_sdp_match.o
export PJMEDIA_CODEC_CFLAGS += $(_CFLAGS) $(GSM_CFLAGS) $(SPEEX_CFLAGS) \
$(ILBC_CFLAGS) $(IPP_CFLAGS) $(G7221_CFLAGS)

View File

@ -38,6 +38,7 @@
#include <pjmedia-codec/openh264.h>
#include <pjmedia-codec/passthrough.h>
#include <pjmedia-codec/silk.h>
#include <pjmedia-codec/opus.h>
#endif /* __PJMEDIA_CODEC_PJMEDIA_CODEC_H__ */

View File

@ -419,6 +419,56 @@
#endif
/**
* Enable OPUS codec.
*
* Default: 0
*/
#ifndef PJMEDIA_HAS_OPUS_CODEC
# define PJMEDIA_HAS_OPUS_CODEC 0
#endif
/**
* OPUS codec sample rate.
*
* Default: 48000
*/
#ifndef PJMEDIA_CODEC_OPUS_DEFAULT_SAMPLE_RATE
# define PJMEDIA_CODEC_OPUS_DEFAULT_SAMPLE_RATE 48000
#endif
/**
* OPUS codec default maximum average bit rate.
*
* Default: 0 (leave it to default value specified by Opus, which will
* take into account factors such as media content (speech/music), sample
* rate, channel count, etc).
*/
#ifndef PJMEDIA_CODEC_OPUS_DEFAULT_BIT_RATE
# define PJMEDIA_CODEC_OPUS_DEFAULT_BIT_RATE 0
#endif
/**
* OPUS default encoding complexity, which is an integer from
* 0 to 10, where 0 is the lowest complexity and 10 is the highest.
*
* Default: 5
*/
#ifndef PJMEDIA_CODEC_OPUS_DEFAULT_COMPLEXITY
# define PJMEDIA_CODEC_OPUS_DEFAULT_COMPLEXITY 5
#endif
/**
* OPUS default CBR (constant bit rate) setting
*
* Default: PJ_FALSE (which means Opus will use VBR (variable bit rate))
*/
#ifndef PJMEDIA_CODEC_OPUS_DEFAULT_CBR
# define PJMEDIA_CODEC_OPUS_DEFAULT_CBR PJ_FALSE
#endif
/**
* Specify if FFMPEG codecs are available.
*

View File

@ -84,6 +84,11 @@
#undef PJMEDIA_HAS_SILK_CODEC
#endif
/* OPUS codec */
#ifndef PJMEDIA_HAS_OPUS_CODEC
#undef PJMEDIA_HAS_OPUS_CODEC
#endif
#endif /* __PJMEDIA_CODEC_CONFIG_AUTO_H_ */

View File

@ -0,0 +1,155 @@
/* $Id$ */
/*
* Copyright (C) 2015-2016 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2012-2015 Zaark Technology AB
*
* 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
*/
/* This file is the header of Opus codec wrapper and was contributed by
* Zaark Technology AB
*/
#ifndef __PJMEDIA_CODEC_OPUS_H__
#define __PJMEDIA_CODEC_OPUS_H__
/**
* @file opus.h
* @brief Opus codec.
*/
#include <pjmedia-codec/types.h>
PJ_BEGIN_DECL
/**
* @defgroup PJMED_OPUS Opus Codec Family
* @ingroup PJMEDIA_CODEC_CODECS
* @brief Opus codec wrapper
* @{
*
* This section describes functions to initialize and register Opus codec
* factory to the codec manager. After the codec factory has been registered,
* application can use @ref PJMEDIA_CODEC API to manipulate the codec.
*
* Opus codec uses multiple bit rates, and supports fullband (48 kHz
* sampling rate), super wideband (24 kHz sampling rate), wideband (16 kHz
* sampling rate), medium band (12kHz sampling rate), and narrowband
* (8 kHz sampling rate).
*
*
* \section 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
* (see the documentation of #pjmedia_codec_param for more info).
*
* For Opus codec specific settings, such as sample rate,
* channel count, bit rate, complexity, and CBR, can be configured
* in #pjmedia_codec_opus_config.
* The default setting of sample rate is specified in
* #PJMEDIA_CODEC_OPUS_DEFAULT_SAMPLE_RATE. The default setting of
* bitrate is specified in #PJMEDIA_CODEC_OPUS_DEFAULT_BIT_RATE.
* And the default setting of complexity is specified in
* #PJMEDIA_CODEC_OPUS_DEFAULT_COMPLEXITY.
*
* After modifying any of these settings, application needs to call
* #pjmedia_codec_opus_set_default_param(), which will generate the
* appropriate decoding fmtp attributes.
*
* Here is an example of modifying the codec settings:
\code
pjmedia_codec_param param;
pjmedia_codec_opus_config opus_cfg;
pjmedia_codec_mgr_get_default_param(.., &param);
pjmedia_codec_opus_get_config(&opus_cfg);
...
// Set VAD
param.setting.vad = 1;
// Set PLC
param.setting.vad = 1;
// Set sample rate
opus_cfg.sample_rate = 16000;
// Set channel count
opus_cfg.channel_cnt = 2;
// Set bit rate
opus_cfg.bit_rate = 20000;
...
pjmedia_codec_opus_set_default_param(&opus_cfg, &param);
\endcode
*
*/
/**
* Opus codec configuration.
*/
typedef struct pjmedia_codec_opus_config
{
unsigned sample_rate; /**< Sample rate in Hz. */
unsigned channel_cnt; /**< Number of channels. */
unsigned bit_rate; /**< Encoder bit rate in bps. */
unsigned packet_loss; /**< Encoder's expected packet loss pct. */
unsigned complexity; /**< Encoder complexity, 0-10(10 is highest)*/
pj_bool_t cbr; /**< Constant bit rate? */
} pjmedia_codec_opus_config;
/**
* Initialize and register Opus codec factory to pjmedia endpoint.
*
* @param endpt The pjmedia endpoint.
*
* @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t) pjmedia_codec_opus_init( pjmedia_endpt *endpt );
/**
* Unregister Opus codec factory from pjmedia endpoint and deinitialize
* the Opus codec library.
*
* @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t) pjmedia_codec_opus_deinit( void );
/**
* Get the default Opus configuration.
*
* @param cfg Opus codec configuration.
*
* @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t)
pjmedia_codec_opus_get_config( pjmedia_codec_opus_config *cfg );
/**
* Set the default Opus configuration and set the default Opus codec param.
* Note that the function will call #pjmedia_codec_mgr_set_default_param().
*
* @param cfg Opus codec configuration.
* @param param The new default Opus codec parameter.
*
* @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t)
pjmedia_codec_opus_set_default_param(const pjmedia_codec_opus_config *cfg,
pjmedia_codec_param *param );
PJ_END_DECL
/**
* @}
*/
#endif /* __PJMEDIA_CODEC_OPUS_H__ */

View File

@ -83,6 +83,7 @@ enum pjmedia_audio_pt
PJMEDIA_RTP_PT_G7221C_48, /**< G722.1 Annex C (48Kbps)*/
PJMEDIA_RTP_PT_G7221_RSV1, /**< G722.1 reserve */
PJMEDIA_RTP_PT_G7221_RSV2, /**< G722.1 reserve */
PJMEDIA_RTP_PT_OPUS, /**< OPUS */
PJMEDIA_RTP_PT_L16_8KHZ_MONO, /**< L16 @ 8KHz, mono */
PJMEDIA_RTP_PT_L16_8KHZ_STEREO, /**< L16 @ 8KHz, stereo */
//PJMEDIA_RTP_PT_L16_11KHZ_MONO, /**< L16 @ 11KHz, mono */

View File

@ -972,6 +972,7 @@
* See:
* - G.722 : RFC 3551 4.5.2
* - MPEG audio : RFC 3551 4.5.13 & RFC 3119
* - OPUS : RFC 7587
*
* Also when this feature is enabled, some handling will be performed
* to deal with clock rate incompatibilities of some phones.

View File

@ -121,6 +121,13 @@ pjmedia_codec_register_audio_codecs(pjmedia_endpt *endpt,
return status;
#endif
#if PJMEDIA_HAS_OPUS_CODEC
/* Register OPUS */
status = pjmedia_codec_opus_init(endpt);
if (status != PJ_SUCCESS)
return status;
#endif
return PJ_SUCCESS;
}

File diff suppressed because it is too large Load Diff

View File

@ -2109,6 +2109,15 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt,
goto err_cleanup;
/* Open the codec. */
/* The clock rate for Opus codec is not static,
* it's negotiated in the SDP.
*/
if (!pj_stricmp2(&info->fmt.encoding_name, "opus")) {
stream->codec_param.info.clock_rate = info->fmt.clock_rate;
stream->codec_param.info.channel_cnt = info->fmt.channel_cnt;
}
status = pjmedia_codec_open(stream->codec, &stream->codec_param);
if (status != PJ_SUCCESS)
goto err_cleanup;
@ -2223,6 +2232,12 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt,
stream->has_g722_mpeg_bug = PJ_TRUE;
/* RTP clock rate = 1/2 real clock rate */
stream->rtp_tx_ts_len_per_pkt >>= 1;
} else if (!pj_stricmp2(&info->fmt.encoding_name, "opus")) {
unsigned opus_ts_modifier = 48000 / afd->clock_rate;
stream->rtp_rx_check_cnt = 0;
stream->has_g722_mpeg_bug = PJ_TRUE;
stream->rtp_tx_ts_len_per_pkt *= opus_ts_modifier;
stream->rtp_rx_ts_len_per_frame *= opus_ts_modifier;
}
#endif

View File

@ -33,6 +33,47 @@ static const pj_str_t ID_RTP_SAVP = { "RTP/SAVP", 8 };
static const pj_str_t ID_RTPMAP = { "rtpmap", 6 };
static const pj_str_t ID_TELEPHONE_EVENT = { "telephone-event", 15 };
static void get_opus_channels_and_clock_rate(const pjmedia_codec_fmtp *enc_fmtp,
const pjmedia_codec_fmtp *dec_fmtp,
unsigned *channel_cnt,
unsigned *clock_rate)
{
unsigned i;
unsigned enc_channel_cnt = 0, local_channel_cnt = 0;
unsigned enc_clock_rate = 0, local_clock_rate = 0;
for (i = 0; i < dec_fmtp->cnt; ++i) {
if (!pj_stricmp2(&dec_fmtp->param[i].name, "sprop-maxcapturerate")) {
local_clock_rate = (unsigned)pj_strtoul(&dec_fmtp->param[i].val);
} else if (!pj_stricmp2(&dec_fmtp->param[i].name, "sprop-stereo")) {
local_channel_cnt = (unsigned)pj_strtoul(&dec_fmtp->param[i].val);
local_channel_cnt = (local_channel_cnt > 0) ? 2 : 1;
}
}
if (!local_clock_rate) local_clock_rate = *clock_rate;
if (!local_channel_cnt) local_channel_cnt = *channel_cnt;
for (i = 0; i < enc_fmtp->cnt; ++i) {
if (!pj_stricmp2(&enc_fmtp->param[i].name, "maxplaybackrate")) {
enc_clock_rate = (unsigned)pj_strtoul(&enc_fmtp->param[i].val);
} else if (!pj_stricmp2(&enc_fmtp->param[i].name, "stereo")) {
enc_channel_cnt = (unsigned)pj_strtoul(&enc_fmtp->param[i].val);
enc_channel_cnt = (enc_channel_cnt > 0) ? 2 : 1;
}
}
/* The default is a standard mono session with 48000 Hz clock rate
* (RFC 7587, section 7)
*/
if (!enc_clock_rate) enc_clock_rate = 48000;
if (!enc_channel_cnt) enc_channel_cnt = 1;
*clock_rate = (enc_clock_rate < local_clock_rate) ? enc_clock_rate :
local_clock_rate;
*channel_cnt = (enc_channel_cnt < local_channel_cnt) ? enc_channel_cnt :
local_channel_cnt;
}
/*
* Internal function for collecting codec info and param from the SDP media.
*/
@ -218,6 +259,14 @@ static pj_status_t get_audio_codec_info_param(pjmedia_stream_info *si,
pjmedia_stream_info_parse_fmtp(pool, local_m, si->rx_pt,
&si->param->setting.dec_fmtp);
if (!pj_stricmp2(&si->fmt.encoding_name, "opus")) {
get_opus_channels_and_clock_rate(&si->param->setting.enc_fmtp,
&si->param->setting.dec_fmtp,
&si->fmt.channel_cnt,
&si->fmt.clock_rate);
}
/* Get the remote ptime for our encoder. */
attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr,
"ptime", NULL);