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 ( 8000 hz Signed Linear )
* \ arg File name extension : wav ( lower case )
* \ ingroup formats
1999-12-05 07:09:27 +00: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"
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
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"
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
# define htoll(b) \
( ( ( ( ( b ) ) & 0xFF ) < < 24 ) | \
( ( ( ( b ) > > 8 ) & 0xFF ) < < 16 ) | \
( ( ( ( b ) > > 16 ) & 0xFF ) < < 8 ) | \
( ( ( ( b ) > > 24 ) & 0xFF ) ) )
# define htols(b) \
( ( ( ( ( b ) ) & 0xFF ) < < 8 ) | \
( ( ( ( b ) > > 8 ) & 0xFF ) ) )
# 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
{
short format , chans , bysam , bisam ;
int bysec ;
int freq ;
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 ) {
2014-02-05 23:03:01 +00:00
ast_log ( LOG_WARNING , " Not a supported wav file format (%d). Only PCM encoded, 16 bit, mono, 8kHz 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 ;
}
2010-09-02 16:44:06 +00:00
if ( ( ( ltohl ( freq ) ! = 8000 ) & & ( ltohl ( freq ) ! = 16000 ) ) | |
( ( ltohl ( freq ) = = 8000 ) & & ( hz ! = 8000 ) ) | |
( ( ltohl ( freq ) = = 16000 ) & & ( hz ! = 16000 ) ) ) {
ast_log ( LOG_WARNING , " Unexpected frequency mismatch %d (expecting %d) \n " , ltohl ( 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 ;
}
size = ltohl ( size ) ;
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 ( ; ; )
{
2005-10-16 16:12:51 +00:00
char buf [ 4 ] ;
2004-02-02 06:34:27 +00:00
/* Begin data chunk */
2005-10-16 16:12:51 +00:00
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 ;
2004-02-02 06:34:27 +00:00
}
/* Data has the actual length of data in it */
2005-10-16 16:12:51 +00:00
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 ;
2004-02-02 06:34:27 +00:00
}
data = ltohl ( data ) ;
2011-04-25 19:40:17 +00:00
if ( memcmp ( & buf , " fmt " , 4 ) = = 0 ) {
if ( check_header_fmt ( f , data , hz ) )
return - 1 ;
continue ;
}
2005-10-16 16:12:51 +00:00
if ( memcmp ( buf , " data " , 4 ) = = 0 )
break ;
2011-04-25 19:40:17 +00:00
ast_log ( LOG_DEBUG , " Skipping unknown block '%.4s' \n " , buf ) ;
2005-10-16 16:12:51 +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 ;
2004-02-02 06:34:27 +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 ;
# 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 ;
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 ) ;
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 . */
2007-11-29 17:50:44 +00:00
struct wav_desc * tmp = ( struct wav_desc * ) s - > _private ;
2011-02-03 16:22:10 +00:00
if ( ( tmp - > maxlen = check_header ( s - > f , ( s - > fmt - > format . id = = AST_FORMAT_SLINEAR16 ? 16000 : 8000 ) ) ) < 0 )
2006-04-04 12:59:25 +00:00
return - 1 ;
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 ;
2011-02-03 16:22:10 +00:00
tmp - > hz = ( s - > fmt - > format . id = = AST_FORMAT_SLINEAR16 ? 16000 : 8000 ) ;
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 ) {
if ( ! fwrite ( & zero , 1 , 1 , s - > f ) ) {
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
{
int 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 ;
2003-05-16 19:23:07 +00:00
if ( bytes < 0 )
bytes = 0 ;
2007-06-14 19:39:12 +00:00
/* ast_debug(1, "here: %d, maxlen: %d, bytes: %d\n", here, s->maxlen, bytes); */
2006-04-04 12:59:25 +00:00
s - > fr . frametype = AST_FRAME_VOICE ;
2011-02-03 16:22:10 +00:00
ast_format_set ( & s - > fr . subclass . format , ( fs - > hz = = 16000 ? AST_FORMAT_SLINEAR16 : AST_FORMAT_SLINEAR ) , 0 ) ;
2006-04-04 12:59:25 +00:00
s - > fr . mallocd = 0 ;
2006-04-09 22:31:38 +00:00
AST_FRAME_SET_BUFFER ( & s - > fr , s - > buf , AST_FRIENDLY_OFFSET , bytes ) ;
2008-10-09 21:47:02 +00:00
2008-05-22 16:29:54 +00:00
if ( ( res = fread ( s - > fr . data . ptr , 1 , s - > fr . datalen , s - > f ) ) < = 0 ) {
2006-04-04 12:59:25 +00:00
if ( res )
1999-12-05 07:09:27 +00:00
ast_log ( LOG_WARNING , " Short read (%d) (%s)! \n " , res , strerror ( errno ) ) ;
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 ;
1999-12-05 07:09:27 +00:00
if ( f - > frametype ! = AST_FRAME_VOICE ) {
ast_log ( LOG_WARNING , " Asked to write non-voice frame! \n " ) ;
return - 1 ;
}
2011-02-03 16:22:10 +00:00
if ( ( f - > subclass . format . id ! = AST_FORMAT_SLINEAR ) & & ( f - > subclass . format . id ! = AST_FORMAT_SLINEAR16 ) ) {
ast_log ( LOG_WARNING , " Asked to write non-SLINEAR%s frame (%s)! \n " , s - > hz = = 16000 ? " 16 " : " " , ast_getformatname ( & f - > subclass . format ) ) ;
2010-09-02 16:44:06 +00:00
return - 1 ;
}
2011-02-03 16:22:10 +00:00
if ( ast_format_cmp ( & f - > subclass . format , & fs - > fmt - > format ) = = AST_FORMAT_CMP_NOT_EQUAL ) {
2010-09-02 16:44:06 +00:00
ast_log ( LOG_WARNING , " Can't change SLINEAR frequency during write \n " ) ;
1999-12-05 07:09:27 +00:00
return - 1 ;
}
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 ;
2007-04-06 22:29:53 +00:00
for ( x = 0 ; x < f - > datalen / 2 ; x + + )
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 ;
2008-10-09 21:47:02 +00: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 ;
}
2003-08-28 20:02:10 +00:00
if ( whence = = SEEK_SET )
2003-02-06 22:11:43 +00:00
offset = samples + min ;
2003-08-28 20:02:10 +00:00
else if ( whence = = SEEK_CUR | | whence = = SEEK_FORCECUR )
2003-02-06 22:11:43 +00:00
offset = samples + cur ;
2003-08-28 20:02:10 +00:00
else if ( whence = = SEEK_END )
offset = max - samples ;
if ( whence ! = SEEK_FORCECUR ) {
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 " ,
. 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
2006-08-21 02:11:39 +00:00
static int load_module ( void )
1999-12-05 07:09:27 +00:00
{
2011-02-03 16:22:10 +00:00
ast_format_set ( & wav_f . format , AST_FORMAT_SLINEAR , 0 ) ;
ast_format_set ( & wav16_f . format , AST_FORMAT_SLINEAR16 , 0 ) ;
if ( ast_format_def_register ( & wav_f )
| | ast_format_def_register ( & wav16_f ) )
2007-10-31 19:24:29 +00:00
return AST_MODULE_LOAD_FAILURE ;
return AST_MODULE_LOAD_SUCCESS ;
1999-12-05 07:09:27 +00:00
}
2006-08-21 02:11:39 +00:00
static int unload_module ( void )
1999-12-05 07:09:27 +00:00
{
2011-02-03 16:22:10 +00:00
return ast_format_def_unregister ( wav_f . name )
| | ast_format_def_unregister ( wav16_f . name ) ;
2010-07-20 19:35:02 +00:00
}
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) " ,
2010-07-26 03:28:02 +00:00
. load = load_module ,
. unload = unload_module ,
. load_pri = AST_MODPRI_APP_DEPEND
) ;