1999-12-05 07:09:27 +00:00
/*
2005-09-14 20:46:50 +00:00
* Asterisk -- An open source telephony toolkit.
1999-12-05 07:09:27 +00:00
*
2005-09-14 20:46:50 +00:00
* Copyright (C) 1999 - 2005, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
1999-12-05 07:09:27 +00:00
*
2005-09-14 20:46:50 +00:00
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
1999-12-05 07:09:27 +00:00
*
* This program is free software, distributed under the terms of
2005-09-14 20:46:50 +00:00
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
2005-10-26 13:03:17 +00:00
/*! \file
2005-09-14 20:46:50 +00:00
*
2005-10-26 13:03:17 +00:00
* \brief Work with WAV in the proprietary Microsoft format.
2005-11-06 15:09:47 +00:00
* Microsoft WAV format (8000hz Signed Linear)
* \arg File name extension: wav (lower case)
* \ingroup formats
1999-12-05 07:09:27 +00:00
*/
2017-12-22 09:23:22 -05:00
2011-07-14 20:28:54 +00:00
/*** MODULEINFO
<support_level>core</support_level>
***/
2006-06-07 18:54:56 +00:00
#include "asterisk.h"
2007-11-22 00:53:49 +00:00
#include "asterisk/mod_format.h"
2005-06-06 22:12:19 +00:00
#include "asterisk/module.h"
#include "asterisk/endian.h"
2014-07-20 22:06:33 +00:00
#include "asterisk/format_cache.h"
#include "asterisk/format.h"
#include "asterisk/codec.h"
2005-06-06 22:12:19 +00:00
2004-01-22 21:30:04 +00:00
/* Some Ideas for this code came from makewave.c by Jeffrey Chilton */
1999-12-05 07:09:27 +00:00
2001-04-10 03:08:27 +00:00
/* Portions of the conversion code are by guido@sienanet.it */
1999-12-05 07:09:27 +00:00
2006-04-04 12:59:25 +00:00
#define WAV_BUF_SIZE 320
2012-04-16 20:17:03 +00:00
#define WAV_HEADER_SIZE 44
2006-04-04 12:59:25 +00:00
struct wav_desc { /* format-specific parameters */
2010-09-02 16:44:06 +00:00
int hz ;
2001-04-10 03:08:27 +00:00
int bytes ;
int lasttimeout ;
2003-05-16 19:23:07 +00:00
int maxlen ;
2001-04-10 03:08:27 +00:00
struct timeval last ;
1999-12-05 07:09:27 +00:00
};
2001-04-10 03:08:27 +00:00
#define BLOCKSIZE 160
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define htoll(b) (b)
#define htols(b) (b)
#define ltohl(b) (b)
#define ltohs(b) (b)
#else
#if __BYTE_ORDER == __BIG_ENDIAN
2015-03-28 12:48:45 +00:00
#define htoll(b) \
(((((b) ) & 0xFF) << 24) | \
((( (b) >> 8) & 0xFF) << 16) | \
((( (b) >> 16) & 0xFF) << 8) | \
((( (b) >> 24) & 0xFF) ))
2001-04-10 03:08:27 +00:00
#define htols(b) \
2015-03-28 12:48:45 +00:00
(((((b) ) & 0xFF) << 8) | \
((( (b) >> 8) & 0xFF) ))
2001-04-10 03:08:27 +00:00
#define ltohl(b) htoll(b)
#define ltohs(b) htols(b)
#else
#error "Endianess not defined"
#endif
#endif
2011-04-25 19:40:17 +00:00
static int check_header_fmt ( FILE * f , int hsize , int hz )
2001-04-10 03:08:27 +00:00
{
2017-04-14 14:52:59 -04:00
unsigned short format , chans , bysam , bisam ;
unsigned int freq , bysec ;
2011-04-25 19:40:17 +00:00
if ( hsize < 16 ) {
2011-11-09 15:28:33 +00:00
ast_log ( LOG_WARNING , "Unexpected header size %d \n " , hsize );
2001-04-10 03:08:27 +00:00
return - 1 ;
}
2005-10-16 16:12:51 +00:00
if ( fread ( & format , 1 , 2 , f ) != 2 ) {
2001-04-10 03:08:27 +00:00
ast_log ( LOG_WARNING , "Read failed (format) \n " );
return - 1 ;
}
if ( ltohs ( format ) != 1 ) {
2017-04-14 14:52:59 -04:00
ast_log ( LOG_WARNING , "Not a supported wav file format (%d). Only PCM encoded, 16 bit, mono, 8kHz/16kHz files are supported with a lowercase '.wav' extension. \n " , ltohs ( format ));
2001-04-10 03:08:27 +00:00
return - 1 ;
}
2005-10-16 16:12:51 +00:00
if ( fread ( & chans , 1 , 2 , f ) != 2 ) {
2001-04-10 03:08:27 +00:00
ast_log ( LOG_WARNING , "Read failed (format) \n " );
return - 1 ;
}
if ( ltohs ( chans ) != 1 ) {
ast_log ( LOG_WARNING , "Not in mono %d \n " , ltohs ( chans ));
return - 1 ;
}
2005-10-16 16:12:51 +00:00
if ( fread ( & freq , 1 , 4 , f ) != 4 ) {
2001-04-10 03:08:27 +00:00
ast_log ( LOG_WARNING , "Read failed (freq) \n " );
return - 1 ;
}
2017-04-14 14:52:59 -04:00
freq = ltohl ( freq );
if (( freq != 8000 && freq != 16000 ) || freq != hz ) {
ast_log ( LOG_WARNING , "Unexpected frequency mismatch %d (expecting %d) \n " , freq , hz );
2001-04-10 03:08:27 +00:00
return - 1 ;
}
/* Ignore the byte frequency */
2005-10-16 16:12:51 +00:00
if ( fread ( & bysec , 1 , 4 , f ) != 4 ) {
2001-04-10 03:08:27 +00:00
ast_log ( LOG_WARNING , "Read failed (BYTES_PER_SECOND) \n " );
return - 1 ;
}
/* Check bytes per sample */
2005-10-16 16:12:51 +00:00
if ( fread ( & bysam , 1 , 2 , f ) != 2 ) {
2001-04-10 03:08:27 +00:00
ast_log ( LOG_WARNING , "Read failed (BYTES_PER_SAMPLE) \n " );
return - 1 ;
}
if ( ltohs ( bysam ) != 2 ) {
ast_log ( LOG_WARNING , "Can only handle 16bits per sample: %d \n " , ltohs ( bysam ));
return - 1 ;
}
2005-10-16 16:12:51 +00:00
if ( fread ( & bisam , 1 , 2 , f ) != 2 ) {
2002-06-21 01:40:13 +00:00
ast_log ( LOG_WARNING , "Read failed (Bits Per Sample): %d \n " , ltohs ( bisam ));
2001-04-10 03:08:27 +00:00
return - 1 ;
}
2004-12-18 22:04:07 +00:00
/* Skip any additional header */
2011-11-09 15:28:33 +00:00
if ( fseek ( f , hsize - 16 , SEEK_CUR ) == - 1 ) {
ast_log ( LOG_WARNING , "Failed to skip remaining header bytes: %d \n " , hsize - 16 );
2001-04-10 03:08:27 +00:00
return - 1 ;
}
2011-04-25 19:40:17 +00:00
return 0 ;
}
static int check_header ( FILE * f , int hz )
{
int type , size , formtype ;
int data ;
if ( fread ( & type , 1 , 4 , f ) != 4 ) {
ast_log ( LOG_WARNING , "Read failed (type) \n " );
return - 1 ;
}
if ( fread ( & size , 1 , 4 , f ) != 4 ) {
ast_log ( LOG_WARNING , "Read failed (size) \n " );
return - 1 ;
}
2015-03-28 12:48:45 +00:00
#if __BYTE_ORDER == __BIG_ENDIAN
2011-04-25 19:40:17 +00:00
size = ltohl ( size );
2015-03-28 12:48:45 +00:00
#endif
2011-04-25 19:40:17 +00:00
if ( fread ( & formtype , 1 , 4 , f ) != 4 ) {
ast_log ( LOG_WARNING , "Read failed (formtype) \n " );
return - 1 ;
}
if ( memcmp ( & type , "RIFF" , 4 )) {
ast_log ( LOG_WARNING , "Does not begin with RIFF \n " );
return - 1 ;
}
if ( memcmp ( & formtype , "WAVE" , 4 )) {
ast_log ( LOG_WARNING , "Does not contain WAVE \n " );
return - 1 ;
}
2004-12-18 22:04:07 +00:00
/* Skip any facts and get the first data block */
2004-02-02 06:34:27 +00:00
for (;;)
2017-12-22 09:23:22 -05:00
{
2005-10-16 16:12:51 +00:00
char buf [ 4 ];
2017-12-22 09:23:22 -05:00
2015-03-28 12:48:45 +00:00
/* Begin data chunk */
if ( fread ( & buf , 1 , 4 , f ) != 4 ) {
2011-04-25 19:40:17 +00:00
ast_log ( LOG_WARNING , "Read failed (block header format) \n " );
2005-10-16 16:12:51 +00:00
return - 1 ;
2015-03-28 12:48:45 +00:00
}
/* Data has the actual length of data in it */
if ( fread ( & data , 1 , 4 , f ) != 4 ) {
2011-04-25 19:40:17 +00:00
ast_log ( LOG_WARNING , "Read failed (block '%.4s' header length) \n " , buf );
2005-10-16 16:12:51 +00:00
return - 1 ;
2015-03-28 12:48:45 +00:00
}
#if __BYTE_ORDER == __BIG_ENDIAN
data = ltohl ( data );
#endif
2011-04-25 19:40:17 +00:00
if ( memcmp ( & buf , "fmt " , 4 ) == 0 ) {
if ( check_header_fmt ( f , data , hz ))
return - 1 ;
continue ;
}
2017-12-22 09:23:22 -05:00
if ( memcmp ( buf , "data" , 4 ) == 0 )
2005-10-16 16:12:51 +00:00
break ;
2011-04-25 19:40:17 +00:00
ast_log ( LOG_DEBUG , "Skipping unknown block '%.4s' \n " , buf );
2015-03-28 12:48:45 +00:00
if ( fseek ( f , data , SEEK_CUR ) == - 1 ) {
2011-04-25 19:40:17 +00:00
ast_log ( LOG_WARNING , "Failed to skip '%.4s' block: %d \n " , buf , data );
2005-10-16 16:12:51 +00:00
return - 1 ;
2015-03-28 12:48:45 +00:00
}
2001-04-10 03:08:27 +00:00
}
2003-05-16 19:23:07 +00:00
#if 0
curpos = lseek(fd, 0, SEEK_CUR);
truelength = lseek(fd, 0, SEEK_END);
lseek(fd, curpos, SEEK_SET);
truelength -= curpos;
2017-12-22 09:23:22 -05:00
#endif
2004-02-02 06:34:27 +00:00
return data ;
2001-04-10 03:08:27 +00:00
}
2005-10-16 16:12:51 +00:00
static int update_header ( FILE * f )
2001-04-10 03:08:27 +00:00
{
2003-02-06 22:11:43 +00:00
off_t cur , end ;
int datalen , filelen , bytes ;
2017-12-22 09:23:22 -05:00
2006-02-20 23:35:12 +00:00
cur = ftello ( f );
2005-10-16 16:12:51 +00:00
fseek ( f , 0 , SEEK_END );
2006-02-20 23:35:12 +00:00
end = ftello ( f );
2003-02-06 22:11:43 +00:00
/* data starts 44 bytes in */
bytes = end - 44 ;
datalen = htoll ( bytes );
/* chunk size is bytes of data plus 36 bytes of header */
filelen = htoll ( 36 + bytes );
2017-12-22 09:23:22 -05:00
2001-04-10 03:08:27 +00:00
if ( cur < 0 ) {
ast_log ( LOG_WARNING , "Unable to find our position \n " );
return - 1 ;
}
2005-10-16 16:12:51 +00:00
if ( fseek ( f , 4 , SEEK_SET )) {
2001-04-10 03:08:27 +00:00
ast_log ( LOG_WARNING , "Unable to set our position \n " );
return - 1 ;
}
2005-10-16 16:12:51 +00:00
if ( fwrite ( & filelen , 1 , 4 , f ) != 4 ) {
2001-04-10 03:08:27 +00:00
ast_log ( LOG_WARNING , "Unable to set write file size \n " );
return - 1 ;
}
2005-10-16 16:12:51 +00:00
if ( fseek ( f , 40 , SEEK_SET )) {
2001-04-10 03:08:27 +00:00
ast_log ( LOG_WARNING , "Unable to set our position \n " );
return - 1 ;
}
2005-10-16 16:12:51 +00:00
if ( fwrite ( & datalen , 1 , 4 , f ) != 4 ) {
2001-04-10 03:08:27 +00:00
ast_log ( LOG_WARNING , "Unable to set write datalen \n " );
return - 1 ;
}
2006-02-20 23:35:12 +00:00
if ( fseeko ( f , cur , SEEK_SET )) {
2001-04-10 03:08:27 +00:00
ast_log ( LOG_WARNING , "Unable to return to position \n " );
return - 1 ;
}
return 0 ;
}
2010-09-02 16:44:06 +00:00
static int write_header ( FILE * f , int writehz )
2001-04-10 03:08:27 +00:00
{
2010-09-02 16:44:06 +00:00
unsigned int hz ;
unsigned int bhz ;
2001-04-10 03:08:27 +00:00
unsigned int hs = htoll ( 16 );
unsigned short fmt = htols ( 1 );
unsigned short chans = htols ( 1 );
unsigned short bysam = htols ( 2 );
unsigned short bisam = htols ( 16 );
unsigned int size = htoll ( 0 );
2010-09-02 16:44:06 +00:00
if ( writehz == 16000 ) {
hz = htoll ( 16000 );
bhz = htoll ( 32000 );
} else {
hz = htoll ( 8000 );
bhz = htoll ( 16000 );
}
2001-04-10 03:08:27 +00:00
/* Write a wav header, ignoring sizes which will be filled in later */
2005-10-16 16:12:51 +00:00
fseek ( f , 0 , SEEK_SET );
if ( fwrite ( "RIFF" , 1 , 4 , f ) != 4 ) {
2001-04-10 03:08:27 +00:00
ast_log ( LOG_WARNING , "Unable to write header \n " );
return - 1 ;
}
2005-10-16 16:12:51 +00:00
if ( fwrite ( & size , 1 , 4 , f ) != 4 ) {
2001-04-10 03:08:27 +00:00
ast_log ( LOG_WARNING , "Unable to write header \n " );
return - 1 ;
}
2005-10-16 16:12:51 +00:00
if ( fwrite ( "WAVEfmt " , 1 , 8 , f ) != 8 ) {
2001-04-10 03:08:27 +00:00
ast_log ( LOG_WARNING , "Unable to write header \n " );
return - 1 ;
}
2005-10-16 16:12:51 +00:00
if ( fwrite ( & hs , 1 , 4 , f ) != 4 ) {
2001-04-10 03:08:27 +00:00
ast_log ( LOG_WARNING , "Unable to write header \n " );
return - 1 ;
}
2005-10-16 16:12:51 +00:00
if ( fwrite ( & fmt , 1 , 2 , f ) != 2 ) {
2001-04-10 03:08:27 +00:00
ast_log ( LOG_WARNING , "Unable to write header \n " );
return - 1 ;
}
2005-10-16 16:12:51 +00:00
if ( fwrite ( & chans , 1 , 2 , f ) != 2 ) {
2001-04-10 03:08:27 +00:00
ast_log ( LOG_WARNING , "Unable to write header \n " );
return - 1 ;
}
2005-10-16 16:12:51 +00:00
if ( fwrite ( & hz , 1 , 4 , f ) != 4 ) {
2001-04-10 03:08:27 +00:00
ast_log ( LOG_WARNING , "Unable to write header \n " );
return - 1 ;
}
2005-10-16 16:12:51 +00:00
if ( fwrite ( & bhz , 1 , 4 , f ) != 4 ) {
2001-04-10 03:08:27 +00:00
ast_log ( LOG_WARNING , "Unable to write header \n " );
return - 1 ;
}
2005-10-16 16:12:51 +00:00
if ( fwrite ( & bysam , 1 , 2 , f ) != 2 ) {
2001-04-10 03:08:27 +00:00
ast_log ( LOG_WARNING , "Unable to write header \n " );
return - 1 ;
}
2005-10-16 16:12:51 +00:00
if ( fwrite ( & bisam , 1 , 2 , f ) != 2 ) {
2001-04-10 03:08:27 +00:00
ast_log ( LOG_WARNING , "Unable to write header \n " );
return - 1 ;
}
2005-10-16 16:12:51 +00:00
if ( fwrite ( "data" , 1 , 4 , f ) != 4 ) {
2001-04-10 03:08:27 +00:00
ast_log ( LOG_WARNING , "Unable to write header \n " );
return - 1 ;
}
2005-10-16 16:12:51 +00:00
if ( fwrite ( & size , 1 , 4 , f ) != 4 ) {
2001-04-10 03:08:27 +00:00
ast_log ( LOG_WARNING , "Unable to write header \n " );
return - 1 ;
}
return 0 ;
}
2006-04-04 12:59:25 +00:00
static int wav_open ( struct ast_filestream * s )
1999-12-05 07:09:27 +00:00
{
/* We don't have any header to read or anything really, but
if we did, it would go here. We also might want to check
and be sure it's a valid file. */
2017-04-14 14:52:59 -04:00
struct wav_desc * tmp = s -> _private ;
unsigned int sample_rate = ast_format_get_sample_rate ( s -> fmt -> format );
tmp -> maxlen = check_header ( s -> f , sample_rate );
if ( tmp -> maxlen < 0 ) {
2006-04-04 12:59:25 +00:00
return - 1 ;
2017-04-14 14:52:59 -04:00
}
tmp -> hz = sample_rate ;
2006-04-04 12:59:25 +00:00
return 0 ;
1999-12-05 07:09:27 +00:00
}
2006-04-04 12:59:25 +00:00
static int wav_rewrite ( struct ast_filestream * s , const char * comment )
1999-12-05 07:09:27 +00:00
{
/* We don't have any header to read or anything really, but
if we did, it would go here. We also might want to check
and be sure it's a valid file. */
2006-04-04 12:59:25 +00:00
2010-09-02 16:44:06 +00:00
struct wav_desc * tmp = ( struct wav_desc * ) s -> _private ;
2014-07-20 22:06:33 +00:00
tmp -> hz = ast_format_get_sample_rate ( s -> fmt -> format );
2010-09-02 16:44:06 +00:00
if ( write_header ( s -> f , tmp -> hz ))
2006-04-04 12:59:25 +00:00
return - 1 ;
return 0 ;
1999-12-05 07:09:27 +00:00
}
static void wav_close ( struct ast_filestream * s )
{
2001-04-10 03:08:27 +00:00
char zero = 0 ;
2007-11-29 17:50:44 +00:00
struct wav_desc * fs = ( struct wav_desc * ) s -> _private ;
2008-04-03 07:49:05 +00:00
2011-07-29 17:20:20 +00:00
if ( s -> mode == O_RDONLY ) {
2011-07-29 17:02:11 +00:00
return ;
}
2008-04-03 07:49:05 +00:00
if ( s -> filename ) {
update_header ( s -> f );
}
2001-04-10 03:08:27 +00:00
/* Pad to even length */
2008-11-02 18:52:13 +00:00
if ( fs -> bytes & 0x1 ) {
2017-04-21 13:04:44 -04:00
if ( fwrite ( & zero , 1 , 1 , s -> f ) != 1 ) {
2008-11-02 18:52:13 +00:00
ast_log ( LOG_WARNING , "fwrite() failed: %s \n " , strerror ( errno ));
}
}
1999-12-05 07:09:27 +00:00
}
2003-06-28 22:50:47 +00:00
static struct ast_frame * wav_read ( struct ast_filestream * s , int * whennext )
1999-12-05 07:09:27 +00:00
{
2017-09-05 11:05:48 -04:00
size_t res ;
2006-04-04 12:59:25 +00:00
int samples ; /* actual samples read */
2007-04-08 14:20:42 +00:00
#if __BYTE_ORDER == __BIG_ENDIAN
2002-09-04 05:09:41 +00:00
int x ;
2011-05-16 14:29:06 +00:00
short * tmp ;
2007-04-08 14:20:42 +00:00
#endif
2010-09-02 16:44:06 +00:00
int bytes ;
2003-05-16 19:23:07 +00:00
off_t here ;
1999-12-05 07:09:27 +00:00
/* Send a frame from the file to the appropriate channel */
2007-11-29 17:50:44 +00:00
struct wav_desc * fs = ( struct wav_desc * ) s -> _private ;
2006-04-04 12:59:25 +00:00
2010-09-02 16:44:06 +00:00
bytes = ( fs -> hz == 16000 ? ( WAV_BUF_SIZE * 2 ) : WAV_BUF_SIZE );
2006-02-20 23:35:12 +00:00
here = ftello ( s -> f );
2006-04-04 12:59:25 +00:00
if ( fs -> maxlen - here < bytes ) /* truncate if necessary */
bytes = fs -> maxlen - here ;
2017-04-21 13:04:44 -04:00
if ( bytes <= 0 ) {
return NULL ;
}
2007-06-14 19:39:12 +00:00
/* ast_debug(1, "here: %d, maxlen: %d, bytes: %d\n", here, s->maxlen, bytes); */
2006-04-09 22:31:38 +00:00
AST_FRAME_SET_BUFFER ( & s -> fr , s -> buf , AST_FRIENDLY_OFFSET , bytes );
2017-04-21 13:04:44 -04:00
2017-09-05 11:05:48 -04:00
if (( res = fread ( s -> fr . data . ptr , 1 , s -> fr . datalen , s -> f )) == 0 ) {
if ( res ) {
ast_log ( LOG_WARNING , "Short read of %s data (expected %d bytes, read %zu): %s \n " ,
ast_format_get_name ( s -> fr . subclass . format ), s -> fr . datalen , res ,
strerror ( errno ));
2017-04-21 13:04:44 -04:00
}
2003-06-28 22:50:47 +00:00
return NULL ;
1999-12-05 07:09:27 +00:00
}
2006-04-04 12:59:25 +00:00
s -> fr . datalen = res ;
s -> fr . samples = samples = res / 2 ;
2003-02-06 22:11:43 +00:00
#if __BYTE_ORDER == __BIG_ENDIAN
2011-05-03 20:45:32 +00:00
tmp = ( short * )( s -> fr . data . ptr );
2006-04-04 12:59:25 +00:00
/* file format is little endian so we need to swap */
2008-10-09 21:47:02 +00:00
for ( x = 0 ; x < samples ; x ++ )
2006-04-04 12:59:25 +00:00
tmp [ x ] = ( tmp [ x ] << 8 ) | (( tmp [ x ] & 0xff00 ) >> 8 );
2003-02-06 22:11:43 +00:00
#endif
2006-04-04 12:59:25 +00:00
* whennext = samples ;
2003-06-28 22:50:47 +00:00
return & s -> fr ;
1999-12-05 07:09:27 +00:00
}
static int wav_write ( struct ast_filestream * fs , struct ast_frame * f )
{
2007-04-06 22:29:53 +00:00
#if __BYTE_ORDER == __BIG_ENDIAN
2007-04-08 14:20:42 +00:00
int x ;
2010-09-02 16:44:06 +00:00
short tmp [ 16000 ], * tmpi ;
2007-04-06 22:29:53 +00:00
#endif
2007-11-29 17:50:44 +00:00
struct wav_desc * s = ( struct wav_desc * ) fs -> _private ;
2006-04-04 12:59:25 +00:00
int res ;
2007-04-06 22:29:53 +00:00
if ( ! f -> datalen )
return - 1 ;
#if __BYTE_ORDER == __BIG_ENDIAN
/* swap and write */
2002-09-04 05:09:41 +00:00
if ( f -> datalen > sizeof ( tmp )) {
ast_log ( LOG_WARNING , "Data length is too long \n " );
return - 1 ;
}
2008-05-22 16:29:54 +00:00
tmpi = f -> data . ptr ;
2017-12-22 09:23:22 -05:00
for ( x = 0 ; x < f -> datalen / 2 ; x ++ )
2007-04-06 22:29:53 +00:00
tmp [ x ] = ( tmpi [ x ] << 8 ) | (( tmpi [ x ] & 0xff00 ) >> 8 );
2003-02-06 22:11:43 +00:00
2006-04-04 12:59:25 +00:00
if (( res = fwrite ( tmp , 1 , f -> datalen , fs -> f )) != f -> datalen ) {
2007-04-06 22:29:53 +00:00
#else
/* just write */
2008-05-22 16:29:54 +00:00
if (( res = fwrite ( f -> data . ptr , 1 , f -> datalen , fs -> f )) != f -> datalen ) {
2007-04-06 22:29:53 +00:00
#endif
2006-04-04 12:59:25 +00:00
ast_log ( LOG_WARNING , "Bad write (%d): %s \n " , res , strerror ( errno ));
1999-12-05 07:09:27 +00:00
return - 1 ;
2001-04-10 03:08:27 +00:00
}
2006-04-04 12:59:25 +00:00
s -> bytes += f -> datalen ;
2017-12-22 09:23:22 -05:00
1999-12-05 07:09:27 +00:00
return 0 ;
2001-04-10 03:08:27 +00:00
1999-12-05 07:09:27 +00:00
}
2006-02-20 23:35:12 +00:00
static int wav_seek ( struct ast_filestream * fs , off_t sample_offset , int whence )
2003-02-06 22:11:43 +00:00
{
2012-04-16 20:17:03 +00:00
off_t min = WAV_HEADER_SIZE , max , cur , offset = 0 , samples ;
2006-02-20 23:35:12 +00:00
2003-02-06 22:11:43 +00:00
samples = sample_offset * 2 ; /* SLINEAR is 16 bits mono, so sample_offset * 2 = bytes */
2012-04-16 20:17:03 +00:00
if (( cur = ftello ( fs -> f )) < 0 ) {
ast_log ( AST_LOG_WARNING , "Unable to determine current position in wav filestream %p: %s \n " , fs , strerror ( errno ));
return - 1 ;
}
if ( fseeko ( fs -> f , 0 , SEEK_END ) < 0 ) {
ast_log ( AST_LOG_WARNING , "Unable to seek to end of wav filestream %p: %s \n " , fs , strerror ( errno ));
return - 1 ;
}
2012-04-17 18:29:51 +00:00
if (( max = ftello ( fs -> f )) < 0 ) {
2012-04-16 20:17:03 +00:00
ast_log ( AST_LOG_WARNING , "Unable to determine max position in wav filestream %p: %s \n " , fs , strerror ( errno ));
return - 1 ;
}
2015-03-28 12:48:45 +00:00
if ( whence == SEEK_SET ) {
2003-02-06 22:11:43 +00:00
offset = samples + min ;
2015-03-28 12:48:45 +00:00
} else if ( whence == SEEK_CUR || whence == SEEK_FORCECUR ) {
2003-02-06 22:11:43 +00:00
offset = samples + cur ;
2015-03-28 12:48:45 +00:00
} else if ( whence == SEEK_END ) {
2003-08-28 20:02:10 +00:00
offset = max - samples ;
2015-03-28 12:48:45 +00:00
}
if ( whence != SEEK_FORCECUR ) {
2003-08-28 20:02:10 +00:00
offset = ( offset > max ) ? max : offset ;
}
2004-12-18 22:04:07 +00:00
/* always protect the header space. */
2004-04-15 16:02:42 +00:00
offset = ( offset < min ) ? min : offset ;
2006-02-20 23:35:12 +00:00
return fseeko ( fs -> f , offset , SEEK_SET );
2003-02-06 22:11:43 +00:00
}
static int wav_trunc ( struct ast_filestream * fs )
{
2012-04-16 20:17:03 +00:00
int fd ;
off_t cur ;
if (( fd = fileno ( fs -> f )) < 0 ) {
ast_log ( AST_LOG_WARNING , "Unable to determine file descriptor for wav filestream %p: %s \n " , fs , strerror ( errno ));
return - 1 ;
}
2012-04-29 19:50:57 +00:00
if (( cur = ftello ( fs -> f )) < 0 ) {
2012-04-16 20:17:03 +00:00
ast_log ( AST_LOG_WARNING , "Unable to determine current position in wav filestream %p: %s \n " , fs , strerror ( errno ));
return - 1 ;
}
/* Truncate file to current length */
if ( ftruncate ( fd , cur )) {
2003-02-06 22:11:43 +00:00
return - 1 ;
2012-04-16 20:17:03 +00:00
}
2005-10-16 16:12:51 +00:00
return update_header ( fs -> f );
2003-02-06 22:11:43 +00:00
}
2006-02-20 23:35:12 +00:00
static off_t wav_tell ( struct ast_filestream * fs )
2003-02-06 22:11:43 +00:00
{
off_t offset ;
2006-02-20 23:35:12 +00:00
offset = ftello ( fs -> f );
2003-02-06 22:11:43 +00:00
/* subtract header size to get samples, then divide by 2 for 16 bit samples */
return ( offset - 44 ) / 2 ;
}
2011-02-03 16:22:10 +00:00
static struct ast_format_def wav16_f = {
2010-09-02 16:44:06 +00:00
. name = "wav16" ,
. exts = "wav16" ,
. open = wav_open ,
. rewrite = wav_rewrite ,
. write = wav_write ,
. seek = wav_seek ,
. trunc = wav_trunc ,
. tell = wav_tell ,
. read = wav_read ,
. close = wav_close ,
. buf_size = ( WAV_BUF_SIZE * 2 ) + AST_FRIENDLY_OFFSET ,
. desc_size = sizeof ( struct wav_desc ),
};
2011-02-03 16:22:10 +00:00
static struct ast_format_def wav_f = {
2006-04-04 12:59:25 +00:00
. name = "wav" ,
. exts = "wav" ,
2018-02-13 10:55:47 -08:00
. mime_types = "audio/wav|audio/x-wav" ,
2006-04-04 12:59:25 +00:00
. open = wav_open ,
. rewrite = wav_rewrite ,
. write = wav_write ,
. seek = wav_seek ,
. trunc = wav_trunc ,
. tell = wav_tell ,
. read = wav_read ,
. close = wav_close ,
. buf_size = WAV_BUF_SIZE + AST_FRIENDLY_OFFSET ,
. desc_size = sizeof ( struct wav_desc ),
};
1999-12-05 07:09:27 +00:00
2017-04-11 10:07:39 -06:00
static int unload_module ( void )
{
return ast_format_def_unregister ( wav_f . name )
|| ast_format_def_unregister ( wav16_f . name );
}
2006-08-21 02:11:39 +00:00
static int load_module ( void )
1999-12-05 07:09:27 +00:00
{
2014-07-20 22:06:33 +00:00
wav_f . format = ast_format_slin ;
wav16_f . format = ast_format_slin16 ;
2011-02-03 16:22:10 +00:00
if ( ast_format_def_register ( & wav_f )
2017-04-11 10:07:39 -06:00
|| ast_format_def_register ( & wav16_f )) {
unload_module ();
return AST_MODULE_LOAD_DECLINE ;
}
2007-10-31 19:24:29 +00:00
return AST_MODULE_LOAD_SUCCESS ;
1999-12-05 07:09:27 +00:00
}
2010-09-02 16:44:06 +00:00
AST_MODULE_INFO ( ASTERISK_GPL_KEY , AST_MODFLAG_LOAD_ORDER , "Microsoft WAV/WAV16 format (8kHz/16kHz Signed Linear)" ,
2014-07-25 16:47:17 +00:00
. support_level = AST_MODULE_SUPPORT_CORE ,
2010-07-26 03:28:02 +00:00
. load = load_module ,
. unload = unload_module ,
. load_pri = AST_MODPRI_APP_DEPEND
);