@ -47,6 +47,7 @@
*/
# include <opus/opus.h>
# include <stdio.h>
# define _OPUS_APPLICATION_ OPUS_APPLICATION_VOIP
/* Allowed values:
@ -88,6 +89,10 @@ static long opus_create(const char* format_parameters, const char** format_param
amci_codec_fmt_info_t * * format_description ) ;
static void opus_destroy ( long h_inst ) ;
static int opus_negotiate_fmt ( int is_offer , const char * params_in , char * params_out , unsigned int params_out_len ) ;
static int opus_load ( const char * ModConfigPath ) ;
# if SYSTEM_SAMPLECLOCK_RATE >= 48000
# define _OPUS_RATE 48000
# elif SYSTEM_SAMPLECLOCK_RATE >= 24000
@ -103,13 +108,14 @@ static void opus_destroy(long h_inst);
static amci_codec_fmt_info_t opus_fmt_description [ ] = { { AMCI_FMT_FRAME_LENGTH , 20 } ,
{ AMCI_FMT_FRAME_SIZE , 20 * _OPUS_RATE / 1000 } , { 0 , 0 } } ;
BEGIN_EXPORTS ( " opus " , AMCI_NO_MODULEINIT , AMCI_NO_MODULEDESTROY )
BEGIN_EXPORTS ( " opus " , opus_load , AMCI_NO_MODULEDESTROY )
BEGIN_CODECS
CODEC ( CODEC_OPUS , pcm16_2_opus , opus_2_pcm16 , opus_plc ,
CODEC _WITH_FMT ( CODEC_OPUS , pcm16_2_opus , opus_2_pcm16 , opus_plc ,
opus_create ,
opus_destroy ,
NULL , NULL )
NULL , NULL ,
opus_negotiate_fmt )
END_CODECS
BEGIN_PAYLOADS
@ -126,13 +132,154 @@ typedef struct {
OpusDecoder * opus_dec ;
} opus_state_t ;
/* e.g. "maxplaybackrate=8000; stereo=0; useinbandfec=1" */
char default_format_parameters [ 80 ] ;
int opus_load ( const char * ModConfigPath ) {
default_format_parameters [ 0 ] = ' \0 ' ;
char conf_file [ 256 ] ;
if ( NULL ! = ModConfigPath ) {
sprintf ( conf_file , " %sopus.conf " , ModConfigPath ) ;
FILE * fp = fopen ( conf_file , " rt " ) ;
if ( fp ) {
char line [ 80 ] ;
while ( fgets ( line , 80 , fp ) ! = NULL ) {
if ( ! line [ 0 ] | | line [ 0 ] = = ' # ' )
continue ;
strcpy ( default_format_parameters , line ) ;
break ;
}
DBG ( " initialized default format parameters as '%s' \n " , default_format_parameters ) ;
fclose ( fp ) ;
}
}
DBG ( " OPUS: initialized \n " ) ;
return 0 ;
}
int opus_negotiate_fmt ( int is_offer , const char * params_in , char * params_out , unsigned int params_out_len ) {
// todo: properly negotiating features
strncpy ( params_out , default_format_parameters , params_out_len ) ;
return 0 ;
}
/*
Search for a parameter assignement in input string .
If it ' s not found * param_value is null , otherwise * param_value points to the
right hand term .
In both cases a pointer suitable for a new search is returned
*/
static char * read_param ( char * input , const char * param , char * * param_value )
{
int param_size ;
/* Eat spaces and semi-colons */
while ( * input & & ( * input = = ' ' | | * input = = ' ; ' | | * input = = ' " ' ) )
input ;
* param_value = NULL ;
param_size = strlen ( param ) ;
if ( strncmp ( input , param , param_size ) )
return input ;
if ( * ( input + param_size ) ! = ' = ' )
return input ;
input = param_size + 1 ;
/* Found and discarded a matching parameter */
* param_value = input ;
while ( * input & & * input ! = ' ' & & * input ! = ' ; ' & & * input ! = ' " ' )
input ;
if ( * input = = ' " ' )
{
* param_value = * param_value + 1 ; /* remove " */
/* string will end after next: " */
while ( * input & & * input ! = ' " ' & & * input ! = ' \r ' & & * input ! = ' \n ' )
input ;
if ( * input = = ' " ' )
input - - ; /* remove " */
}
if ( * input )
* input = 0 ;
return input ;
}
# define BLEN 63
void decode_format_parameters ( const char * format_parameters , unsigned int * maxbandwidth , int * useinbandfec , int * stereo ) {
if ( format_parameters & & strlen ( format_parameters ) < = BLEN ) {
char buffer2 [ BLEN + 1 ] ;
char * buffer = buffer2 ;
strcpy ( buffer , format_parameters ) ;
while ( * buffer ) {
char * param_value ;
/* maxplaybackrate */
buffer = read_param ( buffer , " maxplaybackrate " , & param_value ) ;
if ( param_value ) {
* maxbandwidth = atoi ( param_value ) ;
if ( ! * maxbandwidth ) {
* maxbandwidth = _OPUS_RATE ;
DBG ( " wrong maxbandwidth value '%s' \n " , param_value ) ;
}
continue ;
}
/* stereo */
buffer = read_param ( buffer , " stereo " , & param_value ) ;
if ( param_value ) {
if ( * param_value = = ' 1 ' )
* stereo = 1 ;
else
* stereo = 0 ;
continue ;
}
/* useinbandfec */
buffer = read_param ( buffer , " useinbandfec " , & param_value ) ;
if ( param_value ) {
if ( * param_value = = ' 1 ' )
* useinbandfec = 1 ;
else
* useinbandfec = 0 ;
continue ;
}
/* Unknown parameter */
if ( * buffer ) {
param_value = buffer ;
while ( * buffer & & * buffer ! = ' ; ' )
buffer ;
if ( * buffer )
* buffer = 0 ;
DBG ( " OPUS: SDP parameter fmtp: %s ignored in creating encoder. \n " , param_value ) ;
}
}
}
}
long opus_create ( const char * format_parameters , const char * * format_parameters_out ,
amci_codec_fmt_info_t * * format_description ) {
opus_state_t * codec_inst ;
int error ;
unsigned int maxbandwidth = _OPUS_RATE ;
int useinbandfec = _OPUS_INBAND_FEC_ ;
int stereo = 0 ;
if ( format_parameters ) {
DBG ( " \n \n \n " ) ;
DBG ( " OPUS params: >>%s<<. \n " , format_parameters ) ;
DBG ( " \n \n \n " ) ;
decode_format_parameters ( format_parameters , & maxbandwidth , & useinbandfec , & stereo ) ;
}
codec_inst = ( opus_state_t * ) malloc ( sizeof ( opus_state_t ) ) ;
@ -140,17 +287,34 @@ long opus_create(const char* format_parameters, const char** format_parameters_o
if ( ! codec_inst )
return - 1 ;
DBG ( " OPUS: creating encoder with maxbandwidth=%u, stereo=%s, useinbandfec=%s \n " ,
maxbandwidth , stereo ? " true " : " false " , useinbandfec ? " true " : " false " ) ;
codec_inst - > opus_enc = opus_encoder_create ( _OPUS_RATE , 1 , _OPUS_APPLICATION_ , & error ) ;
if ( error ) {
DBG ( " OPUS: error %d while creating encoder state. \n " , error ) ;
return - 1 ;
}
opus_encoder_ctl ( codec_inst - > opus_enc , OPUS_SET_FORCE_CHANNELS ( 1 ) ) ;
opus_encoder_ctl ( codec_inst - > opus_enc , OPUS_SET_MAX_BANDWIDTH ( _OPUS_MAX_BANDWIDTH_ ) ) ;
opus_encoder_ctl ( codec_inst - > opus_enc , OPUS_SET_FORCE_CHANNELS ( stereo ? 2 : 1 ) ) ;
unsigned int opus_set_bw = _OPUS_RATE ;
if ( maxbandwidth < = 8000 ) {
opus_set_bw = OPUS_BANDWIDTH_NARROWBAND ;
} else if ( maxbandwidth < = 12000 ) {
opus_set_bw = OPUS_BANDWIDTH_MEDIUMBAND ;
} else if ( maxbandwidth < = 16000 ) {
opus_set_bw = OPUS_BANDWIDTH_WIDEBAND ;
} else if ( maxbandwidth < = 24000 ) {
opus_set_bw = OPUS_BANDWIDTH_SUPERWIDEBAND ;
} else {
opus_set_bw = OPUS_BANDWIDTH_FULLBAND ;
}
opus_encoder_ctl ( codec_inst - > opus_enc , OPUS_SET_MAX_BANDWIDTH ( opus_set_bw ) ) ;
opus_encoder_ctl ( codec_inst - > opus_enc , OPUS_SET_PACKET_LOSS_PERC ( _OPUS_PKT_LOSS_PCT_ ) ) ;
opus_encoder_ctl ( codec_inst - > opus_enc , OPUS_SET_COMPLEXITY ( _OPUS_COMPLEXITY_ ) ) ;
opus_encoder_ctl ( codec_inst - > opus_enc , OPUS_SET_INBAND_FEC ( _OPUS_INBAND_FEC_ ) ) ;
opus_encoder_ctl ( codec_inst - > opus_enc , OPUS_SET_INBAND_FEC ( useinbandfec ? 1 : 0 ) ) ;
opus_encoder_ctl ( codec_inst - > opus_enc , OPUS_SET_DTX ( _OPUS_DTX_ ) ) ;
codec_inst - > opus_dec = opus_decoder_create ( _OPUS_RATE , 1 , & error ) ;