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
) ;