2017-07-10 16:29:31 -04:00
/*
* FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
* Copyright ( C ) 2005 - 2014 , Anthony Minessale II < anthm @ freeswitch . org >
*
* 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 ) :
*
* Dragos Oancea < dragos . oancea @ nexmo . com > ( mod_opusfile . c )
*
*
* mod_opusfile . c - - Read and Write OGG / Opus files . Some parts inspired from mod_shout . c , libopusfile , libopusenc
*
*/
# include <switch.h>
# include <opusfile.h>
# ifdef HAVE_OPUSFILE_ENCODE
# include <opus/opusenc.h>
# endif
2018-04-13 04:52:59 -04:00
# define OPUSFILE_MAX 32*1024
# define TC_BUFFER_SIZE 1024 * 256 /* max ammount of decoded audio we can have at a time (bytes)*/
# define DEFAULT_RATE 48000 /* default fullband */
# define OPUS_MAX_PCM 5760 /* opus recommended max output buf */
2017-07-10 16:29:31 -04:00
2018-04-13 04:52:59 -04:00
//#undef HAVE_OPUSFILE_ENCODE /*don't encode anything */
2017-07-10 16:29:31 -04:00
SWITCH_MODULE_LOAD_FUNCTION ( mod_opusfile_load ) ;
SWITCH_MODULE_DEFINITION ( mod_opusfile , mod_opusfile_load , NULL , NULL ) ;
struct opus_file_context {
switch_file_t * fd ;
OggOpusFile * of ;
ogg_int64_t duration ;
int output_seekable ;
ogg_int64_t pcm_offset ;
ogg_int64_t pcm_print_offset ;
ogg_int64_t next_pcm_offset ;
ogg_int64_t nsamples ;
opus_int32 bitrate ;
int li ;
int prev_li ;
switch_mutex_t * audio_mutex ;
switch_buffer_t * audio_buffer ;
2018-04-13 04:52:59 -04:00
switch_mutex_t * ogg_mutex ;
switch_buffer_t * ogg_buffer ;
opus_int16 decode_buf [ OPUS_MAX_PCM ] ;
switch_bool_t eof ;
2017-07-10 16:29:31 -04:00
switch_thread_rwlock_t * rwlock ;
switch_file_handle_t * handle ;
size_t samplerate ;
2018-04-13 04:52:59 -04:00
int frame_size ;
2017-07-10 16:29:31 -04:00
int channels ;
size_t buffer_seconds ;
2018-04-13 04:52:59 -04:00
size_t err ;
2017-07-10 16:29:31 -04:00
opus_int16 * opusbuf ;
switch_size_t opusbuflen ;
FILE * fp ;
# ifdef HAVE_OPUSFILE_ENCODE
OggOpusEnc * enc ;
OggOpusComments * comments ;
2018-04-13 04:52:59 -04:00
unsigned char encode_buf [ OPUSFILE_MAX ] ;
int encoded_buflen ;
size_t samples_encode ;
2017-07-10 16:29:31 -04:00
# endif
switch_memory_pool_t * pool ;
} ;
typedef struct opus_file_context opus_file_context ;
static struct {
int debug ;
} globals ;
2018-04-13 04:52:59 -04:00
static switch_status_t switch_opusfile_decode ( opus_file_context * context , void * data , size_t max_bytes , int channels )
2017-07-10 16:29:31 -04:00
{
2018-04-13 04:52:59 -04:00
int ret = 0 ;
size_t buf_inuse ;
2017-07-10 16:29:31 -04:00
2018-04-13 04:52:59 -04:00
if ( ! context - > of ) {
return SWITCH_STATUS_FALSE ;
}
memset ( context - > decode_buf , 0 , sizeof ( context - > decode_buf ) ) ;
switch_mutex_lock ( context - > audio_mutex ) ;
while ( ! ( context - > eof ) & & ( buf_inuse = switch_buffer_inuse ( context - > audio_buffer ) ) < = max_bytes ) {
2017-07-10 16:29:31 -04:00
if ( channels = = 1 ) {
2018-04-13 04:52:59 -04:00
ret = op_read ( context - > of , ( opus_int16 * ) context - > decode_buf , OPUS_MAX_PCM , NULL ) ;
} else if ( channels = = 2 ) {
ret = op_read_stereo ( context - > of , ( opus_int16 * ) context - > decode_buf , OPUS_MAX_PCM ) ;
} else if ( channels > 2 ) {
ret = op_read ( context - > of , ( opus_int16 * ) context - > decode_buf , OPUS_MAX_PCM , NULL ) ;
} else if ( ( channels > 255 ) | | ( channels < 1 ) ) {
2017-07-10 16:29:31 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " [OGG/OPUS File] Invalid number of channels " ) ;
2018-04-13 04:52:59 -04:00
switch_mutex_unlock ( context - > audio_mutex ) ;
2017-07-10 16:29:31 -04:00
return SWITCH_STATUS_FALSE ;
}
if ( ret < 0 ) {
switch ( ret ) {
case OP_HOLE : /* There was a hole in the data, and some samples may have been skipped. Call this function again to continue decoding past the hole.*/
case OP_EREAD : /*An underlying read operation failed. This may signal a truncation attack from an <https:> source.*/
case OP_EFAULT : /* An internal memory allocation failed. */
case OP_EIMPL : /*An unseekable stream encountered a new link that used a feature that is not implemented, such as an unsupported channel family.*/
case OP_EINVAL : /* The stream was only partially open. */
case OP_ENOTFORMAT : /* An unseekable stream encountered a new link that did not have any logical Opus streams in it. */
case OP_EBADHEADER : /*An unseekable stream encountered a new link with a required header packet that was not properly formatted, contained illegal values, or was missing altogether.*/
case OP_EVERSION : /*An unseekable stream encountered a new link with an ID header that contained an unrecognized version number.*/
case OP_EBADPACKET : /*Failed to properly decode the next packet.*/
case OP_EBADLINK : /*We failed to find data we had seen before.*/
case OP_EBADTIMESTAMP : /*An unseekable stream encountered a new link with a starting timestamp that failed basic validity checks.*/
default :
2018-04-13 04:52:59 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " [OGG/OPUS Decoder]: error decoding file: [%d] \n " , ret ) ;
switch_mutex_unlock ( context - > audio_mutex ) ;
return SWITCH_STATUS_FALSE ;
2017-07-10 16:29:31 -04:00
}
} else if ( ret = = 0 ) {
/*The number of samples returned may be 0 if the buffer was too small to store even a single sample for both channels, or if end-of-file was reached*/
if ( globals . debug ) {
2018-04-13 04:52:59 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " [OGG/OPUS Decoder]: EOF reached [%d] \n " , ret ) ;
2017-07-10 16:29:31 -04:00
}
2020-01-25 16:42:07 +00:00
context - > eof = SWITCH_TRUE ;
2017-07-10 16:29:31 -04:00
break ;
} else /* (ret > 0)*/ {
/*The number of samples read per channel on success*/
2018-04-13 04:52:59 -04:00
switch_buffer_write ( context - > audio_buffer , ( opus_int16 * ) context - > decode_buf , ret * sizeof ( opus_int16 ) * channels ) ;
2017-07-10 16:29:31 -04:00
if ( globals . debug ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG ,
2018-04-13 04:52:59 -04:00
" [OGG/OPUS Decoder]: Read samples: %d. Wrote bytes to buffer: [%d] bytes in use: [%u] \n " , ret , ( int ) ( ret * sizeof ( int16_t ) * channels ) , ( unsigned int ) buf_inuse ) ;
2017-07-10 16:29:31 -04:00
}
}
}
2018-04-13 04:52:59 -04:00
switch_mutex_unlock ( context - > audio_mutex ) ;
2017-07-10 16:29:31 -04:00
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t switch_opusfile_open ( switch_file_handle_t * handle , const char * path )
{
opus_file_context * context ;
char * ext ;
unsigned int flags = 0 ;
int ret ;
if ( ( ext = strrchr ( path , ' . ' ) ) = = 0 ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " [OGG/OPUS File] Invalid Format \n " ) ;
return SWITCH_STATUS_GENERR ;
}
ext + + ;
if ( ( context = switch_core_alloc ( handle - > memory_pool , sizeof ( * context ) ) ) = = 0 ) {
return SWITCH_STATUS_MEMERR ;
}
context - > pool = handle - > memory_pool ;
switch_thread_rwlock_create ( & ( context - > rwlock ) , context - > pool ) ;
switch_thread_rwlock_rdlock ( context - > rwlock ) ;
switch_mutex_init ( & context - > audio_mutex , SWITCH_MUTEX_NESTED , context - > pool ) ;
if ( switch_test_flag ( handle , SWITCH_FILE_FLAG_WRITE ) ) {
flags | = SWITCH_FOPEN_WRITE | SWITCH_FOPEN_CREATE ;
if ( switch_test_flag ( handle , SWITCH_FILE_WRITE_APPEND ) | | switch_test_flag ( handle , SWITCH_FILE_WRITE_OVER ) ) {
flags | = SWITCH_FOPEN_READ ;
} else {
flags | = SWITCH_FOPEN_TRUNCATE ;
}
}
if ( switch_test_flag ( handle , SWITCH_FILE_FLAG_READ ) ) {
if ( switch_buffer_create_dynamic ( & context - > audio_buffer , TC_BUFFER_SIZE , TC_BUFFER_SIZE * 2 , 0 ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Memory Error! \n " ) ;
2018-04-13 04:52:59 -04:00
goto err ;
2017-07-10 16:29:31 -04:00
}
flags | = SWITCH_FOPEN_READ ;
}
handle - > samples = 0 ;
2018-04-13 04:52:59 -04:00
handle - > samplerate = context - > samplerate = DEFAULT_RATE ; /*open files at 48 khz always*/
2017-07-10 16:29:31 -04:00
handle - > format = 0 ;
handle - > sections = 0 ;
handle - > seekable = 1 ;
handle - > speed = 0 ;
handle - > pos = 0 ;
handle - > private_info = context ;
context - > handle = handle ;
memcpy ( handle - > file_path , path , strlen ( path ) ) ;
# ifdef HAVE_OPUSFILE_ENCODE
if ( switch_test_flag ( handle , SWITCH_FILE_FLAG_WRITE ) ) {
2018-04-13 04:52:59 -04:00
int err ; int mapping_family = 0 ;
2017-07-10 16:29:31 -04:00
context - > channels = handle - > channels ;
context - > samplerate = handle - > samplerate ;
handle - > seekable = 0 ;
context - > comments = ope_comments_create ( ) ;
ope_comments_add ( context - > comments , " METADATA " , " Freeswitch/mod_opusfile " ) ;
2018-04-13 04:52:59 -04:00
// opus_multistream_surround_encoder_get_size() in libopus will check these
if ( ( context - > channels > 2 ) & & ( context - > channels < = 8 ) ) {
mapping_family = 1 ;
} else if ( ( context - > channels > 8 ) & & ( context - > channels < = 255 ) ) {
mapping_family = 255 ;
}
context - > enc = ope_encoder_create_file ( handle - > file_path , context - > comments , context - > samplerate , context - > channels , mapping_family , & err ) ;
2017-07-10 16:29:31 -04:00
if ( ! context - > enc ) {
2018-04-13 04:52:59 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Can't open file for writing [%d] [%s] \n " , err , ope_strerror ( err ) ) ;
switch_thread_rwlock_unlock ( context - > rwlock ) ;
return SWITCH_STATUS_FALSE ;
2017-07-10 16:29:31 -04:00
}
2018-04-13 04:52:59 -04:00
switch_thread_rwlock_unlock ( context - > rwlock ) ;
return SWITCH_STATUS_SUCCESS ;
2017-07-10 16:29:31 -04:00
}
# endif
context - > of = op_open_file ( path , & ret ) ;
if ( ! context - > of ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " [OGG/OPUS File] Error opening %s \n " , path ) ;
2018-04-13 04:52:59 -04:00
return SWITCH_STATUS_GENERR ;
2017-07-10 16:29:31 -04:00
}
if ( switch_test_flag ( handle , SWITCH_FILE_WRITE_APPEND ) ) {
op_pcm_seek ( context - > of , 0 ) ; // overwrite
handle - > pos = 0 ;
}
context - > prev_li = - 1 ;
context - > nsamples = 0 ;
handle - > channels = context - > channels = op_channel_count ( context - > of , - 1 ) ;
context - > pcm_offset = op_pcm_tell ( context - > of ) ;
if ( context - > pcm_offset ! = 0 ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " [OGG/OPUS File] Non-zero starting PCM offset: [%li] \n " , ( long ) context - > pcm_offset ) ;
}
2020-01-25 16:42:07 +00:00
context - > eof = SWITCH_FALSE ;
2018-04-13 04:52:59 -04:00
context - > pcm_print_offset = context - > pcm_offset - DEFAULT_RATE ;
2017-07-10 16:29:31 -04:00
context - > bitrate = 0 ;
context - > buffer_seconds = 1 ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " [OGG/OPUS File] Opening File [%s] %dhz \n " , path , handle - > samplerate ) ;
context - > li = op_current_link ( context - > of ) ;
if ( context - > li ! = context - > prev_li ) {
const OpusHead * head ;
const OpusTags * tags ;
head = op_head ( context - > of , context - > li ) ;
if ( head ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " [OGG/OPUS File] Channels: %i \n " , head - > channel_count ) ;
if ( head - > input_sample_rate ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " [OGG/OPUS File] Original sampling rate: %lu Hz \n " , ( unsigned long ) head - > input_sample_rate ) ;
}
}
if ( op_seekable ( context - > of ) ) {
ogg_int64_t duration ;
opus_int64 size ;
duration = op_pcm_total ( context - > of , context - > li ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " [OGG/OPUS File] Duration (samples): %u " , ( unsigned int ) duration ) ;
size = op_raw_total ( context - > of , context - > li ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " [OGG/OPUS File] Size (bytes): %u " , ( unsigned int ) size ) ;
}
tags = op_tags ( context - > of , context - > li ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " [OGG/OPUS File] Encoded by: %s \n " , tags - > vendor ) ;
}
switch_thread_rwlock_unlock ( context - > rwlock ) ;
2018-04-13 04:52:59 -04:00
return SWITCH_STATUS_SUCCESS ;
2017-07-10 16:29:31 -04:00
2018-04-13 04:52:59 -04:00
err :
switch_thread_rwlock_unlock ( context - > rwlock ) ;
return SWITCH_STATUS_FALSE ;
2017-07-10 16:29:31 -04:00
}
static switch_status_t switch_opusfile_close ( switch_file_handle_t * handle )
{
opus_file_context * context = handle - > private_info ;
2018-04-13 04:52:59 -04:00
switch_thread_rwlock_rdlock ( context - > rwlock ) ;
2017-07-10 16:29:31 -04:00
if ( context - > of ) {
op_free ( context - > of ) ;
}
# ifdef HAVE_OPUSFILE_ENCODE
if ( context - > enc ) {
ope_encoder_destroy ( context - > enc ) ;
}
if ( context - > comments ) {
ope_comments_destroy ( context - > comments ) ;
}
2018-04-13 04:52:59 -04:00
# endif
2017-07-10 16:29:31 -04:00
if ( context - > audio_buffer ) {
switch_buffer_destroy ( & context - > audio_buffer ) ;
}
2018-04-13 04:52:59 -04:00
switch_thread_rwlock_unlock ( context - > rwlock ) ;
2017-07-10 16:29:31 -04:00
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t switch_opusfile_seek ( switch_file_handle_t * handle , unsigned int * cur_sample , int64_t samples , int whence )
{
int ret ;
opus_file_context * context = handle - > private_info ;
if ( handle - > handler | | switch_test_flag ( handle , SWITCH_FILE_FLAG_WRITE ) ) {
return SWITCH_STATUS_FALSE ;
} else {
if ( whence = = SWITCH_SEEK_CUR ) {
samples - = switch_buffer_inuse ( context - > audio_buffer ) / sizeof ( int16_t ) ;
}
switch_buffer_zero ( context - > audio_buffer ) ;
ret = op_pcm_seek ( context - > of , samples ) ;
if ( globals . debug ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " [OGG/OPUS File] seek samples: [%u] " , ( unsigned int ) samples ) ;
}
if ( ret = = 0 ) {
handle - > pos = * cur_sample = samples ;
return SWITCH_STATUS_SUCCESS ;
}
}
return SWITCH_STATUS_FALSE ;
}
static switch_status_t switch_opusfile_read ( switch_file_handle_t * handle , void * data , size_t * len )
{
opus_file_context * context = handle - > private_info ;
size_t bytes = * len * sizeof ( int16_t ) * handle - > real_channels ;
size_t rb = 0 , newbytes ;
if ( ! context ) {
return SWITCH_STATUS_FALSE ;
}
if ( ! handle - > handler ) {
2018-04-13 04:52:59 -04:00
if ( switch_opusfile_decode ( context , data , bytes , handle - > real_channels ) = = SWITCH_STATUS_FALSE ) {
2020-01-25 16:42:07 +00:00
context - > eof = SWITCH_TRUE ;
2017-07-10 16:29:31 -04:00
}
}
switch_mutex_lock ( context - > audio_mutex ) ;
rb = switch_buffer_read ( context - > audio_buffer , data , bytes ) ;
switch_mutex_unlock ( context - > audio_mutex ) ;
2020-01-25 16:42:07 +00:00
if ( globals . debug ) {
2020-02-07 12:34:37 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " [OGG/OPUS File] rb: [% " SWITCH_SIZE_T_FMT " ] bytes: [% " SWITCH_SIZE_T_FMT " ] \n " , rb , bytes ) ;
2020-01-25 16:42:07 +00:00
}
2020-01-06 22:47:49 +04:00
if ( ! rb & & ( context - > eof ) ) {
2020-01-25 16:42:07 +00:00
if ( globals . debug ) {
// should be same as returned by op_pcm_total()
2020-02-07 12:34:37 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " [OGG/OPUS File] EOF. sample count: [% " SWITCH_SIZE_T_FMT " ] \n " , handle - > sample_count ) ;
2020-01-25 16:42:07 +00:00
}
* len = 0 ;
2017-07-10 16:29:31 -04:00
return SWITCH_STATUS_FALSE ;
}
if ( rb ) {
* len = rb / sizeof ( int16_t ) / handle - > real_channels ;
if ( globals . debug ) {
2020-02-07 12:34:37 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " [OGG/OPUS File] rb: [% " SWITCH_SIZE_T_FMT " ] *len: [% " SWITCH_SIZE_T_FMT " ] \n " , rb , * len ) ;
2017-07-10 16:29:31 -04:00
}
} else {
newbytes = ( 2 * handle - > samplerate * handle - > real_channels ) * context - > buffer_seconds ;
if ( newbytes < bytes ) {
bytes = newbytes ;
}
if ( globals . debug ) {
2018-04-13 04:52:59 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG ,
" [OGG/OPUS File] Padding with empty audio. seconds: [%d] bytes: [%d] newbytes: [%d] real_channels: [%d] \n " ,
( int ) context - > buffer_seconds , ( int ) bytes , ( int ) newbytes , ( int ) handle - > real_channels ) ;
2017-07-10 16:29:31 -04:00
}
memset ( data , 255 , bytes ) ;
* len = bytes / sizeof ( int16_t ) / handle - > real_channels ;
}
handle - > pos + = * len ;
handle - > sample_count + = * len ;
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t switch_opusfile_write ( switch_file_handle_t * handle , void * data , size_t * len )
{
# ifdef HAVE_OPUSFILE_ENCODE
size_t nsamples = * len ;
2018-04-13 04:52:59 -04:00
int err ;
int mapping_family = 0 ;
2017-07-10 16:29:31 -04:00
opus_file_context * context = handle - > private_info ;
if ( ! handle ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Error no handle \n " ) ;
return SWITCH_STATUS_FALSE ;
}
if ( ! ( context = handle - > private_info ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Error no context \n " ) ;
return SWITCH_STATUS_FALSE ;
}
2018-04-13 04:52:59 -04:00
if ( ! context - > comments ) {
context - > comments = ope_comments_create ( ) ;
ope_comments_add ( context - > comments , " METADATA " , " Freeswitch/mod_opusfile " ) ;
}
if ( context - > channels > 2 ) {
mapping_family = 1 ;
}
2017-07-10 16:29:31 -04:00
if ( ! context - > enc ) {
2018-04-13 04:52:59 -04:00
context - > enc = ope_encoder_create_file ( handle - > file_path , context - > comments , handle - > samplerate , handle - > channels , mapping_family , & err ) ;
2017-07-10 16:29:31 -04:00
if ( ! context - > enc ) {
2018-04-13 04:52:59 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Can't open file for writing. err: [%d] [%s] \n " , err , ope_strerror ( err ) ) ;
2017-07-10 16:29:31 -04:00
return SWITCH_STATUS_FALSE ;
}
}
if ( globals . debug ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " [OGG/OPUS File] write nsamples: [%d] " , ( int ) nsamples ) ;
}
2018-04-13 04:52:59 -04:00
err = ope_encoder_write ( context - > enc , ( opus_int16 * ) data , nsamples ) ;
if ( err ! = OPE_OK ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " [OGG/OPUS File] Can't encode. err: [%d] [%s] " , err , ope_strerror ( err ) ) ;
2017-07-10 16:29:31 -04:00
return SWITCH_STATUS_FALSE ;
}
handle - > sample_count + = * len ;
# endif
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t switch_opusfile_set_string ( switch_file_handle_t * handle , switch_audio_col_t col , const char * string )
{
return SWITCH_STATUS_FALSE ;
}
static switch_status_t switch_opusfile_get_string ( switch_file_handle_t * handle , switch_audio_col_t col , const char * * string )
{
return SWITCH_STATUS_FALSE ;
}
2018-04-13 04:52:59 -04:00
2017-07-10 16:29:31 -04:00
# define OPUSFILE_DEBUG_SYNTAX "<on|off>"
SWITCH_STANDARD_API ( mod_opusfile_debug )
{
if ( zstr ( cmd ) ) {
stream - > write_function ( stream , " -USAGE: %s \n " , OPUSFILE_DEBUG_SYNTAX ) ;
} else {
if ( ! strcasecmp ( cmd , " on " ) ) {
globals . debug = 1 ;
stream - > write_function ( stream , " OPUSFILE Debug: on \n " ) ;
2018-04-13 04:52:59 -04:00
# ifdef HAVE_OPUSFILE_ENCODE
stream - > write_function ( stream , " Library version (encoding): %s \n " , ope_get_version_string ( ) ) ;
# endif
2017-07-10 16:29:31 -04:00
} else if ( ! strcasecmp ( cmd , " off " ) ) {
globals . debug = 0 ;
stream - > write_function ( stream , " OPUSFILE Debug: off \n " ) ;
} else {
stream - > write_function ( stream , " -USAGE: %s \n " , OPUSFILE_DEBUG_SYNTAX ) ;
}
}
return SWITCH_STATUS_SUCCESS ;
}
/* Registration */
static char * supported_formats [ SWITCH_MAX_CODECS ] = { 0 } ;
SWITCH_MODULE_LOAD_FUNCTION ( mod_opusfile_load )
{
switch_file_interface_t * file_interface ;
switch_api_interface_t * commands_api_interface ;
supported_formats [ 0 ] = " opus " ;
* module_interface = switch_loadable_module_create_module_interface ( pool , modname ) ;
SWITCH_ADD_API ( commands_api_interface , " opusfile_debug " , " Set OPUSFILE Debug " , mod_opusfile_debug , OPUSFILE_DEBUG_SYNTAX ) ;
switch_console_set_complete ( " add opusfile_debug on " ) ;
switch_console_set_complete ( " add opusfile_debug off " ) ;
2018-04-13 04:52:59 -04:00
globals . debug = 0 ;
2017-07-10 16:29:31 -04:00
file_interface = switch_loadable_module_create_interface ( * module_interface , SWITCH_FILE_INTERFACE ) ;
file_interface - > interface_name = modname ;
file_interface - > extens = supported_formats ;
file_interface - > file_open = switch_opusfile_open ;
file_interface - > file_close = switch_opusfile_close ;
file_interface - > file_read = switch_opusfile_read ;
file_interface - > file_write = switch_opusfile_write ;
file_interface - > file_seek = switch_opusfile_seek ;
file_interface - > file_set_string = switch_opusfile_set_string ;
file_interface - > file_get_string = switch_opusfile_get_string ;
2018-04-13 04:52:59 -04:00
2017-07-10 16:29:31 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " mod_opusfile loaded \n " ) ;
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS ;
}
/* For Emacs:
* Local Variables :
* mode : c
* indent - tabs - mode : t
* tab - width : 4
* c - basic - offset : 4
* End :
* For VIM :
* vim : set softtabstop = 4 shiftwidth = 4 tabstop = 4 noet :
*/
2018-04-13 04:52:59 -04:00