2014-02-18 22:21:46 -06:00
/*
2011-02-04 15:33:28 -06:00
* FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
2014-02-05 15:02:28 -06:00
* Copyright ( C ) 2005 - 2014 , Anthony Minessale II < anthm @ freeswitch . org >
2011-02-04 15:33:28 -06:00
*
* Version : MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 ( the " License " ) ; you may not use this file except in compliance with
* the License . You may obtain a copy of the License at
* http : //www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an " AS IS " basis ,
* WITHOUT WARRANTY OF ANY KIND , either express or implied . See the License
* for the specific language governing rights and limitations under the
* License .
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II < anthm @ freeswitch . org >
* Portions created by the Initial Developer are Copyright ( C )
* the Initial Developer . All Rights Reserved .
*
* Contributor ( s ) :
2014-02-18 22:21:46 -06:00
*
2011-02-04 15:33:28 -06:00
* Brian K . West < brian @ freeswitch . org >
2014-02-18 22:21:46 -06:00
* Noel Morgan < noel @ vwci . com >
2015-07-03 11:21:27 -04:00
* Dragos Oancea < droancea @ yahoo . com >
2011-02-04 15:33:28 -06:00
*
* mod_opus . c - - The OPUS ultra - low delay audio codec ( http : //www.opus-codec.org/)
*
*/
# include "switch.h"
# include "opus.h"
2015-10-23 20:27:25 -04:00
# define SWITCH_OPUS_MIN_BITRATE 6000
# define SWITCH_OPUS_MAX_BITRATE 510000
# define SWITCH_OPUS_MIN_FEC_BITRATE 12400
2011-02-04 15:33:28 -06:00
SWITCH_MODULE_LOAD_FUNCTION ( mod_opus_load ) ;
SWITCH_MODULE_DEFINITION ( mod_opus , mod_opus_load , NULL , NULL ) ;
2013-11-08 03:44:21 +05:00
/*! \brief Various codec settings */
struct opus_codec_settings {
int useinbandfec ;
int usedtx ;
int maxaveragebitrate ;
2014-11-12 09:06:11 +01:00
int maxplaybackrate ;
2013-11-08 03:44:21 +05:00
int stereo ;
int cbr ;
int sprop_maxcapturerate ;
int sprop_stereo ;
int maxptime ;
int minptime ;
int ptime ;
int samplerate ;
} ;
typedef struct opus_codec_settings opus_codec_settings_t ;
static opus_codec_settings_t default_codec_settings = {
/*.useinbandfec */ 1 ,
/*.usedtx */ 1 ,
/*.maxaveragebitrate */ 30000 ,
2014-11-12 09:06:11 +01:00
/*.maxplaybackrate */ 48000 ,
2013-11-08 03:44:21 +05:00
/*.stereo*/ 0 ,
/*.cbr*/ 0 ,
/*.sprop_maxcapturerate*/ 0 ,
/*.sprop_stereo*/ 0 ,
2015-09-09 15:17:20 -04:00
/*.maxptime*/ 40 ,
/*.minptime*/ 10 ,
/*.ptime*/ 0 ,
/*.samplerate*/ 0
} ;
static opus_codec_settings_t default_codec_settings_8k = {
/*.useinbandfec */ 1 ,
/*.usedtx */ 1 ,
/*.maxaveragebitrate */ 14000 ,
/*.maxplaybackrate */ 8000 ,
/*.stereo*/ 0 ,
/*.cbr*/ 0 ,
/*.sprop_maxcapturerate*/ 8000 ,
/*.sprop_stereo*/ 0 ,
/*.maxptime*/ 120 ,
/*.minptime*/ 10 ,
2013-11-08 03:44:21 +05:00
/*.ptime*/ 0 ,
/*.samplerate*/ 0
} ;
2016-12-20 10:34:16 -05:00
static opus_codec_settings_t default_codec_settings_16k = {
/*.useinbandfec */ 1 ,
/*.usedtx */ 1 ,
/*.maxaveragebitrate */ 20000 ,
/*.maxplaybackrate */ 16000 ,
/*.stereo*/ 0 ,
/*.cbr*/ 0 ,
/*.sprop_maxcapturerate*/ 16000 ,
/*.sprop_stereo*/ 0 ,
/*.maxptime*/ 60 ,
/*.minptime*/ 10 ,
/*.ptime*/ 0 ,
/*.samplerate*/ 0
} ;
2015-10-07 11:34:35 -04:00
struct dec_stats {
uint32_t fec_counter ;
uint32_t plc_counter ;
uint32_t frame_counter ;
} ;
typedef struct dec_stats dec_stats_t ;
2016-10-20 04:48:34 -04:00
struct enc_stats {
uint32_t frame_counter ;
uint32_t encoded_bytes ;
uint32_t encoded_msec ;
uint32_t fec_counter ;
} ;
typedef struct enc_stats enc_stats_t ;
2015-10-23 20:27:25 -04:00
struct codec_control_state {
int keep_fec ;
opus_int32 current_bitrate ;
opus_int32 wanted_bitrate ;
uint32_t increase_step ;
uint32_t decrease_step ;
} ;
typedef struct codec_control_state codec_control_state_t ;
2011-02-04 15:33:28 -06:00
struct opus_context {
OpusEncoder * encoder_object ;
OpusDecoder * decoder_object ;
2015-03-12 17:51:41 -05:00
uint32_t enc_frame_size ;
uint32_t dec_frame_size ;
2015-06-05 18:11:14 -05:00
uint32_t old_plpct ;
2015-09-11 11:37:01 -05:00
uint32_t debug ;
uint32_t use_jb_lookahead ;
2015-06-05 18:11:14 -05:00
opus_codec_settings_t codec_settings ;
2015-10-01 19:11:51 -05:00
int look_check ;
int look_ts ;
2015-10-07 11:34:35 -04:00
dec_stats_t decoder_stats ;
2016-10-20 04:48:34 -04:00
enc_stats_t encoder_stats ;
2015-10-23 20:27:25 -04:00
codec_control_state_t control_state ;
2022-08-18 19:48:20 +03:00
switch_bool_t recreate_decoder ;
2011-02-04 15:33:28 -06:00
} ;
2014-02-18 22:21:46 -06:00
struct {
2022-01-08 12:14:16 +02:00
switch_bool_t use_vbr ;
switch_bool_t use_dtx ;
2015-09-09 12:48:34 -05:00
int complexity ;
int maxaveragebitrate ;
int maxplaybackrate ;
2015-06-11 14:07:02 -04:00
int sprop_maxcapturerate ;
2015-06-04 15:57:33 -05:00
int plpct ;
2022-01-08 12:14:16 +02:00
switch_bool_t asymmetric_samplerates ;
switch_bool_t bitrate_negotiation ;
switch_bool_t keep_fec ;
switch_bool_t fec_decode ;
switch_bool_t adjust_bitrate ;
2015-06-15 11:42:51 -04:00
int debuginfo ;
2022-01-08 12:14:16 +02:00
switch_bool_t use_jb_lookahead ;
2015-09-09 12:48:34 -05:00
switch_mutex_t * mutex ;
2022-01-08 12:14:16 +02:00
switch_bool_t mono ;
2014-02-18 22:21:46 -06:00
} opus_prefs ;
2015-06-15 11:42:51 -04:00
static struct {
int debug ;
} globals ;
2015-06-11 14:07:02 -04:00
static switch_bool_t switch_opus_acceptable_rate ( int rate )
{
2015-09-09 12:48:34 -05:00
if ( rate ! = 8000 & & rate ! = 12000 & & rate ! = 16000 & & rate ! = 24000 & & rate ! = 48000 ) {
2015-06-11 14:07:02 -04:00
return SWITCH_FALSE ;
2015-09-09 12:48:34 -05:00
}
2015-06-11 14:07:02 -04:00
return SWITCH_TRUE ;
}
2014-02-18 22:21:46 -06:00
2015-09-10 19:17:08 -04:00
static uint32_t switch_opus_encoder_set_audio_bandwidth ( OpusEncoder * encoder_object , int enc_samplerate )
{
if ( enc_samplerate = = 8000 ) { /* Audio Bandwidth: 0-4000Hz Sampling Rate: 8000Hz */
opus_encoder_ctl ( encoder_object , OPUS_SET_BANDWIDTH ( OPUS_BANDWIDTH_NARROWBAND ) ) ;
opus_encoder_ctl ( encoder_object , OPUS_SET_MAX_BANDWIDTH ( OPUS_BANDWIDTH_NARROWBAND ) ) ;
opus_encoder_ctl ( encoder_object , OPUS_SET_SIGNAL ( OPUS_SIGNAL_VOICE ) ) ;
return OPUS_BANDWIDTH_NARROWBAND ;
} else if ( enc_samplerate = = 12000 ) { /* Audio Bandwidth: 0-6000Hz Sampling Rate: 12000Hz */
opus_encoder_ctl ( encoder_object , OPUS_SET_BANDWIDTH ( OPUS_BANDWIDTH_MEDIUMBAND ) ) ;
opus_encoder_ctl ( encoder_object , OPUS_SET_MAX_BANDWIDTH ( OPUS_BANDWIDTH_MEDIUMBAND ) ) ;
opus_encoder_ctl ( encoder_object , OPUS_SET_SIGNAL ( OPUS_SIGNAL_VOICE ) ) ;
return OPUS_BANDWIDTH_MEDIUMBAND ;
} else if ( enc_samplerate = = 16000 ) { /* Audio Bandwidth: 0-8000Hz Sampling Rate: 16000Hz */
opus_encoder_ctl ( encoder_object , OPUS_SET_BANDWIDTH ( OPUS_BANDWIDTH_WIDEBAND ) ) ;
opus_encoder_ctl ( encoder_object , OPUS_SET_MAX_BANDWIDTH ( OPUS_BANDWIDTH_WIDEBAND ) ) ;
opus_encoder_ctl ( encoder_object , OPUS_SET_SIGNAL ( OPUS_SIGNAL_VOICE ) ) ;
return OPUS_BANDWIDTH_WIDEBAND ;
} else if ( enc_samplerate = = 24000 ) { /* Audio Bandwidth: 0-12000Hz Sampling Rate: 24000Hz */
opus_encoder_ctl ( encoder_object , OPUS_SET_BANDWIDTH ( OPUS_BANDWIDTH_SUPERWIDEBAND ) ) ;
opus_encoder_ctl ( encoder_object , OPUS_SET_MAX_BANDWIDTH ( OPUS_BANDWIDTH_SUPERWIDEBAND ) ) ;
opus_encoder_ctl ( encoder_object , OPUS_SET_SIGNAL ( OPUS_AUTO ) ) ;
return OPUS_BANDWIDTH_SUPERWIDEBAND ;
2017-01-06 02:10:15 -05:00
}
2015-09-10 19:17:08 -04:00
/* Audio Bandwidth: 0-20000Hz Sampling Rate: 48000Hz */
opus_encoder_ctl ( encoder_object , OPUS_SET_BANDWIDTH ( OPUS_AUTO ) ) ;
opus_encoder_ctl ( encoder_object , OPUS_SET_MAX_BANDWIDTH ( OPUS_BANDWIDTH_FULLBAND ) ) ;
opus_encoder_ctl ( encoder_object , OPUS_SET_SIGNAL ( OPUS_AUTO ) ) ;
return OPUS_BANDWIDTH_FULLBAND ;
}
static switch_bool_t switch_opus_show_audio_bandwidth ( int audiobandwidth , char * audiobandwidth_str )
{
if ( audiobandwidth = = OPUS_BANDWIDTH_NARROWBAND ) {
2018-12-12 05:27:06 +00:00
strncpy ( audiobandwidth_str , " NARROWBAND " , 11 ) ;
2015-10-05 10:51:50 -04:00
return SWITCH_TRUE ;
2015-09-10 19:17:08 -04:00
} else if ( audiobandwidth = = OPUS_BANDWIDTH_MEDIUMBAND ) {
2018-12-12 05:27:06 +00:00
strncpy ( audiobandwidth_str , " MEDIUMBAND " , 11 ) ;
2015-10-05 10:51:50 -04:00
return SWITCH_TRUE ;
2015-09-10 19:17:08 -04:00
} else if ( audiobandwidth = = OPUS_BANDWIDTH_WIDEBAND ) {
2018-12-12 05:27:06 +00:00
strncpy ( audiobandwidth_str , " WIDEBAND " , 9 ) ;
2015-10-05 10:51:50 -04:00
return SWITCH_TRUE ;
2015-09-10 19:17:08 -04:00
} else if ( audiobandwidth = = OPUS_BANDWIDTH_SUPERWIDEBAND ) {
2018-12-12 05:27:06 +00:00
strncpy ( audiobandwidth_str , " SUPERWIDEBAND " , 14 ) ;
2015-10-05 10:51:50 -04:00
return SWITCH_TRUE ;
2015-09-10 19:17:08 -04:00
} else if ( audiobandwidth = = OPUS_BANDWIDTH_FULLBAND ) {
2018-12-12 05:27:06 +00:00
strncpy ( audiobandwidth_str , " FULLBAND " , 9 ) ;
2015-10-05 10:51:50 -04:00
return SWITCH_TRUE ;
2015-09-10 19:17:08 -04:00
}
2015-10-05 10:51:50 -04:00
return SWITCH_FALSE ;
2015-09-10 19:17:08 -04:00
}
2013-11-08 03:44:21 +05:00
static switch_status_t switch_opus_fmtp_parse ( const char * fmtp , switch_codec_fmtp_t * codec_fmtp )
{
if ( codec_fmtp ) {
opus_codec_settings_t local_settings = { 0 } ;
opus_codec_settings_t * codec_settings = & local_settings ;
2015-09-09 12:48:34 -05:00
2013-11-08 03:44:21 +05:00
if ( codec_fmtp - > private_info ) {
codec_settings = codec_fmtp - > private_info ;
if ( zstr ( fmtp ) ) {
memcpy ( codec_settings , & default_codec_settings , sizeof ( * codec_settings ) ) ;
}
}
2015-09-09 12:48:34 -05:00
2013-11-08 03:44:21 +05:00
if ( fmtp ) {
int x , argc ;
char * argv [ 10 ] ;
char * fmtp_dup = strdup ( fmtp ) ;
2015-09-09 12:48:34 -05:00
2013-11-08 03:44:21 +05:00
switch_assert ( fmtp_dup ) ;
2015-09-09 12:48:34 -05:00
2013-11-08 03:44:21 +05:00
argc = switch_separate_string ( fmtp_dup , ' ; ' , argv , ( sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ;
for ( x = 0 ; x < argc ; x + + ) {
char * data = argv [ x ] ;
char * arg ;
switch_assert ( data ) ;
while ( * data = = ' ' ) {
data + + ;
}
2015-09-09 12:48:34 -05:00
2013-11-08 03:44:21 +05:00
if ( ( arg = strchr ( data , ' = ' ) ) ) {
* arg + + = ' \0 ' ;
2015-09-09 12:48:34 -05:00
2019-07-12 19:57:22 +04:00
if ( ! strcasecmp ( data , " useinbandfec " ) ) {
codec_settings - > useinbandfec = switch_true ( arg ) ;
}
2015-09-09 12:48:34 -05:00
2019-07-12 19:57:22 +04:00
if ( ! strcasecmp ( data , " usedtx " ) ) {
codec_settings - > usedtx = switch_true ( arg ) ;
}
2015-07-08 19:54:28 -04:00
2019-07-12 19:57:22 +04:00
if ( ! strcasecmp ( data , " cbr " ) ) {
codec_settings - > cbr = switch_true ( arg ) ;
}
2015-09-09 12:48:34 -05:00
2019-07-12 19:57:22 +04:00
if ( ! strcasecmp ( data , " maxptime " ) ) {
codec_settings - > maxptime = atoi ( arg ) ;
2023-05-11 03:55:11 +03:00
codec_fmtp - > max_ptime = codec_settings - > maxptime ;
2019-07-12 19:57:22 +04:00
}
2015-09-09 12:48:34 -05:00
2019-07-12 19:57:22 +04:00
if ( ! strcasecmp ( data , " minptime " ) ) {
codec_settings - > minptime = atoi ( arg ) ;
2023-05-11 03:55:11 +03:00
codec_fmtp - > min_ptime = codec_settings - > minptime ;
2019-07-12 19:57:22 +04:00
}
2015-09-09 12:48:34 -05:00
2019-07-12 19:57:22 +04:00
if ( ! strcasecmp ( data , " ptime " ) ) {
codec_settings - > ptime = atoi ( arg ) ;
codec_fmtp - > microseconds_per_packet = codec_settings - > ptime * 1000 ;
}
2015-09-09 12:48:34 -05:00
2019-07-12 19:57:22 +04:00
if ( ! strcasecmp ( data , " stereo " ) ) {
2021-05-14 18:36:30 +03:00
codec_settings - > stereo = opus_prefs . mono ? 0 : atoi ( arg ) ;
2019-07-12 19:57:22 +04:00
codec_fmtp - > stereo = codec_settings - > stereo ;
}
2015-07-13 17:39:36 -04:00
2019-07-12 19:57:22 +04:00
if ( ! strcasecmp ( data , " sprop-stereo " ) ) {
codec_settings - > sprop_stereo = atoi ( arg ) ;
2023-05-11 03:55:11 +03:00
codec_fmtp - > sprop_stereo = codec_settings - > sprop_stereo ;
2019-07-12 19:57:22 +04:00
}
2015-09-09 12:48:34 -05:00
2019-07-12 19:57:22 +04:00
if ( ! strcasecmp ( data , " maxaveragebitrate " ) ) {
codec_settings - > maxaveragebitrate = atoi ( arg ) ;
if ( codec_settings - > maxaveragebitrate < SWITCH_OPUS_MIN_BITRATE | | codec_settings - > maxaveragebitrate > SWITCH_OPUS_MAX_BITRATE ) {
codec_settings - > maxaveragebitrate = 0 ; /* values outside the range between 6000 and 510000 SHOULD be ignored */
2013-11-08 03:44:21 +05:00
}
2019-07-12 19:57:22 +04:00
}
2015-09-09 12:48:34 -05:00
2019-07-12 19:57:22 +04:00
if ( ! strcasecmp ( data , " maxplaybackrate " ) ) {
codec_settings - > maxplaybackrate = atoi ( arg ) ;
if ( ! switch_opus_acceptable_rate ( codec_settings - > maxplaybackrate ) ) {
codec_settings - > maxplaybackrate = 0 ; /* value not supported */
2014-11-12 09:06:11 +01:00
}
2019-07-12 19:57:22 +04:00
}
if ( ! strcasecmp ( data , " sprop-maxcapturerate " ) ) {
codec_settings - > sprop_maxcapturerate = atoi ( arg ) ;
if ( ! switch_opus_acceptable_rate ( codec_settings - > sprop_maxcapturerate ) ) {
codec_settings - > sprop_maxcapturerate = 0 ; /* value not supported */
2015-06-11 14:07:02 -04:00
}
2023-06-15 16:29:43 +03:00
if ( codec_settings - > sprop_maxcapturerate ) {
codec_fmtp - > actual_samples_per_second = codec_settings - > sprop_maxcapturerate ;
}
2013-11-08 03:44:21 +05:00
}
}
}
free ( fmtp_dup ) ;
}
return SWITCH_STATUS_SUCCESS ;
}
return SWITCH_STATUS_FALSE ;
}
static char * gen_fmtp ( opus_codec_settings_t * settings , switch_memory_pool_t * pool )
{
2015-08-31 13:25:18 -04:00
char buf [ 256 ] = { 0 } ;
2015-09-09 12:48:34 -05:00
2015-10-03 13:45:24 -04:00
snprintf ( buf + strlen ( buf ) , sizeof ( buf ) - strlen ( buf ) , " useinbandfec=%d; " , settings - > useinbandfec ) ;
2015-09-09 12:48:34 -05:00
2013-11-08 03:44:21 +05:00
if ( settings - > usedtx ) {
2014-06-12 22:06:33 +05:00
snprintf ( buf + strlen ( buf ) , sizeof ( buf ) - strlen ( buf ) , " usedtx=1; " ) ;
2013-11-08 03:44:21 +05:00
}
2015-07-08 19:54:28 -04:00
if ( settings - > cbr ) {
snprintf ( buf + strlen ( buf ) , sizeof ( buf ) - strlen ( buf ) , " cbr=1; " ) ;
}
2015-09-09 12:48:34 -05:00
2013-11-08 03:44:21 +05:00
if ( settings - > maxaveragebitrate ) {
2014-06-12 22:06:33 +05:00
snprintf ( buf + strlen ( buf ) , sizeof ( buf ) - strlen ( buf ) , " maxaveragebitrate=%d; " , settings - > maxaveragebitrate ) ;
2014-11-12 09:06:11 +01:00
}
2015-09-09 12:48:34 -05:00
2014-11-12 09:06:11 +01:00
if ( settings - > maxplaybackrate ) {
snprintf ( buf + strlen ( buf ) , sizeof ( buf ) - strlen ( buf ) , " maxplaybackrate=%d; " , settings - > maxplaybackrate ) ;
2013-11-08 03:44:21 +05:00
}
2015-06-11 14:07:02 -04:00
if ( settings - > sprop_maxcapturerate ) {
snprintf ( buf + strlen ( buf ) , sizeof ( buf ) - strlen ( buf ) , " sprop-maxcapturerate=%d; " , settings - > sprop_maxcapturerate ) ;
}
2013-11-08 03:44:21 +05:00
if ( settings - > ptime ) {
2014-06-12 22:06:33 +05:00
snprintf ( buf + strlen ( buf ) , sizeof ( buf ) - strlen ( buf ) , " ptime=%d; " , settings - > ptime ) ;
2013-11-08 03:44:21 +05:00
}
2015-09-09 12:48:34 -05:00
2013-11-08 03:44:21 +05:00
if ( settings - > minptime ) {
2014-06-12 22:06:33 +05:00
snprintf ( buf + strlen ( buf ) , sizeof ( buf ) - strlen ( buf ) , " minptime=%d; " , settings - > minptime ) ;
2013-11-08 03:44:21 +05:00
}
2014-06-12 22:06:33 +05:00
2013-11-08 03:44:21 +05:00
if ( settings - > maxptime ) {
2014-06-12 22:06:33 +05:00
snprintf ( buf + strlen ( buf ) , sizeof ( buf ) - strlen ( buf ) , " maxptime=%d; " , settings - > maxptime ) ;
2013-11-08 03:44:21 +05:00
}
2015-09-09 12:48:34 -05:00
2014-06-12 22:06:33 +05:00
if ( settings - > stereo ) {
snprintf ( buf + strlen ( buf ) , sizeof ( buf ) - strlen ( buf ) , " stereo=%d; " , settings - > stereo ) ;
}
2015-07-13 17:39:36 -04:00
if ( settings - > sprop_stereo ) {
snprintf ( buf + strlen ( buf ) , sizeof ( buf ) - strlen ( buf ) , " sprop-stereo=%d; " , settings - > sprop_stereo ) ;
}
2014-06-12 22:06:33 +05:00
if ( end_of ( buf ) = = ' ' ) {
* ( end_of_p ( buf ) - 1 ) = ' \0 ' ;
2013-11-08 03:44:21 +05:00
}
2015-09-09 12:48:34 -05:00
2013-11-08 03:44:21 +05:00
return switch_core_strdup ( pool , buf ) ;
2015-09-09 12:48:34 -05:00
2013-11-08 03:44:21 +05:00
}
2017-01-06 02:10:15 -05:00
static switch_bool_t switch_opus_has_fec ( const uint8_t * payload , int payload_length_bytes )
2015-09-17 13:10:33 +00:00
{
2015-10-07 17:18:23 -04:00
/* nb_silk_frames: number of silk-frames (10 or 20 ms) in an opus frame: 0, 1, 2 or 3 */
/* computed from the 5 MSB (configuration) of the TOC byte (payload[0]) */
/* nb_opus_frames: number of opus frames in the packet */
/* computed from the 2 LSB (p0p1) of the TOC byte */
/* p0p1 = 0 => nb_opus_frames = 1 */
/* p0p1 = 1 or 2 => nb_opus_frames = 2 */
/* p0p1 = 3 => given by the 6 LSB of payload[1] */
2017-01-06 02:10:15 -05:00
int nb_silk_frames , nb_opus_frames , n , i ;
2015-09-17 13:10:33 +00:00
opus_int16 frame_sizes [ 48 ] ;
const unsigned char * frame_data [ 48 ] ;
2015-09-29 18:35:47 -04:00
if ( payload = = NULL | | payload_length_bytes < = 0 ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " corrupted packet (invalid size) \n " ) ;
2015-09-17 13:10:33 +00:00
return SWITCH_FALSE ;
}
2017-01-06 02:10:15 -05:00
if ( payload [ 0 ] & 0x80 ) {
2015-10-06 09:34:19 -05:00
/* this scares users and its harmless so commenting it */
//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FEC in CELT_ONLY mode ?!\n");
2015-09-17 13:10:33 +00:00
return SWITCH_FALSE ;
}
2017-01-06 02:10:15 -05:00
2015-10-07 17:18:23 -04:00
if ( ( nb_opus_frames = opus_packet_parse ( payload , payload_length_bytes , NULL , frame_data , frame_sizes , NULL ) ) < = 0 ) {
2015-09-29 18:35:47 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " OPUS_INVALID_PACKET ! nb_opus_frames: %d \n " , nb_opus_frames ) ;
2015-09-17 13:10:33 +00:00
return SWITCH_FALSE ;
}
2015-09-29 18:35:47 -04:00
if ( ( payload [ 0 ] > > 3 ) < 12 ) { /* config in silk-only : NB,MB,WB */
nb_silk_frames = ( payload [ 0 ] > > 3 ) & 0x3 ;
if ( nb_silk_frames = = 0 ) {
nb_silk_frames = 1 ;
}
2017-01-06 02:10:15 -05:00
if ( ( nb_silk_frames = = 1 ) & & ( nb_opus_frames = = 1 ) ) {
2015-10-07 17:18:23 -04:00
for ( n = 0 ; n < = ( payload [ 0 ] & 0x4 ) ; n + + ) { /* mono or stereo: 10,20 ms */
2015-09-29 18:35:47 -04:00
if ( frame_data [ 0 ] [ 0 ] & ( 0x80 > > ( ( n + 1 ) * ( nb_silk_frames + 1 ) - 1 ) ) ) {
2015-10-07 17:18:23 -04:00
return SWITCH_TRUE ; /* frame has FEC */
2015-09-29 18:35:47 -04:00
}
}
} else {
opus_int16 LBRR_flag = 0 ;
2015-10-07 17:18:23 -04:00
for ( i = 0 ; i < nb_opus_frames ; i + + ) { /* only mono Opus frames */
2015-09-29 18:35:47 -04:00
LBRR_flag = ( frame_data [ i ] [ 0 ] > > ( 7 - nb_silk_frames ) ) & 0x1 ;
if ( LBRR_flag ) {
2017-01-06 02:10:15 -05:00
return SWITCH_TRUE ; /* one of the silk frames has FEC */
2015-09-29 18:35:47 -04:00
}
}
2015-09-17 13:10:33 +00:00
}
2015-10-03 02:38:00 -05:00
return SWITCH_FALSE ;
}
2015-09-17 13:10:33 +00:00
return SWITCH_FALSE ;
}
2015-09-17 12:52:55 -04:00
/* this is only useful for fs = 8000 hz, the map is only used
* at the beginning of the call . */
static int switch_opus_get_fec_bitrate ( int fs , int loss )
{
2017-07-27 16:59:16 +01:00
int threshold_bitrates_8k [ 25 ] = {
2015-09-17 12:52:55 -04:00
15600 , 15200 , 15200 , 15200 , 14800 ,
14800 , 14800 , 14800 , 14400 , 14400 ,
14400 , 14000 , 14000 , 14000 , 13600 ,
13600 , 13600 , 13600 , 13200 , 13200 ,
13200 , 12800 , 12800 , 12800 , 12400
} ;
2017-07-27 16:59:16 +01:00
int threshold_bitrates_16k [ 25 ] = {
20400 , 20400 , 20000 , 20000 , 19600 ,
19600 , 19600 , 19200 , 19200 , 18800 ,
18800 , 18800 , 18400 , 18400 , 18000 ,
18000 , 18000 , 17600 , 17600 , 17200 ,
17200 , 17200 , 16800 , 16800 , 16400
} ;
2015-09-17 12:52:55 -04:00
if ( loss < = 0 ) {
return SWITCH_STATUS_FALSE ;
2017-01-06 02:10:15 -05:00
}
2015-09-17 12:52:55 -04:00
if ( fs = = 8000 ) {
2017-01-06 02:10:15 -05:00
if ( loss > = 25 ) {
2017-07-27 16:59:16 +01:00
return threshold_bitrates_8k [ 24 ] ;
} else {
return threshold_bitrates_8k [ loss - 1 ] ;
}
} else if ( fs = = 16000 ) {
if ( loss > = 25 ) {
return threshold_bitrates_16k [ 24 ] ;
2015-09-17 12:52:55 -04:00
} else {
2017-07-27 16:59:16 +01:00
return threshold_bitrates_16k [ loss - 1 ] ;
2015-09-17 12:52:55 -04:00
}
}
2017-01-06 02:10:15 -05:00
return SWITCH_STATUS_FALSE ;
2015-09-17 12:52:55 -04:00
}
2022-08-18 19:48:20 +03:00
static switch_status_t switch_opus_info ( switch_core_session_t * session , void * encoded_data , uint32_t len , uint32_t samples_per_second , char * print_text )
2015-06-15 11:42:51 -04:00
{
2015-10-07 17:18:23 -04:00
int nb_samples , nb_opus_frames , nb_channels ;
2015-06-15 11:42:51 -04:00
int audiobandwidth ;
2015-09-10 19:17:08 -04:00
char audiobandwidth_str [ 32 ] = { 0 } ;
2015-06-15 11:42:51 -04:00
opus_int16 frame_sizes [ 48 ] ;
const unsigned char * frame_data [ 48 ] ;
char has_fec = 0 ;
2015-10-07 17:18:23 -04:00
uint8_t * payload = encoded_data ;
2015-06-15 11:42:51 -04:00
2015-06-18 17:34:59 -04:00
if ( ! encoded_data ) {
2017-05-02 17:55:23 +01:00
/* print stuff, even if encoded_data is NULL. eg: "PLC correction" */
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " %s " , print_text ) ;
2015-06-18 17:34:59 -04:00
return SWITCH_STATUS_FALSE ;
}
2015-06-15 11:42:51 -04:00
audiobandwidth = opus_packet_get_bandwidth ( encoded_data ) ;
2015-06-18 17:34:59 -04:00
2015-09-10 19:17:08 -04:00
if ( ! switch_opus_show_audio_bandwidth ( audiobandwidth , audiobandwidth_str ) ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " %s: OPUS_INVALID_PACKET ! \n " , print_text ) ;
2015-06-15 11:42:51 -04:00
}
2015-06-18 17:34:59 -04:00
2015-10-07 17:18:23 -04:00
if ( ( nb_opus_frames = opus_packet_parse ( encoded_data , len , NULL , frame_data , frame_sizes , NULL ) ) < = 0 ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " %s: OPUS_INVALID_PACKET ! frames: %d \n " , print_text , nb_opus_frames ) ;
2015-10-02 23:42:59 -04:00
return SWITCH_STATUS_FALSE ;
2015-09-29 18:35:47 -04:00
}
nb_samples = opus_packet_get_samples_per_frame ( encoded_data , samples_per_second ) * nb_opus_frames ;
2015-10-07 17:18:23 -04:00
has_fec = switch_opus_has_fec ( payload , len ) ;
nb_channels = opus_packet_get_nb_channels ( payload ) ;
2015-06-18 17:34:59 -04:00
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " %s: opus_frames [%d] samples [%d] audio bandwidth [%s] bytes [%d] FEC[%s] channels[%d] \n " ,
2015-10-07 17:18:23 -04:00
print_text , nb_opus_frames , nb_samples , audiobandwidth_str , len , has_fec ? " yes " : " no " , nb_channels ) ;
2015-06-18 17:34:59 -04:00
2015-06-15 11:42:51 -04:00
return SWITCH_STATUS_SUCCESS ;
2017-01-06 02:10:15 -05:00
}
2015-06-15 11:42:51 -04:00
2011-02-04 15:33:28 -06:00
static switch_status_t switch_opus_init ( switch_codec_t * codec , switch_codec_flag_t flags , const switch_codec_settings_t * codec_settings )
{
struct opus_context * context = NULL ;
int encoding = ( flags & SWITCH_CODEC_FLAG_ENCODE ) ;
int decoding = ( flags & SWITCH_CODEC_FLAG_DECODE ) ;
2015-08-31 17:47:57 -04:00
switch_codec_fmtp_t codec_fmtp , codec_fmtp_only_remote = { 0 } ;
2013-11-08 03:44:21 +05:00
opus_codec_settings_t opus_codec_settings = { 0 } ;
2015-06-11 14:07:02 -04:00
opus_codec_settings_t opus_codec_settings_remote = { 0 } ;
2022-08-18 19:48:20 +03:00
switch_core_session_t * session = codec - > session ;
2015-09-09 12:48:34 -05:00
2011-02-04 15:33:28 -06:00
if ( ! ( encoding | | decoding ) | | ( ! ( context = switch_core_alloc ( codec - > memory_pool , sizeof ( * context ) ) ) ) ) {
return SWITCH_STATUS_FALSE ;
}
2015-03-12 17:51:41 -05:00
2015-09-09 12:48:34 -05:00
context - > enc_frame_size = codec - > implementation - > actual_samples_per_second * ( codec - > implementation - > microseconds_per_packet / 1000 ) / 1000 ;
2014-10-28 14:19:06 -05:00
2013-11-08 03:44:21 +05:00
memset ( & codec_fmtp , ' \0 ' , sizeof ( struct switch_codec_fmtp ) ) ;
codec_fmtp . private_info = & opus_codec_settings ;
switch_opus_fmtp_parse ( codec - > fmtp_in , & codec_fmtp ) ;
2016-09-28 11:22:40 -04:00
if ( opus_prefs . asymmetric_samplerates | | opus_prefs . bitrate_negotiation ) {
2015-07-13 19:46:00 -04:00
/* save the remote fmtp values, before processing */
codec_fmtp_only_remote . private_info = & opus_codec_settings_remote ;
switch_opus_fmtp_parse ( codec - > fmtp_in , & codec_fmtp_only_remote ) ;
}
2014-11-13 13:48:04 +01:00
2016-09-28 11:22:40 -04:00
/* If bitrate negotiation is allowed, verify whether remote is asking for a smaller maxaveragebitrate */
2015-09-09 12:48:34 -05:00
if ( opus_prefs . maxaveragebitrate & &
2016-09-28 11:22:40 -04:00
( ! opus_prefs . bitrate_negotiation | | ( opus_prefs . maxaveragebitrate < opus_codec_settings_remote . maxaveragebitrate ) | | ! opus_codec_settings_remote . maxaveragebitrate ) ) {
2014-11-13 13:48:04 +01:00
opus_codec_settings . maxaveragebitrate = opus_prefs . maxaveragebitrate ;
2015-06-11 14:07:02 -04:00
} else {
opus_codec_settings . maxaveragebitrate = opus_codec_settings_remote . maxaveragebitrate ;
2014-11-13 13:48:04 +01:00
}
2015-09-09 12:48:34 -05:00
2016-09-28 11:22:40 -04:00
/* If asymmetric sample rates are allowed, verify whether remote is asking for a smaller maxplaybackrate */
2015-09-09 12:48:34 -05:00
if ( opus_prefs . maxplaybackrate & &
2016-09-28 11:22:40 -04:00
( ! opus_prefs . asymmetric_samplerates | | ( opus_prefs . maxplaybackrate < opus_codec_settings_remote . maxplaybackrate ) | | ! opus_codec_settings_remote . maxplaybackrate ) ) {
2014-11-13 13:48:04 +01:00
opus_codec_settings . maxplaybackrate = opus_prefs . maxplaybackrate ;
2015-06-11 14:07:02 -04:00
} else {
opus_codec_settings . maxplaybackrate = opus_codec_settings_remote . maxplaybackrate ;
}
2015-09-09 12:48:34 -05:00
2016-09-28 11:22:40 -04:00
/* If asymmetric sample rates are allowed, verify whether remote is asking for a smaller sprop_maxcapturerate */
2015-09-09 12:48:34 -05:00
if ( opus_prefs . sprop_maxcapturerate & &
2016-09-28 11:22:40 -04:00
( ! opus_prefs . asymmetric_samplerates | | ( opus_prefs . sprop_maxcapturerate < opus_codec_settings_remote . sprop_maxcapturerate ) | | ! opus_codec_settings_remote . sprop_maxcapturerate ) ) {
2015-06-11 14:07:02 -04:00
opus_codec_settings . sprop_maxcapturerate = opus_prefs . sprop_maxcapturerate ;
} else {
opus_codec_settings . sprop_maxcapturerate = opus_codec_settings_remote . sprop_maxcapturerate ;
2014-11-13 13:48:04 +01:00
}
2015-10-03 13:45:24 -04:00
opus_codec_settings . useinbandfec = opus_prefs . fec_decode ;
2015-07-08 19:54:28 -04:00
opus_codec_settings . cbr = ! opus_prefs . use_vbr ;
2015-07-13 18:10:10 -04:00
opus_codec_settings . usedtx = opus_prefs . use_dtx ;
2021-05-14 18:36:30 +03:00
if ( opus_prefs . mono ) {
opus_codec_settings . stereo = 0 ;
opus_codec_settings . sprop_stereo = 0 ;
}
2013-11-08 03:44:21 +05:00
codec - > fmtp_out = gen_fmtp ( & opus_codec_settings , codec - > memory_pool ) ;
2014-06-12 22:06:33 +05:00
2011-02-04 15:33:28 -06:00
if ( encoding ) {
/* come up with a way to specify these */
2013-11-08 03:44:21 +05:00
int bitrate_bps = OPUS_AUTO ;
2019-07-12 19:57:22 +04:00
int use_vbr = opus_codec_settings . cbr ? 0 : opus_prefs . use_vbr ;
2014-02-18 22:21:46 -06:00
int complexity = opus_prefs . complexity ;
2015-06-04 15:57:33 -05:00
int plpct = opus_prefs . plpct ;
2012-09-13 10:32:00 -05:00
int err ;
2015-06-11 14:07:02 -04:00
int enc_samplerate = opus_codec_settings . samplerate ? opus_codec_settings . samplerate : codec - > implementation - > actual_samples_per_second ;
2015-09-09 12:48:34 -05:00
2015-06-11 14:07:02 -04:00
if ( opus_prefs . asymmetric_samplerates ) {
/* If an entity receives an fmtp: maxplaybackrate=R1,sprop-maxcapturerate=R2 and sends an fmtp with:
* maxplaybackrate = R3 , sprop - maxcapturerate = R4
* then it should start the encoder at sample rate : min ( R1 , R4 ) and the decoder at sample rate : min ( R3 , R2 ) */
2015-09-09 12:48:34 -05:00
if ( codec_fmtp . private_info ) {
2015-08-31 13:25:18 -04:00
opus_codec_settings_t * settings = codec_fmtp_only_remote . private_info ;
2019-04-23 14:13:56 +00:00
if ( opus_codec_settings . sprop_maxcapturerate | | ( settings & & settings - > maxplaybackrate ) ) {
2015-06-11 14:07:02 -04:00
enc_samplerate = opus_codec_settings . sprop_maxcapturerate ; /*R4*/
2019-04-23 14:13:56 +00:00
if ( settings & & settings - > maxplaybackrate < enc_samplerate & & settings - > maxplaybackrate ) {
2015-08-31 13:25:18 -04:00
enc_samplerate = settings - > maxplaybackrate ; /*R1*/
2015-06-11 14:07:02 -04:00
context - > enc_frame_size = enc_samplerate * ( codec - > implementation - > microseconds_per_packet / 1000 ) / 1000 ;
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Opus encoder will be created at sample rate %d hz \n " , enc_samplerate ) ;
2015-06-11 14:07:02 -04:00
} else {
enc_samplerate = codec - > implementation - > actual_samples_per_second ;
}
}
}
}
context - > encoder_object = opus_encoder_create ( enc_samplerate ,
2013-02-12 14:26:55 -06:00
codec - > implementation - > number_of_channels ,
2014-10-02 10:41:59 -05:00
codec - > implementation - > number_of_channels = = 1 ? OPUS_APPLICATION_VOIP : OPUS_APPLICATION_AUDIO , & err ) ;
2015-09-09 12:48:34 -05:00
if ( err ! = OPUS_OK ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Cannot create encoder: %s \n " , opus_strerror ( err ) ) ;
2015-09-09 12:48:34 -05:00
return SWITCH_STATUS_GENERR ;
}
2014-11-12 09:06:11 +01:00
2015-09-10 19:17:08 -04:00
/* https://tools.ietf.org/html/rfc7587 */
2017-01-06 02:10:15 -05:00
if ( opus_codec_settings . maxaveragebitrate ) {
2014-11-12 09:06:11 +01:00
opus_encoder_ctl ( context - > encoder_object , OPUS_SET_BITRATE ( opus_codec_settings . maxaveragebitrate ) ) ;
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Opus encoder: set bitrate based on maxaveragebitrate value found in SDP or local config [%dbps] \n " , opus_codec_settings . maxaveragebitrate ) ;
2013-11-08 03:44:21 +05:00
} else {
2015-09-10 19:17:08 -04:00
opus_encoder_ctl ( context - > encoder_object , OPUS_SET_BANDWIDTH ( OPUS_AUTO ) ) ;
opus_encoder_ctl ( context - > encoder_object , OPUS_SET_BITRATE ( bitrate_bps ) ) ; /* OPUS_AUTO */
2017-01-06 02:10:15 -05:00
opus_encoder_ctl ( context - > encoder_object , OPUS_GET_BITRATE ( & bitrate_bps ) ) ; /* return average bps for this audio bandwidth */
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Opus encoder: set bitrate to local settings [%dbps] \n " , bitrate_bps ) ;
2013-11-08 03:44:21 +05:00
}
2015-09-10 19:17:08 -04:00
/* Another fmtp setting from https://tools.ietf.org/html/rfc7587 - "RTP Payload Format for the Opus Speech and Audio Codec" */
2015-09-09 12:48:34 -05:00
if ( opus_codec_settings . maxplaybackrate ) {
2017-01-06 02:10:15 -05:00
opus_int32 audiobandwidth ;
2015-09-10 19:17:08 -04:00
char audiobandwidth_str [ 32 ] = { 0 } ;
audiobandwidth = switch_opus_encoder_set_audio_bandwidth ( context - > encoder_object , opus_codec_settings . maxplaybackrate ) ;
if ( ! switch_opus_show_audio_bandwidth ( audiobandwidth , audiobandwidth_str ) ) {
2019-07-12 19:57:22 +04:00
snprintf ( audiobandwidth_str , sizeof ( audiobandwidth_str ) , " %s " , " OPUS_AUTO " ) ;
2014-11-12 09:06:11 +01:00
}
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Opus encoder: set audio bandwidth to [%s] based on maxplaybackrate value found in SDP or local config [%dHz] \n " , audiobandwidth_str , opus_codec_settings . maxplaybackrate ) ;
2014-11-12 09:06:11 +01:00
}
2014-02-27 15:29:25 -06:00
if ( use_vbr ) {
2015-07-08 19:54:28 -04:00
/* VBR is default*/
2014-02-27 15:29:25 -06:00
opus_encoder_ctl ( context - > encoder_object , OPUS_SET_VBR ( use_vbr ) ) ;
2015-07-08 19:54:28 -04:00
} else {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Opus encoder: CBR mode enabled \n " ) ;
2015-07-08 19:54:28 -04:00
opus_encoder_ctl ( context - > encoder_object , OPUS_SET_VBR ( 0 ) ) ;
2014-02-27 15:29:25 -06:00
}
2015-09-09 12:48:34 -05:00
2014-02-27 15:29:25 -06:00
if ( complexity ) {
opus_encoder_ctl ( context - > encoder_object , OPUS_SET_COMPLEXITY ( complexity ) ) ;
2015-09-09 12:48:34 -05:00
}
2014-02-27 15:29:25 -06:00
2015-06-04 15:57:33 -05:00
if ( plpct ) {
opus_encoder_ctl ( context - > encoder_object , OPUS_SET_PACKET_LOSS_PERC ( plpct ) ) ;
}
2015-09-09 12:48:34 -05:00
2013-11-08 03:44:21 +05:00
if ( opus_codec_settings . useinbandfec ) {
2015-09-17 12:52:55 -04:00
/* FEC on the encoder: start the call with a preconfigured packet loss percentage */
2017-01-06 02:10:15 -05:00
int loss_percent = opus_prefs . plpct ;
2013-11-08 03:44:21 +05:00
opus_encoder_ctl ( context - > encoder_object , OPUS_SET_INBAND_FEC ( opus_codec_settings . useinbandfec ) ) ;
2015-09-17 12:52:55 -04:00
opus_encoder_ctl ( context - > encoder_object , OPUS_SET_PACKET_LOSS_PERC ( loss_percent ) ) ;
2017-01-06 02:10:15 -05:00
if ( opus_prefs . keep_fec ) {
2019-04-23 19:33:33 +00:00
int fec_bitrate = switch_opus_get_fec_bitrate ( enc_samplerate , loss_percent ) ;
2015-09-17 12:52:55 -04:00
/* keep a bitrate for which the encoder will always add FEC */
if ( fec_bitrate ! = SWITCH_STATUS_FALSE ) {
2017-01-06 02:10:15 -05:00
opus_encoder_ctl ( context - > encoder_object , OPUS_SET_BITRATE ( fec_bitrate ) ) ;
/* will override the maxaveragebitrate set in opus.conf.xml */
2015-09-17 12:52:55 -04:00
opus_codec_settings . maxaveragebitrate = fec_bitrate ;
}
2016-10-01 19:00:04 -04:00
context - > control_state . keep_fec = opus_prefs . keep_fec ;
2015-09-17 12:52:55 -04:00
}
2013-11-08 03:44:21 +05:00
}
2015-09-09 12:48:34 -05:00
2013-11-08 03:44:21 +05:00
if ( opus_codec_settings . usedtx ) {
opus_encoder_ctl ( context - > encoder_object , OPUS_SET_DTX ( opus_codec_settings . usedtx ) ) ;
}
2015-10-23 20:27:25 -04:00
if ( opus_prefs . adjust_bitrate ) {
switch_set_flag ( codec , SWITCH_CODEC_FLAG_HAS_ADJ_BITRATE ) ;
}
2011-02-04 15:33:28 -06:00
}
2015-09-09 12:48:34 -05:00
2011-02-04 15:33:28 -06:00
if ( decoding ) {
2012-09-13 10:32:00 -05:00
int err ;
2015-06-11 14:07:02 -04:00
int dec_samplerate = codec - > implementation - > actual_samples_per_second ;
2015-09-09 12:48:34 -05:00
2015-06-11 14:07:02 -04:00
if ( opus_prefs . asymmetric_samplerates ) {
if ( codec_fmtp . private_info ) {
2015-08-31 13:25:18 -04:00
opus_codec_settings_t * settings = codec_fmtp_only_remote . private_info ;
2019-04-23 14:13:56 +00:00
if ( opus_codec_settings . maxplaybackrate | | ( settings & & settings - > sprop_maxcapturerate ) ) {
2015-06-11 14:07:02 -04:00
dec_samplerate = opus_codec_settings . maxplaybackrate ; /* R3 */
2019-04-23 14:13:56 +00:00
if ( settings & & dec_samplerate > settings - > sprop_maxcapturerate & & settings - > sprop_maxcapturerate ) {
2015-08-31 13:25:18 -04:00
dec_samplerate = settings - > sprop_maxcapturerate ; /* R2 */
2015-06-11 14:07:02 -04:00
context - > dec_frame_size = dec_samplerate * ( codec - > implementation - > microseconds_per_packet / 1000 ) / 1000 ;
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Opus decoder will be created at sample rate %d hz \n " , dec_samplerate ) ;
2015-06-11 14:07:02 -04:00
} else {
dec_samplerate = codec - > implementation - > actual_samples_per_second ;
}
}
}
}
2016-07-08 17:00:22 -04:00
context - > decoder_object = opus_decoder_create ( dec_samplerate , ( ! context - > codec_settings . sprop_stereo ? codec - > implementation - > number_of_channels : 2 ) , & err ) ;
2015-09-09 12:48:34 -05:00
2015-06-04 15:01:36 -05:00
switch_set_flag ( codec , SWITCH_CODEC_FLAG_HAS_PLC ) ;
2015-09-09 12:48:34 -05:00
2012-09-13 10:32:00 -05:00
if ( err ! = OPUS_OK ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Cannot create decoder: %s \n " , opus_strerror ( err ) ) ;
2015-09-09 12:48:34 -05:00
2012-09-13 10:32:00 -05:00
if ( context - > encoder_object ) {
opus_encoder_destroy ( context - > encoder_object ) ;
context - > encoder_object = NULL ;
}
2015-09-09 12:48:34 -05:00
2012-09-13 10:32:00 -05:00
return SWITCH_STATUS_GENERR ;
}
2011-02-04 15:33:28 -06:00
}
2015-09-09 12:48:34 -05:00
2016-10-01 19:00:04 -04:00
context - > codec_settings = opus_codec_settings ;
2011-02-04 15:33:28 -06:00
codec - > private_info = context ;
2015-09-09 12:48:34 -05:00
2011-02-04 15:33:28 -06:00
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t switch_opus_destroy ( switch_codec_t * codec )
{
2012-09-13 10:32:00 -05:00
struct opus_context * context = codec - > private_info ;
2015-09-09 12:48:34 -05:00
2012-09-13 10:32:00 -05:00
if ( context ) {
if ( context - > decoder_object ) {
2015-10-07 11:34:35 -04:00
switch_core_session_t * session = codec - > session ;
if ( session ) {
2017-01-06 02:10:15 -05:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Opus decoder stats: Frames[%d] PLC[%d] FEC[%d] \n " ,
context - > decoder_stats . frame_counter , context - > decoder_stats . plc_counter - context - > decoder_stats . fec_counter , context - > decoder_stats . fec_counter ) ;
2015-10-07 11:34:35 -04:00
}
2012-09-13 10:32:00 -05:00
opus_decoder_destroy ( context - > decoder_object ) ;
context - > decoder_object = NULL ;
}
if ( context - > encoder_object ) {
2016-10-20 04:48:34 -04:00
switch_core_session_t * session = codec - > session ;
int avg_encoded_bitrate = 0 ;
if ( session ) {
2016-11-02 06:17:34 -05:00
if ( context - > encoder_stats . encoded_bytes > 0 & & ( context - > encoder_stats . encoded_msec > 1000 ) ) {
2016-10-20 04:48:34 -04:00
avg_encoded_bitrate = ( context - > encoder_stats . encoded_bytes * 8 ) / ( context - > encoder_stats . encoded_msec / 1000 ) ;
}
2017-05-02 17:55:23 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG ,
" Opus encoder stats: Frames[%d] Bytes encoded[%d] Encoded length ms[%d] Average encoded bitrate bps[%d] \n " ,
context - > encoder_stats . frame_counter , context - > encoder_stats . encoded_bytes , context - > encoder_stats . encoded_msec , avg_encoded_bitrate ) ;
if ( globals . debug | | context - > debug > 1 ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG ,
" Opus encoder stats: FEC frames (only for debug mode) [%d] \n " , context - > encoder_stats . fec_counter ) ;
}
2016-10-20 04:48:34 -04:00
}
2012-09-13 10:32:00 -05:00
opus_encoder_destroy ( context - > encoder_object ) ;
context - > encoder_object = NULL ;
}
}
2015-09-09 12:48:34 -05:00
2011-02-04 15:33:28 -06:00
codec - > private_info = NULL ;
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t switch_opus_encode ( switch_codec_t * codec ,
switch_codec_t * other_codec ,
void * decoded_data ,
uint32_t decoded_data_len ,
uint32_t decoded_rate , void * encoded_data , uint32_t * encoded_data_len , uint32_t * encoded_rate ,
unsigned int * flag )
{
struct opus_context * context = codec - > private_info ;
int bytes = 0 ;
int len = ( int ) * encoded_data_len ;
2015-03-12 17:51:41 -05:00
2011-02-04 15:33:28 -06:00
if ( ! context ) {
return SWITCH_STATUS_FALSE ;
}
2015-09-09 12:48:34 -05:00
2015-03-12 17:51:41 -05:00
bytes = opus_encode ( context - > encoder_object , ( void * ) decoded_data , context - > enc_frame_size , ( unsigned char * ) encoded_data , len ) ;
2015-06-15 11:42:51 -04:00
2015-09-11 11:37:01 -05:00
if ( globals . debug | | context - > debug > 1 ) {
2015-06-15 11:42:51 -04:00
int samplerate = context - > enc_frame_size * 1000 / ( codec - > implementation - > microseconds_per_packet / 1000 ) ;
2022-08-18 19:48:20 +03:00
switch_opus_info ( codec - > session , encoded_data , bytes , samplerate , " encode " ) ;
2015-06-15 11:42:51 -04:00
}
2011-02-04 15:33:28 -06:00
if ( bytes > 0 ) {
* encoded_data_len = ( uint32_t ) bytes ;
2016-10-20 04:48:34 -04:00
context - > encoder_stats . frame_counter + + ;
if ( context - > enc_frame_size > 0 ) {
context - > encoder_stats . encoded_msec + = codec - > implementation - > microseconds_per_packet / 1000 ;
}
context - > encoder_stats . encoded_bytes + = ( uint32_t ) bytes ;
if ( globals . debug | | context - > debug > 1 ) {
// This stat is expensive, so get it only when in debug mode
if ( switch_opus_has_fec ( ( uint8_t * ) encoded_data , bytes ) ) {
context - > encoder_stats . fec_counter + + ;
}
}
2011-02-04 15:33:28 -06:00
return SWITCH_STATUS_SUCCESS ;
}
2014-06-12 22:06:33 +05:00
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( codec - > session ) , SWITCH_LOG_ERROR ,
2015-09-09 12:48:34 -05:00
" Encoder Error: %s Decoded Datalen %u Codec NumberChans %u Len %u DecodedDate %p EncodedData %p ContextEncoderObject %p! \n " ,
opus_strerror ( bytes ) , decoded_data_len , codec - > implementation - > number_of_channels , len , ( void * ) decoded_data ,
( void * ) encoded_data , ( void * ) context - > encoder_object ) ;
2014-06-12 22:06:33 +05:00
2011-02-04 15:33:28 -06:00
return SWITCH_STATUS_GENERR ;
}
2015-09-11 11:37:01 -05:00
2011-02-04 15:33:28 -06:00
static switch_status_t switch_opus_decode ( switch_codec_t * codec ,
switch_codec_t * other_codec ,
void * encoded_data ,
uint32_t encoded_data_len ,
uint32_t encoded_rate , void * decoded_data , uint32_t * decoded_data_len , uint32_t * decoded_rate ,
unsigned int * flag )
{
struct opus_context * context = codec - > private_info ;
int samples = 0 ;
2015-06-05 18:11:14 -05:00
int fec = 0 , plc = 0 ;
2015-10-02 12:51:57 -05:00
int32_t frame_size = 0 , last_frame_size = 0 ;
2014-12-12 17:52:02 -06:00
uint32_t frame_samples ;
2022-10-28 03:15:15 +03:00
uint8_t buf [ SWITCH_RTP_MAX_BUF_LEN ] ;
2022-08-18 19:48:20 +03:00
switch_core_session_t * session = codec - > session ;
2014-12-12 17:52:02 -06:00
2011-02-04 15:33:28 -06:00
if ( ! context ) {
return SWITCH_STATUS_FALSE ;
}
2014-12-12 17:52:02 -06:00
2016-07-08 17:00:22 -04:00
frame_samples = * decoded_data_len / 2 / ( ! context - > codec_settings . sprop_stereo ? codec - > implementation - > number_of_channels : 2 ) ;
2014-12-12 17:52:02 -06:00
frame_size = frame_samples - ( frame_samples % ( codec - > implementation - > actual_samples_per_second / 400 ) ) ;
2015-06-04 15:01:36 -05:00
2015-06-05 18:11:14 -05:00
if ( * flag & SFF_PLC ) {
2015-09-11 11:37:01 -05:00
switch_jb_t * jb = NULL ;
2015-06-05 18:11:14 -05:00
plc = 1 ;
2015-09-11 11:37:01 -05:00
2015-06-05 18:11:14 -05:00
encoded_data = NULL ;
2015-09-11 11:37:01 -05:00
2015-09-16 17:05:00 -05:00
if ( ( opus_prefs . use_jb_lookahead | | context - > use_jb_lookahead ) & & context - > codec_settings . useinbandfec & & session ) {
2015-10-15 10:56:29 -05:00
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2015-10-01 19:11:51 -05:00
if ( ! context - > look_check ) {
context - > look_ts = switch_true ( switch_channel_get_variable_dup ( channel , " jb_use_timestamps " , SWITCH_FALSE , - 1 ) ) ;
context - > look_check = 1 ;
}
if ( codec - > cur_frame & & ( jb = switch_core_session_get_jb ( session , SWITCH_MEDIA_TYPE_AUDIO ) ) ) {
2015-09-11 11:37:01 -05:00
switch_frame_t frame = { 0 } ;
2015-10-01 19:11:51 -05:00
uint32_t ts = 0 ;
uint16_t seq = 0 ;
if ( context - > look_ts ) {
ts = codec - > cur_frame - > timestamp ;
} else {
seq = codec - > cur_frame - > seq ;
}
2015-09-11 11:37:01 -05:00
frame . data = buf ;
frame . buflen = sizeof ( buf ) ;
2017-01-06 02:10:15 -05:00
2015-10-02 12:51:57 -05:00
if ( globals . debug | | context - > debug ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Missing %s %u Checking JB \n " , seq ? " SEQ " : " TS " , seq ? seq : ts ) ;
2015-10-02 12:51:57 -05:00
}
2017-01-06 02:10:15 -05:00
2015-10-01 19:11:51 -05:00
if ( switch_jb_peek_frame ( jb , ts , seq , 1 , & frame ) = = SWITCH_STATUS_SUCCESS ) {
if ( globals . debug | | context - > debug ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Lookahead frame found: %u:%u \n " ,
2015-10-02 12:51:57 -05:00
frame . timestamp , frame . seq ) ;
2015-10-01 19:11:51 -05:00
}
2015-09-11 11:37:01 -05:00
2017-01-06 02:10:15 -05:00
2015-10-01 19:11:51 -05:00
if ( ( fec = switch_opus_has_fec ( frame . data , frame . datalen ) ) ) {
2015-10-02 12:51:57 -05:00
encoded_data = frame . data ;
encoded_data_len = frame . datalen ;
2015-10-01 19:11:51 -05:00
}
2017-01-06 02:10:15 -05:00
2015-09-17 13:10:33 +00:00
if ( globals . debug | | context - > debug ) {
2015-10-01 19:11:51 -05:00
if ( fec ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " FEC info available in packet with SEQ: %d LEN: %d \n " ,
2015-10-02 12:51:57 -05:00
frame . seq , frame . datalen ) ;
2015-09-17 13:10:33 +00:00
} else {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " NO FEC info in this packet with SEQ: %d LEN: %d \n " ,
2015-10-02 12:51:57 -05:00
frame . seq , frame . datalen ) ;
2015-09-17 13:10:33 +00:00
}
}
2015-10-01 19:11:51 -05:00
}
2015-09-11 11:37:01 -05:00
}
}
2017-01-06 02:10:15 -05:00
2015-06-04 15:01:36 -05:00
2015-10-02 12:51:57 -05:00
opus_decoder_ctl ( context - > decoder_object , OPUS_GET_LAST_PACKET_DURATION ( & last_frame_size ) ) ;
if ( last_frame_size ) frame_size = last_frame_size ;
2017-01-06 02:10:15 -05:00
2015-09-11 11:37:01 -05:00
if ( globals . debug | | context - > debug ) {
if ( opus_prefs . use_jb_lookahead | | context - > use_jb_lookahead ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " MISSING FRAME: %s \n " , fec ? " Look-ahead FEC " : " PLC " ) ;
2015-09-11 11:37:01 -05:00
} else {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " MISSING FRAME: OPUS_PLC \n " ) ;
2015-09-11 11:37:01 -05:00
}
2015-06-02 01:17:20 +02:00
}
2015-06-04 15:01:36 -05:00
* flag & = ~ SFF_PLC ;
}
2015-06-05 18:11:14 -05:00
2015-09-11 11:37:01 -05:00
if ( globals . debug | | context - > debug > 1 ) {
2015-06-15 11:42:51 -04:00
int samplerate = context - > dec_frame_size * 1000 / ( codec - > implementation - > microseconds_per_packet / 1000 ) ;
2022-08-18 19:48:20 +03:00
switch_opus_info ( codec - > session , encoded_data , encoded_data_len ,
2017-01-06 02:10:15 -05:00
samplerate ? samplerate : codec - > implementation - > actual_samples_per_second ,
2015-10-02 12:51:57 -05:00
! encoded_data ? " PLC correction " : fec ? " FEC correction " : " decode " ) ;
2015-06-15 11:42:51 -04:00
}
2015-10-07 11:34:35 -04:00
if ( plc ) {
context - > decoder_stats . plc_counter + + ;
}
if ( fec ) {
context - > decoder_stats . fec_counter + + ;
}
/* a frame for which we decode FEC will be counted twice */
context - > decoder_stats . frame_counter + + ;
2015-06-05 18:11:14 -05:00
samples = opus_decode ( context - > decoder_object , encoded_data , encoded_data_len , decoded_data , frame_size , fec ) ;
2015-09-09 12:48:34 -05:00
2011-02-04 15:33:28 -06:00
if ( samples < 0 ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Decoder Error: %s fs:%u plc:%s! \n " ,
opus_strerror ( samples ) , frame_size , plc ? " true " : " false " ) ;
2020-12-11 14:38:25 -03:00
return SWITCH_STATUS_NOOP ;
2011-02-04 15:33:28 -06:00
}
2015-09-09 12:48:34 -05:00
2016-07-08 17:00:22 -04:00
* decoded_data_len = samples * 2 * ( ! context - > codec_settings . sprop_stereo ? codec - > implementation - > number_of_channels : 2 ) ;
2015-09-09 12:48:34 -05:00
2011-02-04 15:33:28 -06:00
return SWITCH_STATUS_SUCCESS ;
}
2015-07-17 21:01:38 -04:00
static switch_status_t switch_opus_encode_repacketize ( switch_codec_t * codec ,
switch_codec_t * other_codec ,
void * decoded_data ,
uint32_t decoded_data_len ,
uint32_t decoded_rate , void * encoded_data , uint32_t * encoded_data_len , uint32_t * encoded_rate ,
unsigned int * flag )
{
struct opus_context * context = codec - > private_info ;
int len = ( int ) * encoded_data_len ;
OpusRepacketizer * rp = opus_repacketizer_create ( ) ;
int16_t * dec_ptr_buf = decoded_data ;
2015-09-09 12:48:34 -05:00
/* work inside the available buffer to avoid other buffer allocations. *encoded_data_len will be SWITCH_RECOMMENDED_BUFFER_SIZE */
unsigned char * enc_ptr_buf = ( unsigned char * ) encoded_data + ( len / 2 ) ;
2015-10-26 13:45:48 -04:00
uint32_t nb_frames = codec - > implementation - > microseconds_per_packet / 20000 ; /* requested ptime: 20 ms * nb_frames */
uint32_t frame_size , i ;
int bytes = 0 , want_fec = 0 , toggle_fec = 0 ;
2015-07-17 21:01:38 -04:00
opus_int32 ret = 0 ;
opus_int32 total_len = 0 ;
switch_status_t status = SWITCH_STATUS_SUCCESS ;
2017-01-06 02:10:15 -05:00
2015-07-17 21:01:38 -04:00
if ( ! context ) {
switch_goto_status ( SWITCH_STATUS_FALSE , end ) ;
}
2015-09-09 15:01:59 -04:00
opus_encoder_ctl ( context - > encoder_object , OPUS_GET_INBAND_FEC ( & want_fec ) ) ;
if ( want_fec & & context - > codec_settings . useinbandfec ) {
/* if FEC might be used , pack only 2 frames like: 80 ms = 2 x 40 ms , 120 ms = 2 x 60 ms */
/* the first frame in the resulting payload must have FEC, the other must not ( avoid redundant FEC payload ) */
nb_frames = 2 ;
if ( codec - > implementation - > microseconds_per_packet / 1000 = = 100 ) { /* 100 ms = 20 ms * 5 . because there is no 50 ms frame in Opus */
nb_frames = 5 ;
}
}
frame_size = ( decoded_data_len / 2 ) / nb_frames ;
if ( ( frame_size * nb_frames ) ! = context - > enc_frame_size ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( codec - > session ) , SWITCH_LOG_ERROR , " Encoder Error: Decoded Datalen %u Number of frames: %u Encoder frame size: %u \n " , decoded_data_len , nb_frames , context - > enc_frame_size ) ;
2015-09-09 15:01:59 -04:00
switch_goto_status ( SWITCH_STATUS_GENERR , end ) ;
}
2015-07-17 21:01:38 -04:00
opus_repacketizer_init ( rp ) ;
2015-09-09 15:01:59 -04:00
dec_ptr_buf = ( int16_t * ) decoded_data ;
2015-07-17 21:01:38 -04:00
for ( i = 0 ; i < nb_frames ; i + + ) {
2015-10-13 17:54:15 -04:00
/* set inband FEC ON or OFF for the next Opus frame */
2017-01-06 02:10:15 -05:00
if ( i = = ( nb_frames - 1 ) & & want_fec ) {
/* When FEC is enabled for Opus frame N, LBRR is stored during regular encoding of */
2015-10-13 17:54:15 -04:00
/* this Opus frame N, and this LBRR data will be packed with the regular encoding */
/* data of Opus frame N+1. We enable FEC on our last Opus frame which is to be packed, just */
/* to actually have it stored in the first Opus frame, that is when switch_opus_encode_repacketize() */
2017-01-06 02:10:15 -05:00
/* is called again to pack the next big 80,100 or 120 ms frame. */
2015-10-13 17:54:15 -04:00
toggle_fec = 1 ; /* FEC ON for the last frame */
}
opus_encoder_ctl ( context - > encoder_object , OPUS_SET_INBAND_FEC ( toggle_fec ) ) ;
2015-09-09 15:01:59 -04:00
bytes = opus_encode ( context - > encoder_object , ( opus_int16 * ) dec_ptr_buf , frame_size , enc_ptr_buf , len ) ;
2015-10-13 17:54:15 -04:00
2015-07-17 21:01:38 -04:00
if ( bytes < 0 ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( codec - > session ) , SWITCH_LOG_ERROR , " Encoder Error: %s Decoded Datalen %u Codec NumberChans %u " \
2015-09-09 12:48:34 -05:00
" Len %u DecodedDate %p EncodedData %p ContextEncoderObject %p enc_frame_size: %d \n " ,
opus_strerror ( bytes ) , decoded_data_len , codec - > implementation - > number_of_channels , len ,
( void * ) decoded_data , ( void * ) encoded_data , ( void * ) context - > encoder_object , context - > enc_frame_size ) ;
2015-07-17 21:01:38 -04:00
switch_goto_status ( SWITCH_STATUS_GENERR , end ) ;
}
/* enc_ptr_buf : Opus API manual: "The application must ensure this pointer remains valid until the next call to opus_repacketizer_init() or opus_repacketizer_destroy()." */
ret = opus_repacketizer_cat ( rp , enc_ptr_buf , bytes ) ;
if ( ret ! = OPUS_OK ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( codec - > session ) , SWITCH_LOG_ERROR , " Opus encoder: error while repacketizing (cat) : %s ! \n " , opus_strerror ( ret ) ) ;
2015-07-17 21:01:38 -04:00
switch_goto_status ( SWITCH_STATUS_GENERR , end ) ;
2015-09-09 12:48:34 -05:00
}
2015-07-17 21:01:38 -04:00
enc_ptr_buf + = bytes ;
total_len + = bytes ;
2015-09-09 15:01:59 -04:00
dec_ptr_buf + = frame_size ;
2015-07-17 21:01:38 -04:00
}
/* this will never happen, unless there is a huge and unsupported number of frames */
if ( total_len + opus_repacketizer_get_nb_frames ( rp ) > len / 2 ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( codec - > session ) , SWITCH_LOG_ERROR , " Opus encoder: error while repacketizing: not enough buffer space \n " ) ;
2015-07-17 21:01:38 -04:00
switch_goto_status ( SWITCH_STATUS_GENERR , end ) ;
}
ret = opus_repacketizer_out ( rp , encoded_data , total_len + opus_repacketizer_get_nb_frames ( rp ) ) ;
2015-09-09 12:48:34 -05:00
2015-09-11 11:37:01 -05:00
if ( globals . debug | | context - > debug ) {
2015-07-17 21:01:38 -04:00
int samplerate = context - > enc_frame_size * 1000 / ( codec - > implementation - > microseconds_per_packet / 1000 ) ;
2022-08-18 19:48:20 +03:00
switch_opus_info ( codec - > session , encoded_data , ret , samplerate , " encode_repacketize " ) ;
2015-07-17 21:01:38 -04:00
}
2015-09-09 12:48:34 -05:00
2015-07-17 21:01:38 -04:00
if ( ret < = 0 ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( codec - > session ) , SWITCH_LOG_ERROR , " Opus encoder: error while repacketizing (out) : %s ! packed nb_frames: %d \n " , opus_strerror ( ret ) , opus_repacketizer_get_nb_frames ( rp ) ) ;
2015-07-17 21:01:38 -04:00
switch_goto_status ( SWITCH_STATUS_GENERR , end ) ;
}
2015-09-09 15:01:59 -04:00
if ( want_fec ) {
opus_encoder_ctl ( context - > encoder_object , OPUS_SET_INBAND_FEC ( want_fec ) ) ; /*restore FEC state*/
}
2015-07-17 21:01:38 -04:00
* encoded_data_len = ( uint32_t ) ret ;
end :
if ( rp ) {
opus_repacketizer_destroy ( rp ) ;
}
2015-09-09 12:48:34 -05:00
2015-07-17 21:01:38 -04:00
return status ;
}
2014-02-18 22:21:46 -06:00
static switch_status_t opus_load_config ( switch_bool_t reload )
{
char * cf = " opus.conf " ;
switch_xml_t cfg , xml = NULL , param , settings ;
switch_status_t status = SWITCH_STATUS_SUCCESS ;
2015-09-09 12:48:34 -05:00
2014-02-18 22:21:46 -06:00
if ( ! ( xml = switch_xml_open_cfg ( cf , & cfg , NULL ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Opening of %s failed \n " , cf ) ;
2014-02-27 15:25:29 -06:00
return status ;
2014-02-18 22:21:46 -06:00
}
2015-09-09 12:48:34 -05:00
2015-10-01 19:11:51 -05:00
memset ( & opus_prefs , 0 , sizeof ( opus_prefs ) ) ;
opus_prefs . use_jb_lookahead = 1 ;
opus_prefs . keep_fec = 1 ;
2015-10-04 16:53:43 -05:00
opus_prefs . use_dtx = 0 ;
2015-10-01 19:11:51 -05:00
opus_prefs . plpct = 20 ;
2015-10-04 16:53:43 -05:00
opus_prefs . use_vbr = 0 ;
2015-12-16 18:22:27 -06:00
opus_prefs . fec_decode = 1 ;
2015-10-01 19:11:51 -05:00
2014-02-18 22:21:46 -06:00
if ( ( settings = switch_xml_child ( cfg , " settings " ) ) ) {
for ( param = switch_xml_child ( settings , " param " ) ; param ; param = param - > next ) {
char * key = ( char * ) switch_xml_attr_soft ( param , " name " ) ;
char * val = ( char * ) switch_xml_attr_soft ( param , " value " ) ;
2015-09-09 12:48:34 -05:00
2014-02-19 12:46:23 -06:00
if ( ! strcasecmp ( key , " use-vbr " ) & & ! zstr ( val ) ) {
2022-01-08 12:14:16 +02:00
opus_prefs . use_vbr = switch_true ( val ) ;
2015-07-13 18:10:10 -04:00
} else if ( ! strcasecmp ( key , " use-dtx " ) ) {
2022-01-08 12:14:16 +02:00
opus_prefs . use_dtx = switch_true ( val ) ;
2014-02-18 22:21:46 -06:00
} else if ( ! strcasecmp ( key , " complexity " ) ) {
opus_prefs . complexity = atoi ( val ) ;
2015-06-04 15:57:33 -05:00
} else if ( ! strcasecmp ( key , " packet-loss-percent " ) ) {
opus_prefs . plpct = atoi ( val ) ;
2015-06-11 14:07:02 -04:00
} else if ( ! strcasecmp ( key , " asymmetric-sample-rates " ) ) {
2022-01-08 12:14:16 +02:00
opus_prefs . asymmetric_samplerates = switch_true ( val ) ;
2016-09-28 11:22:40 -04:00
} else if ( ! strcasecmp ( key , " bitrate-negotiation " ) ) {
2022-01-08 12:14:16 +02:00
opus_prefs . bitrate_negotiation = switch_true ( val ) ;
2015-09-11 11:37:01 -05:00
} else if ( ! strcasecmp ( key , " use-jb-lookahead " ) ) {
opus_prefs . use_jb_lookahead = switch_true ( val ) ;
2015-10-03 13:45:24 -04:00
} else if ( ! strcasecmp ( key , " keep-fec-enabled " ) ) { /* encoder */
2022-01-08 12:14:16 +02:00
opus_prefs . keep_fec = switch_true ( val ) ;
2015-10-07 11:34:35 -04:00
} else if ( ! strcasecmp ( key , " advertise-useinbandfec " ) ) { /*decoder, has meaning only for FMTP: useinbandfec=1 by default */
2022-01-08 12:14:16 +02:00
opus_prefs . fec_decode = switch_true ( val ) ;
2015-10-23 20:27:25 -04:00
} else if ( ! strcasecmp ( key , " adjust-bitrate " ) ) { /* encoder, this setting will make the encoder adjust its bitrate based on a feedback loop (RTCP). This is not "VBR".*/
2022-01-08 12:14:16 +02:00
opus_prefs . adjust_bitrate = switch_true ( val ) ;
2014-11-13 13:48:04 +01:00
} else if ( ! strcasecmp ( key , " maxaveragebitrate " ) ) {
opus_prefs . maxaveragebitrate = atoi ( val ) ;
2015-10-23 20:27:25 -04:00
if ( opus_prefs . maxaveragebitrate < SWITCH_OPUS_MIN_BITRATE | | opus_prefs . maxaveragebitrate > SWITCH_OPUS_MAX_BITRATE ) {
2014-11-13 13:48:04 +01:00
opus_prefs . maxaveragebitrate = 0 ; /* values outside the range between 6000 and 510000 SHOULD be ignored */
}
} else if ( ! strcasecmp ( key , " maxplaybackrate " ) ) {
opus_prefs . maxplaybackrate = atoi ( val ) ;
2015-07-13 19:46:00 -04:00
if ( ! switch_opus_acceptable_rate ( opus_prefs . maxplaybackrate ) ) {
2014-11-13 13:48:04 +01:00
opus_prefs . maxplaybackrate = 0 ; /* value not supported */
}
2015-06-11 14:07:02 -04:00
} else if ( ! strcasecmp ( key , " sprop-maxcapturerate " ) ) {
opus_prefs . sprop_maxcapturerate = atoi ( val ) ;
if ( ! switch_opus_acceptable_rate ( opus_prefs . sprop_maxcapturerate ) ) {
2015-07-13 19:46:00 -04:00
opus_prefs . sprop_maxcapturerate = 0 ; /* value not supported */
2015-06-11 14:07:02 -04:00
}
2021-05-14 18:36:30 +03:00
} else if ( ! strcasecmp ( key , " mono " ) ) {
2022-01-08 12:14:16 +02:00
opus_prefs . mono = switch_true ( val ) ;
2014-02-18 22:21:46 -06:00
}
}
}
2015-09-09 12:48:34 -05:00
2019-07-12 19:57:22 +04:00
switch_xml_free ( xml ) ;
2015-09-09 12:48:34 -05:00
return status ;
2014-02-18 22:21:46 -06:00
}
2015-07-03 11:21:27 -04:00
static switch_status_t switch_opus_keep_fec_enabled ( switch_codec_t * codec )
{
struct opus_context * context = codec - > private_info ;
opus_int32 current_bitrate ;
opus_int32 current_loss ;
2015-09-09 12:48:34 -05:00
uint32_t LBRR_threshold_bitrate , LBRR_rate_thres_bps , real_target_bitrate ;
opus_int32 a32 , b32 ;
2015-07-03 11:21:27 -04:00
uint32_t fs = context - > enc_frame_size * 1000 / ( codec - > implementation - > microseconds_per_packet / 1000 ) ;
2023-03-23 15:06:56 +02:00
float frame_rate = ( float ) ( 1000 / ( float ) ( codec - > implementation - > microseconds_per_packet / 1000 ) ) ;
2015-07-09 07:22:19 -04:00
uint32_t step = ( codec - > implementation - > microseconds_per_packet / 1000 ) ! = 60 ? 8000 / ( codec - > implementation - > microseconds_per_packet / 1000 ) : 134 ;
2015-07-03 11:21:27 -04:00
opus_encoder_ctl ( context - > encoder_object , OPUS_GET_BITRATE ( & current_bitrate ) ) ;
opus_encoder_ctl ( context - > encoder_object , OPUS_GET_PACKET_LOSS_PERC ( & current_loss ) ) ;
2015-09-09 12:48:34 -05:00
if ( current_loss = = 0 ) {
2015-07-09 07:22:19 -04:00
opus_encoder_ctl ( context - > encoder_object , OPUS_SET_BITRATE ( opus_prefs . maxaveragebitrate ) ) ;
2015-09-09 12:48:34 -05:00
2015-07-09 07:22:19 -04:00
return SWITCH_STATUS_SUCCESS ;
}
2015-09-09 12:48:34 -05:00
if ( fs = = 8000 ) {
2015-07-03 11:21:27 -04:00
LBRR_rate_thres_bps = 12000 ; /*LBRR_NB_MIN_RATE_BPS*/
2015-09-09 12:48:34 -05:00
} else if ( fs = = 12000 ) {
2015-07-03 11:21:27 -04:00
LBRR_rate_thres_bps = 14000 ; /*LBRR_MB_MIN_RATE_BPS*/
2015-09-09 12:48:34 -05:00
} else {
2015-07-03 11:21:27 -04:00
LBRR_rate_thres_bps = 16000 ; /*LBRR_WB_MIN_RATE_BPS*/
}
/*see opus-1.1/src/opus_encoder.c , opus_encode_native() */
2015-08-31 13:25:18 -04:00
real_target_bitrate = ( uint32_t ) ( 8 * ( current_bitrate * context - > enc_frame_size / ( fs * 8 ) - 1 ) * frame_rate ) ;
2015-07-03 11:21:27 -04:00
/*check if the internally used bitrate is above the threshold defined in opus-1.1/silk/control_codec.c */
a32 = LBRR_rate_thres_bps * ( 125 - ( ( ( current_loss ) < ( 25 ) ) ? ( current_loss ) : ( 25 ) ) ) ;
b32 = ( ( opus_int32 ) ( ( 0.01 ) * ( ( opus_int64 ) 1 < < ( 16 ) ) + 0.5 ) ) ;
LBRR_threshold_bitrate = ( a32 > > 16 ) * ( opus_int32 ) ( ( opus_int16 ) b32 ) + ( ( ( a32 & 0x0000FFFF ) * ( opus_int32 ) ( ( opus_int16 ) b32 ) ) > > 16 ) ;
2015-09-09 12:48:34 -05:00
2019-07-12 19:57:22 +04:00
if ( ! real_target_bitrate | | ! LBRR_threshold_bitrate ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( codec - > session ) , SWITCH_LOG_ERROR , " Opus encoder: error while controlling FEC params \n " ) ;
2015-09-09 12:48:34 -05:00
2015-07-03 11:21:27 -04:00
return SWITCH_STATUS_FALSE ;
}
2015-09-09 12:48:34 -05:00
/* Is there any FEC at the current bitrate and requested packet loss ?
2015-07-03 11:21:27 -04:00
* If yes , then keep the current bitrate . If not , modify bitrate to keep FEC on . */
if ( real_target_bitrate > LBRR_threshold_bitrate ) {
/*FEC is already enabled, do nothing*/
2015-09-11 11:37:01 -05:00
if ( globals . debug | | context - > debug ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( codec - > session ) , SWITCH_LOG_DEBUG , " Opus encoder: FEC is enabled \n " ) ;
2015-09-09 12:48:34 -05:00
}
2015-07-03 11:21:27 -04:00
return SWITCH_STATUS_SUCCESS ;
} else {
while ( real_target_bitrate < = LBRR_threshold_bitrate ) {
current_bitrate + = step ;
2015-08-31 13:25:18 -04:00
real_target_bitrate = ( uint32_t ) ( 8 * ( current_bitrate * context - > enc_frame_size / ( fs * 8 ) - 1 ) * frame_rate ) ;
2015-07-03 11:21:27 -04:00
}
2015-09-09 12:48:34 -05:00
2015-07-03 11:21:27 -04:00
opus_encoder_ctl ( context - > encoder_object , OPUS_SET_BITRATE ( current_bitrate ) ) ;
2015-09-09 12:48:34 -05:00
2015-09-11 11:37:01 -05:00
if ( globals . debug | | context - > debug ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( codec - > session ) , SWITCH_LOG_DEBUG , " Opus encoder: increased bitrate to [%d] to keep FEC enabled \n " , current_bitrate ) ;
2015-09-09 12:48:34 -05:00
}
2015-07-03 11:21:27 -04:00
return SWITCH_STATUS_SUCCESS ;
}
}
2015-06-05 18:11:14 -05:00
static switch_status_t switch_opus_control ( switch_codec_t * codec ,
switch_codec_control_command_t cmd ,
switch_codec_control_type_t ctype ,
void * cmd_data ,
2015-09-11 11:37:01 -05:00
switch_codec_control_type_t atype ,
void * cmd_arg ,
2015-06-05 18:11:14 -05:00
switch_codec_control_type_t * rtype ,
void * * ret_data )
{
struct opus_context * context = codec - > private_info ;
switch ( cmd ) {
2015-09-11 11:37:01 -05:00
case SCC_CODEC_SPECIFIC :
{
2015-10-26 13:45:48 -04:00
const char * command = ( const char * ) cmd_data ;
2015-09-11 11:37:01 -05:00
const char * arg = ( const char * ) cmd_arg ;
switch_codec_control_type_t reply_type = SCCT_STRING ;
const char * reply = " ERROR INVALID COMMAND " ;
2015-10-26 13:45:48 -04:00
if ( ! zstr ( command ) ) {
if ( ! strcasecmp ( command , " jb_lookahead " ) ) {
2015-09-11 11:37:01 -05:00
if ( ! zstr ( arg ) ) {
context - > use_jb_lookahead = switch_true ( arg ) ;
}
reply = context - > use_jb_lookahead ? " LOOKAHEAD ON " : " LOOKAHEAD OFF " ;
}
}
if ( rtype ) {
* rtype = reply_type ;
2019-07-12 19:57:22 +04:00
* ret_data = ( void * ) reply ;
2015-09-11 11:37:01 -05:00
}
}
break ;
case SCC_DEBUG :
{
int32_t level = * ( ( uint32_t * ) cmd_data ) ;
context - > debug = level ;
}
break ;
2015-06-05 18:11:14 -05:00
case SCC_AUDIO_PACKET_LOSS :
{
uint32_t plpct = * ( ( uint32_t * ) cmd_data ) ;
uint32_t calc ;
if ( plpct > 100 ) {
plpct = 100 ;
}
2015-09-17 12:52:55 -04:00
if ( opus_prefs . keep_fec ) {
opus_encoder_ctl ( context - > encoder_object , OPUS_SET_PACKET_LOSS_PERC ( plpct ) ) ;
} else {
calc = plpct % 10 ;
plpct = plpct - calc + ( calc ? 10 : 0 ) ;
2015-09-11 11:37:01 -05:00
}
2015-06-05 18:11:14 -05:00
if ( plpct ! = context - > old_plpct ) {
2015-09-09 12:48:34 -05:00
if ( opus_prefs . keep_fec ) {
2015-09-17 12:52:55 -04:00
if ( plpct > 10 ) {
/* this will increase bitrate a little bit, just to keep FEC enabled */
switch_opus_keep_fec_enabled ( codec ) ;
}
} else {
/* this can have no effect because FEC is F(bitrate,packetloss), let the codec decide if FEC is to be used or not */
opus_encoder_ctl ( context - > encoder_object , OPUS_SET_PACKET_LOSS_PERC ( plpct ) ) ;
2015-09-09 12:48:34 -05:00
}
2015-09-11 11:37:01 -05:00
if ( globals . debug | | context - > debug ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( codec - > session ) , SWITCH_LOG_DEBUG , " Opus encoder: Adjusting packet loss percent from %d%% to %d%%! \n " ,
2015-09-09 12:48:34 -05:00
context - > old_plpct , plpct ) ;
}
2015-06-05 18:11:14 -05:00
}
2016-10-01 19:00:04 -04:00
if ( opus_prefs . adjust_bitrate ) {
2017-01-06 02:10:15 -05:00
/* make bitrate adjust the step , but keep it as a multiple of 400 (see OpusFAQ).
2016-10-01 19:00:04 -04:00
* usual RTCP interval is 5 seconds which is long time - the step should be bigger . */
2017-01-06 02:10:15 -05:00
/* step's value should depend on packet loss too, to decrease more abrubtly
2016-10-01 19:00:04 -04:00
* at high packet loss . */
int base_step = 400 ; /*bps*/
int range = context - > codec_settings . maxaveragebitrate - SWITCH_OPUS_MIN_BITRATE ;
float steps = ( float ) ( ( float ) ( range / 100 ) / base_step ) ;
2017-01-06 02:10:15 -05:00
int br_step = ( int ) ( round ( steps ) * base_step ) * plpct ;
2016-10-01 19:00:04 -04:00
if ( globals . debug | | context - > debug ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( codec - > session ) ,
2017-01-06 02:10:15 -05:00
SWITCH_LOG_DEBUG , " Opus encoder: bitrate increase/decrease step now is: %d bps, range:%d \n " , br_step , range ) ;
2016-10-01 19:00:04 -04:00
}
2017-01-06 02:10:15 -05:00
context - > control_state . increase_step = context - > control_state . decrease_step = br_step ;
2016-10-01 19:00:04 -04:00
}
2015-06-05 18:11:14 -05:00
context - > old_plpct = plpct ;
}
break ;
2015-10-23 20:27:25 -04:00
case SCC_AUDIO_ADJUST_BITRATE :
{
const char * cmd = ( const char * ) cmd_data ;
if ( ! zstr ( cmd ) ) {
opus_int32 current_bitrate = context - > control_state . current_bitrate ;
if ( ! strcasecmp ( cmd , " increase " ) ) {
/* https://wiki.xiph.org/OpusFAQ
2017-01-06 02:10:15 -05:00
" [...]Opus scales from about 6 to 512 kb/s, in increments of 0.4 kb/s (one byte with 20 ms frames).
2015-10-23 20:27:25 -04:00
Opus can have more than 1200 possible bitrates [ . . . ] " */
int br_step = context - > control_state . increase_step ? context - > control_state . increase_step : 400 ;
opus_encoder_ctl ( context - > encoder_object , OPUS_GET_BITRATE ( & current_bitrate ) ) ;
if ( opus_prefs . maxaveragebitrate > current_bitrate ) {
opus_encoder_ctl ( context - > encoder_object , OPUS_SET_BITRATE ( current_bitrate + br_step ) ) ;
if ( ( context - > control_state . keep_fec ) & & ( current_bitrate > SWITCH_OPUS_MIN_FEC_BITRATE ) ) {
opus_prefs . keep_fec = 1 ; /* enable back FEC if it was disabled by SCC_AUDIO_ADJUST_BITRATE, we have enough network bandwidth now */
2017-01-06 02:10:15 -05:00
}
2015-10-23 20:27:25 -04:00
if ( globals . debug | | context - > debug ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( codec - > session ) , SWITCH_LOG_DEBUG , " Opus encoder: Adjusting bitrate to %d (increase) \n " , current_bitrate + br_step ) ;
2015-10-23 20:27:25 -04:00
}
}
} else if ( ! strcasecmp ( cmd , " decrease " ) ) {
int br_step = context - > control_state . decrease_step ? context - > control_state . decrease_step : 400 ;
opus_encoder_ctl ( context - > encoder_object , OPUS_GET_BITRATE ( & current_bitrate ) ) ;
if ( current_bitrate > SWITCH_OPUS_MIN_BITRATE ) {
2016-10-01 19:00:04 -04:00
if ( context - > control_state . keep_fec ) {
2017-01-06 02:10:15 -05:00
/* no point to try to keep FEC enabled anymore,
2016-10-01 19:00:04 -04:00
* we ' re low on network bandwidth ( that ' s why we ended up here ) */
opus_prefs . keep_fec = 0 ;
2015-10-23 20:27:25 -04:00
}
opus_encoder_ctl ( context - > encoder_object , OPUS_SET_BITRATE ( current_bitrate - br_step ) ) ;
if ( globals . debug | | context - > debug ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( codec - > session ) , SWITCH_LOG_DEBUG , " Opus encoder: Adjusting bitrate to %d (decrease) \n " , current_bitrate - br_step ) ;
2015-10-23 20:27:25 -04:00
}
}
} else if ( ! strcasecmp ( cmd , " default " ) ) {
/*restore default bitrate */
opus_encoder_ctl ( context - > encoder_object , OPUS_SET_BITRATE ( opus_prefs . maxaveragebitrate ) ) ;
if ( context - > control_state . keep_fec ) {
opus_prefs . keep_fec = 1 ; /* enable back FEC, we have enough network bandwidth now */
2017-01-06 02:10:15 -05:00
}
2015-10-23 20:27:25 -04:00
if ( globals . debug | | context - > debug ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( codec - > session ) , SWITCH_LOG_DEBUG , " Opus encoder: Adjusting bitrate to %d (configured maxaveragebitrate) \n " , opus_prefs . maxaveragebitrate ) ;
2015-10-23 20:27:25 -04:00
}
} else {
/* set Opus minimum bitrate */
opus_encoder_ctl ( context - > encoder_object , OPUS_SET_BITRATE ( SWITCH_OPUS_MIN_BITRATE ) ) ;
if ( context - > control_state . keep_fec ) {
opus_prefs . keep_fec = 0 ; /* do not enforce FEC anymore, we're low on network bandwidth */
2017-01-06 02:10:15 -05:00
}
2015-10-23 20:27:25 -04:00
if ( globals . debug | | context - > debug ) {
2022-08-18 19:48:20 +03:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( codec - > session ) , SWITCH_LOG_DEBUG , " Opus encoder: Adjusting bitrate to %d (minimum) \n " , SWITCH_OPUS_MIN_BITRATE ) ;
2015-10-23 20:27:25 -04:00
}
}
}
}
break ;
2015-06-05 18:11:14 -05:00
default :
break ;
}
return SWITCH_STATUS_SUCCESS ;
}
2015-06-15 11:42:51 -04:00
# define OPUS_DEBUG_SYNTAX "<on|off>"
SWITCH_STANDARD_API ( mod_opus_debug )
{
if ( zstr ( cmd ) ) {
stream - > write_function ( stream , " -USAGE: %s \n " , OPUS_DEBUG_SYNTAX ) ;
} else {
if ( ! strcasecmp ( cmd , " on " ) ) {
globals . debug = 1 ;
stream - > write_function ( stream , " OPUS Debug: on \n " ) ;
2015-09-10 19:17:08 -04:00
stream - > write_function ( stream , " Library version: %s \n " , opus_get_version_string ( ) ) ;
2015-06-15 11:42:51 -04:00
} else if ( ! strcasecmp ( cmd , " off " ) ) {
globals . debug = 0 ;
stream - > write_function ( stream , " OPUS Debug: off \n " ) ;
} else {
stream - > write_function ( stream , " -USAGE: %s \n " , OPUS_DEBUG_SYNTAX ) ;
}
}
return SWITCH_STATUS_SUCCESS ;
}
2015-06-05 18:11:14 -05:00
2011-02-04 15:33:28 -06:00
SWITCH_MODULE_LOAD_FUNCTION ( mod_opus_load )
{
switch_codec_interface_t * codec_interface ;
2015-06-15 11:42:51 -04:00
switch_api_interface_t * commands_api_interface ;
2022-08-24 13:02:35 +03:00
int samples = 480 ; /* start with 10 ms ptime */
2012-11-05 10:33:28 -06:00
int bytes = 960 ;
2011-02-04 16:25:00 -06:00
int mss = 10000 ;
int x = 0 ;
int rate = 48000 ;
2013-11-08 03:44:21 +05:00
int bits = 0 ;
char * dft_fmtp = NULL ;
opus_codec_settings_t settings = { 0 } ;
2015-09-09 12:48:34 -05:00
switch_status_t status = SWITCH_STATUS_SUCCESS ;
2014-02-18 22:21:46 -06:00
if ( ( status = opus_load_config ( SWITCH_FALSE ) ) ! = SWITCH_STATUS_SUCCESS ) {
return status ;
}
2015-09-09 12:48:34 -05:00
2011-02-04 15:33:28 -06:00
/* connect my internal structure to the blank pointer passed to me */
* module_interface = switch_loadable_module_create_module_interface ( pool , modname ) ;
2015-09-09 12:48:34 -05:00
2012-09-13 10:32:00 -05:00
SWITCH_ADD_CODEC ( codec_interface , " OPUS (STANDARD) " ) ;
2015-06-15 11:42:51 -04:00
SWITCH_ADD_API ( commands_api_interface , " opus_debug " , " Set OPUS Debug " , mod_opus_debug , OPUS_DEBUG_SYNTAX ) ;
2015-09-09 12:48:34 -05:00
2015-06-18 17:34:59 -04:00
switch_console_set_complete ( " add opus_debug on " ) ;
switch_console_set_complete ( " add opus_debug off " ) ;
2013-11-08 03:44:21 +05:00
codec_interface - > parse_fmtp = switch_opus_fmtp_parse ;
2015-09-09 12:48:34 -05:00
2016-12-20 10:34:16 -05:00
/* 48 khz */
2013-11-08 03:44:21 +05:00
settings = default_codec_settings ;
2015-09-09 12:48:34 -05:00
2015-10-03 13:45:24 -04:00
settings . useinbandfec = opus_prefs . fec_decode ;
settings . cbr = ! opus_prefs . use_vbr ;
2015-10-02 08:13:05 -07:00
settings . usedtx = opus_prefs . use_dtx ;
2015-09-09 12:48:34 -05:00
if ( opus_prefs . maxaveragebitrate ) {
settings . maxaveragebitrate = opus_prefs . maxaveragebitrate ;
}
if ( opus_prefs . maxplaybackrate ) {
settings . maxplaybackrate = opus_prefs . maxplaybackrate ;
}
2015-06-11 14:07:02 -04:00
if ( opus_prefs . sprop_maxcapturerate ) {
settings . sprop_maxcapturerate = opus_prefs . sprop_maxcapturerate ;
}
2015-04-22 16:04:07 +02:00
2012-10-13 19:03:53 -04:00
for ( x = 0 ; x < 3 ; x + + ) {
2015-09-09 12:48:34 -05:00
2013-11-08 03:44:21 +05:00
settings . ptime = mss / 1000 ;
settings . samplerate = rate ;
2014-06-13 01:49:10 -04:00
settings . stereo = 0 ;
2013-11-08 03:44:21 +05:00
dft_fmtp = gen_fmtp ( & settings , pool ) ;
2014-10-28 14:19:06 -05:00
2011-02-04 16:25:00 -06:00
switch_core_codec_add_implementation ( pool , codec_interface , SWITCH_CODEC_TYPE_AUDIO , /* enumeration defining the type of the codec */
2012-10-13 19:03:53 -04:00
116 , /* the IANA code number */
2012-09-13 10:32:00 -05:00
" opus " , /* the IANA code name */
2013-11-08 03:44:21 +05:00
dft_fmtp , /* default fmtp to send (can be overridden by the init function) */
48000 , /* samples transferred per second */
2011-02-04 16:25:00 -06:00
rate , /* actual samples transferred per second */
bits , /* bits transferred per second */
mss , /* number of microseconds per frame */
samples , /* number of samples per frame */
bytes , /* number of bytes per frame decompressed */
0 , /* number of bytes per frame compressed */
2013-02-12 14:26:55 -06:00
1 , /* number of channels represented */
2011-02-04 16:25:00 -06:00
1 , /* number of frames per network packet */
switch_opus_init , /* function to initialize a codec handle using this implementation */
switch_opus_encode , /* function to encode raw data into encoded data */
switch_opus_decode , /* function to decode encoded data into raw data */
switch_opus_destroy ) ; /* deinitalize a codec handle using this implementation */
2015-06-05 18:11:14 -05:00
codec_interface - > implementations - > codec_control = switch_opus_control ;
2015-09-09 12:48:34 -05:00
2014-06-12 22:06:33 +05:00
settings . stereo = 1 ;
2016-06-02 13:14:19 -05:00
dft_fmtp = gen_fmtp ( & settings , pool ) ;
switch_core_codec_add_implementation ( pool , codec_interface , SWITCH_CODEC_TYPE_AUDIO , /* enumeration defining the type of the codec */
116 , /* the IANA code number */
" opus " , /* the IANA code name */
dft_fmtp , /* default fmtp to send (can be overridden by the init function) */
rate , /* samples transferred per second */
rate , /* actual samples transferred per second */
bits , /* bits transferred per second */
mss , /* number of microseconds per frame */
samples , /* number of samples per frame */
bytes * 2 , /* number of bytes per frame decompressed */
0 , /* number of bytes per frame compressed */
2 , /* number of channels represented */
1 , /* number of frames per network packet */
switch_opus_init , /* function to initialize a codec handle using this implementation */
switch_opus_encode , /* function to encode raw data into encoded data */
switch_opus_decode , /* function to decode encoded data into raw data */
switch_opus_destroy ) ; /* deinitalize a codec handle using this implementation */
codec_interface - > implementations - > codec_control = switch_opus_control ;
2017-01-06 02:10:15 -05:00
2011-02-04 16:25:00 -06:00
bytes * = 2 ;
samples * = 2 ;
mss * = 2 ;
}
2015-09-09 12:48:34 -05:00
2016-12-20 10:34:16 -05:00
/* 16 khz */
2022-08-24 13:02:35 +03:00
samples = 160 ;
2016-12-20 10:34:16 -05:00
bytes = 320 ;
mss = 10000 ;
rate = 16000 ;
settings = default_codec_settings_16k ;
settings . useinbandfec = opus_prefs . fec_decode ;
settings . cbr = ! opus_prefs . use_vbr ;
settings . usedtx = opus_prefs . use_dtx ;
if ( opus_prefs . maxaveragebitrate ) {
settings . maxaveragebitrate = opus_prefs . maxaveragebitrate ;
}
if ( opus_prefs . maxplaybackrate ) {
settings . maxplaybackrate = opus_prefs . maxplaybackrate ;
}
if ( opus_prefs . sprop_maxcapturerate ) {
settings . sprop_maxcapturerate = opus_prefs . sprop_maxcapturerate ;
}
for ( x = 0 ; x < 3 ; x + + ) {
settings . stereo = 0 ;
settings . ptime = mss / 1000 ;
settings . samplerate = rate ;
dft_fmtp = gen_fmtp ( & settings , pool ) ;
switch_core_codec_add_implementation ( pool , codec_interface , SWITCH_CODEC_TYPE_AUDIO , /* enumeration defining the type of the codec */
116 , /* the IANA code number */
" opus " , /* the IANA code name */
dft_fmtp , /* default fmtp to send (can be overridden by the init function) */
48000 , /* samples transferred per second */
rate , /* actual samples transferred per second */
bits , /* bits transferred per second */
mss , /* number of microseconds per frame */
samples , /* number of samples per frame */
bytes , /* number of bytes per frame decompressed */
0 , /* number of bytes per frame compressed */
1 , /* number of channels represented */
1 , /* number of frames per network packet */
switch_opus_init , /* function to initialize a codec handle using this implementation */
switch_opus_encode , /* function to encode raw data into encoded data */
switch_opus_decode , /* function to decode encoded data into raw data */
switch_opus_destroy ) ; /* deinitalize a codec handle using this implementation */
codec_interface - > implementations - > codec_control = switch_opus_control ;
settings . stereo = 1 ;
dft_fmtp = gen_fmtp ( & settings , pool ) ;
switch_core_codec_add_implementation ( pool , codec_interface , SWITCH_CODEC_TYPE_AUDIO , /* enumeration defining the type of the codec */
116 , /* the IANA code number */
" opus " , /* the IANA code name */
dft_fmtp , /* default fmtp to send (can be overridden by the init function) */
48000 , /* samples transferred per second */
rate , /* actual samples transferred per second */
bits , /* bits transferred per second */
mss , /* number of microseconds per frame */
samples , /* number of samples per frame */
bytes * 2 , /* number of bytes per frame decompressed */
0 , /* number of bytes per frame compressed */
2 , /* number of channels represented */
1 , /* number of frames per network packet */
switch_opus_init , /* function to initialize a codec handle using this implementation */
switch_opus_encode , /* function to encode raw data into encoded data */
switch_opus_decode , /* function to decode encoded data into raw data */
switch_opus_destroy ) ; /* deinitalize a codec handle using this implementation */
codec_interface - > implementations - > codec_control = switch_opus_control ;
if ( x = = 1 ) { /*20 ms * 3 = 60 ms */
settings . stereo = 0 ;
settings . ptime = mss * 3 / 1000 ;
dft_fmtp = gen_fmtp ( & settings , pool ) ;
switch_core_codec_add_implementation ( pool , codec_interface , SWITCH_CODEC_TYPE_AUDIO , /* enumeration defining the type of the codec */
116 , /* the IANA code number */
" opus " , /* the IANA code name */
dft_fmtp , /* default fmtp to send (can be overridden by the init function) */
48000 , /* samples transferred per second */
rate , /* actual samples transferred per second */
bits , /* bits transferred per second */
mss * 3 , /* number of microseconds per frame */
samples * 3 , /* number of samples per frame */
bytes * 3 , /* number of bytes per frame decompressed */
0 , /* number of bytes per frame compressed */
1 , /* number of channels represented */
1 , /* number of frames per network packet */
switch_opus_init , /* function to initialize a codec handle using this implementation */
switch_opus_encode , /* function to encode raw data into encoded data */
switch_opus_decode , /* function to decode encoded data into raw data */
switch_opus_destroy ) ; /* deinitalize a codec handle using this implementation */
codec_interface - > implementations - > codec_control = switch_opus_control ;
}
bytes * = 2 ;
samples * = 2 ;
mss * = 2 ;
}
2015-09-09 12:48:34 -05:00
2016-12-20 10:34:16 -05:00
/* 8 khz */
2022-08-24 13:02:35 +03:00
samples = 80 ;
2013-11-08 03:44:21 +05:00
bytes = 160 ;
mss = 10000 ;
rate = 8000 ;
2014-10-28 14:19:06 -05:00
2015-09-09 15:17:20 -04:00
settings = default_codec_settings_8k ;
2015-10-03 13:45:24 -04:00
settings . useinbandfec = opus_prefs . fec_decode ;
settings . cbr = ! opus_prefs . use_vbr ;
settings . usedtx = opus_prefs . use_dtx ;
2015-09-09 15:17:20 -04:00
if ( opus_prefs . maxaveragebitrate ) {
settings . maxaveragebitrate = opus_prefs . maxaveragebitrate ;
}
if ( opus_prefs . maxplaybackrate ) {
settings . maxplaybackrate = opus_prefs . maxplaybackrate ;
}
if ( opus_prefs . sprop_maxcapturerate ) {
settings . sprop_maxcapturerate = opus_prefs . sprop_maxcapturerate ;
}
2013-11-08 03:44:21 +05:00
for ( x = 0 ; x < 3 ; x + + ) {
2015-09-09 12:48:34 -05:00
settings . stereo = 0 ;
2013-11-08 03:44:21 +05:00
settings . ptime = mss / 1000 ;
settings . samplerate = rate ;
dft_fmtp = gen_fmtp ( & settings , pool ) ;
2015-09-09 12:48:34 -05:00
2013-11-08 03:44:21 +05:00
switch_core_codec_add_implementation ( pool , codec_interface , SWITCH_CODEC_TYPE_AUDIO , /* enumeration defining the type of the codec */
116 , /* the IANA code number */
" opus " , /* the IANA code name */
dft_fmtp , /* default fmtp to send (can be overridden by the init function) */
48000 , /* samples transferred per second */
rate , /* actual samples transferred per second */
bits , /* bits transferred per second */
mss , /* number of microseconds per frame */
samples , /* number of samples per frame */
bytes , /* number of bytes per frame decompressed */
0 , /* number of bytes per frame compressed */
1 , /* number of channels represented */
1 , /* number of frames per network packet */
switch_opus_init , /* function to initialize a codec handle using this implementation */
switch_opus_encode , /* function to encode raw data into encoded data */
switch_opus_decode , /* function to decode encoded data into raw data */
switch_opus_destroy ) ; /* deinitalize a codec handle using this implementation */
2015-07-03 11:21:27 -04:00
codec_interface - > implementations - > codec_control = switch_opus_control ;
2014-10-28 14:19:06 -05:00
settings . stereo = 1 ;
dft_fmtp = gen_fmtp ( & settings , pool ) ;
switch_core_codec_add_implementation ( pool , codec_interface , SWITCH_CODEC_TYPE_AUDIO , /* enumeration defining the type of the codec */
116 , /* the IANA code number */
" opus " , /* the IANA code name */
dft_fmtp , /* default fmtp to send (can be overridden by the init function) */
48000 , /* samples transferred per second */
rate , /* actual samples transferred per second */
bits , /* bits transferred per second */
mss , /* number of microseconds per frame */
samples , /* number of samples per frame */
bytes * 2 , /* number of bytes per frame decompressed */
0 , /* number of bytes per frame compressed */
2 , /* number of channels represented */
1 , /* number of frames per network packet */
switch_opus_init , /* function to initialize a codec handle using this implementation */
switch_opus_encode , /* function to encode raw data into encoded data */
switch_opus_decode , /* function to decode encoded data into raw data */
switch_opus_destroy ) ; /* deinitalize a codec handle using this implementation */
2015-07-03 11:21:27 -04:00
codec_interface - > implementations - > codec_control = switch_opus_control ;
2015-09-09 12:48:34 -05:00
if ( x = = 1 ) { /*20 ms * 3 = 60 ms */
2015-07-17 21:01:38 -04:00
int nb_frames ;
2015-07-08 18:09:48 -04:00
settings . stereo = 0 ;
2015-09-09 15:17:20 -04:00
settings . ptime = mss * 3 / 1000 ;
2015-07-08 18:09:48 -04:00
dft_fmtp = gen_fmtp ( & settings , pool ) ;
switch_core_codec_add_implementation ( pool , codec_interface , SWITCH_CODEC_TYPE_AUDIO , /* enumeration defining the type of the codec */
116 , /* the IANA code number */
" opus " , /* the IANA code name */
dft_fmtp , /* default fmtp to send (can be overridden by the init function) */
48000 , /* samples transferred per second */
rate , /* actual samples transferred per second */
bits , /* bits transferred per second */
mss * 3 , /* number of microseconds per frame */
samples * 3 , /* number of samples per frame */
2015-07-17 21:01:38 -04:00
bytes * 3 , /* number of bytes per frame decompressed */
2015-07-08 18:09:48 -04:00
0 , /* number of bytes per frame compressed */
1 , /* number of channels represented */
1 , /* number of frames per network packet */
switch_opus_init , /* function to initialize a codec handle using this implementation */
switch_opus_encode , /* function to encode raw data into encoded data */
switch_opus_decode , /* function to decode encoded data into raw data */
switch_opus_destroy ) ; /* deinitalize a codec handle using this implementation */
codec_interface - > implementations - > codec_control = switch_opus_control ;
2015-07-17 21:01:38 -04:00
for ( nb_frames = 4 ; nb_frames < = 6 ; nb_frames + + ) {
/*20 ms * nb_frames = 80 ms , 100 ms , 120 ms */
settings . stereo = 0 ;
2015-09-09 15:17:20 -04:00
settings . ptime = mss * nb_frames / 1000 ;
2015-07-17 21:01:38 -04:00
dft_fmtp = gen_fmtp ( & settings , pool ) ;
switch_core_codec_add_implementation ( pool , codec_interface , SWITCH_CODEC_TYPE_AUDIO , /* enumeration defining the type of the codec */
116 , /* the IANA code number */
" opus " , /* the IANA code name */
dft_fmtp , /* default fmtp to send (can be overridden by the init function) */
48000 , /* samples transferred per second */
rate , /* actual samples transferred per second */
bits , /* bits transferred per second */
mss * nb_frames , /* number of microseconds per frame */
samples * nb_frames , /* number of samples per frame */
bytes * nb_frames , /* number of bytes per frame decompressed */
0 , /* number of bytes per frame compressed */
1 , /* number of channels represented */
1 , /* number of frames per network packet */
switch_opus_init , /* function to initialize a codec handle using this implementation */
switch_opus_encode_repacketize , /* function to encode raw data into encoded data */
switch_opus_decode , /* function to decode encoded data into raw data */
switch_opus_destroy ) ; /* deinitalize a codec handle using this implementation */
codec_interface - > implementations - > codec_control = switch_opus_control ;
2015-09-09 12:48:34 -05:00
2015-07-17 21:01:38 -04:00
}
2015-09-09 12:48:34 -05:00
}
2015-07-17 21:01:38 -04:00
2015-07-07 07:56:55 -04:00
bytes * = 2 ;
samples * = 2 ;
mss * = 2 ;
2013-11-08 03:44:21 +05:00
}
2015-09-09 12:48:34 -05:00
2016-12-20 10:34:16 -05:00
2011-02-04 15:33:28 -06:00
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS ;
}
2015-06-05 18:11:14 -05:00
2011-02-04 15:33:28 -06:00
/* For Emacs:
* Local Variables :
* mode : c
* indent - tabs - mode : t
* tab - width : 4
* c - basic - offset : 4
* End :
* For VIM :
2013-06-25 11:50:17 -05:00
* vim : set softtabstop = 4 shiftwidth = 4 tabstop = 4 noet :
2011-02-04 15:33:28 -06:00
*/