1 /*
2  * Copyright (C) 2002-2003 Fhg Fokus
3  *
4  * This file is part of SEMS, a free SIP media server.
5  *
6  * SEMS is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version. This program is released under
10  * the GPL with the additional exemption that compiling, linking,
11  * and/or using OpenSSL is allowed.
12  *
13  * For a license to use the SEMS software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *    info@iptel.org
17  *
18  * SEMS is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  */
27 
28 #include "AmAudioFile.h"
29 #include "AmPlugIn.h"
30 #include "AmUtils.h"
31 
32 #include <string.h>
33 
AmAudioFileFormat(const string & name,int subtype)34 AmAudioFileFormat::AmAudioFileFormat(const string& name, int subtype)
35   : name(name), subtype(subtype), p_subtype(0)
36 {
37   getSubtype();
38   codec = getCodec();
39 
40   if(p_subtype && codec){
41     rate = p_subtype->sample_rate;
42     channels = p_subtype->channels;
43     subtype = p_subtype->type;
44   }
45   DBG("created AmAudioFileFormat of subtype %i, with rate %u, channels %u\n",
46       subtype, rate, channels);
47 }
48 
AmAudioFileFormat(const string & name,int subtype,amci_subtype_t * p_subtype)49 AmAudioFileFormat::AmAudioFileFormat(const string& name, int subtype, amci_subtype_t* p_subtype)
50   : name(name), subtype(subtype), p_subtype(p_subtype)
51 {
52   codec = getCodec();
53 
54   if(p_subtype && codec){
55     rate = p_subtype->sample_rate;
56     channels = p_subtype->channels;
57   }
58   DBG("created AmAudioFileFormat of subtype %i, with rate %u, channels %u\n",
59       subtype, rate, channels);
60 }
61 
getCodec()62 amci_codec_t* AmAudioFileFormat::getCodec()
63 {
64   if(p_subtype && p_subtype->codec_id != codec_id){
65     codec_id = p_subtype->codec_id;
66     destroyCodec();
67   }
68   return AmAudioFormat::getCodec();
69 }
70 
setSubtypeId(int subtype_id)71 void AmAudioFileFormat::setSubtypeId(int subtype_id)  {
72   if (subtype != subtype_id) {
73     DBG("changing file subtype to ID %d\n", subtype_id);
74     destroyCodec();
75     subtype = subtype_id;
76     p_subtype = 0;
77     getSubtype();
78     codec = getCodec();
79   }
80 }
81 
getSubtype()82 amci_subtype_t*  AmAudioFileFormat::getSubtype()
83 {
84   if(!p_subtype && !name.empty()){
85     // get file format from file name
86     amci_inoutfmt_t* iofmt = AmPlugIn::instance()->fileFormat(name.c_str());
87     if(!iofmt){
88       ERROR("AmAudioFileFormat::getSubtype: file format '%s' does not exist\n",
89 	    name.c_str());
90       return NULL;
91     }
92 
93     p_subtype = AmPlugIn::instance()->subtype(iofmt,subtype);
94     if(!p_subtype) {
95       ERROR("AmAudioFileFormat::getSubtype: subtype %i in format '%s' does not exist\n",
96 	    subtype,iofmt->name);
97       return NULL;
98     }
99 
100     subtype = p_subtype->type;
101   }
102   return p_subtype;
103 }
104 
105 
fileName2Fmt(const string & name,const string & subtype)106 AmAudioFileFormat* AmAudioFile::fileName2Fmt(const string& name, const string& subtype)
107 {
108   string ext = file_extension(name);
109   if(ext == ""){
110     ERROR("fileName2Fmt: file name has no extension (%s)\n",name.c_str());
111     return NULL;
112   }
113 
114   iofmt = AmPlugIn::instance()->fileFormat("",ext);
115   if(!iofmt){
116     ERROR("fileName2Fmt: could not find a format with that extension: '%s'\n",ext.c_str());
117     return NULL;
118   }
119 
120   if (!subtype.empty()) {
121     amci_subtype_t* st = AmPlugIn::instance()->subtype(iofmt, subtype);
122     if (st!=NULL) {
123       return new AmAudioFileFormat(iofmt->name, st->type, st);
124     }
125     WARN("subtype '%s' for file '%s' not found. Using default subtype\n",
126 	 subtype.c_str(), name.c_str());
127   }
128 
129   return new AmAudioFileFormat(iofmt->name, -1);
130 }
131 
132 
getCodecId()133 int AmAudioFileFormat::getCodecId()
134 {
135   if(!name.empty()){
136     getSubtype();
137     if(p_subtype)
138       return p_subtype->codec_id;
139   }
140 
141   return -1;
142 }
143 
getSubtype(string & filename)144 string AmAudioFile::getSubtype(string& filename) {
145   string res;
146   size_t dpos  = filename.rfind('|');
147   if (dpos != string::npos) {
148     res = filename.substr(dpos+1);
149     filename = filename.substr(0, dpos);
150   }
151   return res;
152 }
153 
154 
155 // returns 0 if everything's OK
156 // return -1 if error
open(const string & filename,OpenMode mode,bool is_tmp)157 int  AmAudioFile::open(const string& filename, OpenMode mode, bool is_tmp)
158 {
159   close();
160 
161   this->close_on_exit = true;
162   on_close_done = false;
163 
164   FILE* n_fp = NULL;
165 
166   string f_name = filename;
167   string subtype = getSubtype(f_name);
168 
169   if(!is_tmp){
170     n_fp = fopen(f_name.c_str(),mode == AmAudioFile::Read ? "r" : "w+");
171     if(!n_fp){
172       if(mode == AmAudioFile::Read)
173 	ERROR("file not found: %s\n",f_name.c_str());
174       else
175 	ERROR("could not create/overwrite file: %s\n",f_name.c_str());
176       return -1;
177     }
178   } else {
179     n_fp = tmpfile();
180     if(!n_fp){
181       ERROR("could not create temporary file: %s\n",strerror(errno));
182       return -1;
183     }
184   }
185 
186   return fpopen_int(f_name, mode, n_fp, subtype);
187 }
188 
fpopen(const string & filename,OpenMode mode,FILE * n_fp)189 int AmAudioFile::fpopen(const string& filename, OpenMode mode, FILE* n_fp)
190 {
191   close();
192   on_close_done = false;
193   string f_name = filename;
194   string subtype = getSubtype(f_name);
195   return fpopen_int(f_name, mode, n_fp, subtype);
196 }
197 
fpopen_int(const string & filename,OpenMode mode,FILE * n_fp,const string & subtype)198 int AmAudioFile::fpopen_int(const string& filename, OpenMode mode,
199 			    FILE* n_fp, const string& subtype)
200 {
201 
202   AmAudioFileFormat* f_fmt = fileName2Fmt(filename, subtype);
203   if(!f_fmt){
204     ERROR("while trying to determine the format of '%s'\n",
205 	  filename.c_str());
206     return -1;
207   }
208   fmt.reset(f_fmt);
209 
210   open_mode = mode;
211   fp = n_fp;
212   fseek(fp,0L,SEEK_SET);
213 
214   amci_file_desc_t fd;
215   memset(&fd, 0, sizeof(amci_file_desc_t));
216 
217   int ret = -1;
218 
219   if(open_mode == AmAudioFile::Write){
220 
221     if (f_fmt->channels<0 /*|| f_fmt->getRate()<0*/) {
222       if (f_fmt->channels<0)
223 	ERROR("channel count must be set for output file.\n");
224       // if (f_fmt->getRate()<0)
225       // 	ERROR("sampling rate must be set for output file.\n");
226       close();
227       return -1;
228     }
229   }
230 
231   fd.subtype = f_fmt->getSubtypeId();
232   fd.channels = f_fmt->channels;
233   fd.rate = f_fmt->getRate();
234 
235   if( iofmt->open &&
236       !(ret = (*iofmt->open)(fp, &fd, mode, f_fmt->getHCodecNoInit())) ) {
237 
238     if (mode == AmAudioFile::Read) {
239       f_fmt->setSubtypeId(fd.subtype);
240       f_fmt->channels = fd.channels;
241       f_fmt->setRate(fd.rate);
242       data_size = fd.data_size;
243 
244       setBufferSize(fd.buffer_size, fd.buffer_thresh, fd.buffer_full_thresh);
245     }
246     begin = ftell(fp);
247   } else {
248     if(!iofmt->open)
249       ERROR("no open function\n");
250     else
251       ERROR("open returned %d: %s\n", ret, strerror(errno));
252     close();
253     return ret;
254   }
255 
256   //     if(open_mode == AmAudioFile::Write){
257 
258   // 	DBG("After open:\n");
259   // 	DBG("fmt::subtype = %i\n",f_fmt->getSubtypeId());
260   // 	DBG("fmt::channels = %i\n",f_fmt->channels);
261   // 	DBG("fmt::rate = %i\n",f_fmt->rate);
262   //     }
263 
264   return ret;
265 }
266 
267 
AmAudioFile()268 AmAudioFile::AmAudioFile()
269   : AmBufferedAudio(0, 0, 0), fp(0),
270     begin(0), data_size(0), on_close_done(false), close_on_exit(true),
271     loop(false),
272     autorewind(false)
273 {
274 }
275 
~AmAudioFile()276 AmAudioFile::~AmAudioFile()
277 {
278   close();
279 }
280 
rewind()281 void AmAudioFile::rewind()
282 {
283   fseek(fp,begin,SEEK_SET);
284   clearBufferEOF();
285 }
286 
rewind(unsigned int msec)287 void AmAudioFile::rewind(unsigned int msec)
288 {
289   long fpos = ftell(fp);
290   long int k = fmt->calcBytesToRead(((getSampleRate()/100)*msec)/10);
291 
292   if(fpos > begin + k) {
293     DBG("Rewinding %d milliseconds (%ld bytes)\n", msec, k);
294     fseek(fp, -k, SEEK_CUR);
295   } else {
296     DBG("Rewinding file\n");
297     fseek(fp, begin, SEEK_SET);
298   }
299   clearBufferEOF();
300 }
301 
forward(unsigned int msec)302 void AmAudioFile::forward(unsigned int msec)
303 {
304   long fpos = ftell(fp);
305   long int k = fmt->calcBytesToRead(((getSampleRate()/100)*msec)/10);
306 
307   if(fpos <= (data_size - k)) {
308     DBG("Forwarding %d milliseconds (%ld bytes)\n", msec, k);
309     fseek(fp, k, SEEK_CUR);
310     clearBufferEOF();
311   } else {
312     DBG("Forwarding to EOF\n");
313     fseek(fp, data_size, SEEK_SET);
314   }
315 }
316 
on_close()317 void AmAudioFile::on_close()
318 {
319   if(fp && !on_close_done){
320 
321     AmAudioFileFormat* f_fmt =
322       dynamic_cast<AmAudioFileFormat*>(fmt.get());
323 
324     if(f_fmt){
325       amci_file_desc_t fmt_desc = { f_fmt->getSubtypeId(),
326 				    (int)f_fmt->getRate(),
327 				    f_fmt->channels,
328 				    data_size ,
329 				    0, 0, 0};
330 
331       if(!iofmt){
332 	ERROR("file format pointer not initialized: on_close will not be called\n");
333       }
334       else if(iofmt->on_close)
335 	(*iofmt->on_close)(fp,&fmt_desc,open_mode, fmt->getHCodecNoInit(), fmt->getCodec());
336     }
337 
338     if(open_mode == AmAudioFile::Write){
339 
340       DBG("After close:\n");
341       DBG("fmt::subtype = %i\n",f_fmt->getSubtypeId());
342       DBG("fmt::channels = %i\n",f_fmt->channels);
343       DBG("fmt::rate = %i\n",f_fmt->getRate());
344     }
345 
346     on_close_done = true;
347   }
348 }
349 
350 
close()351 void AmAudioFile::close()
352 {
353   if(fp){
354     on_close();
355 
356     if(close_on_exit)
357       fclose(fp);
358     fp = 0;
359   }
360 }
361 
getMimeType()362 string AmAudioFile::getMimeType()
363 {
364   if(!iofmt)
365     return "";
366 
367   return iofmt->email_content_type;
368 }
369 
370 
read(unsigned int user_ts,unsigned int size)371 int AmAudioFile::read(unsigned int user_ts, unsigned int size)
372 {
373   if(!fp){
374     ERROR("AmAudioFile::read: file is not opened\n");
375     return -1;
376   }
377 
378   int ret;
379   int s = size;
380 
381  read_block:
382   long fpos  = ftell(fp);
383   if(data_size < 0 || fpos - begin < data_size){
384 
385     if((data_size > 0) && (fpos - begin + (int)size > data_size)) {
386       // last block to read
387       s = data_size - fpos + begin;
388     }
389 
390     if ((data_size == -1) && loop.get() && feof(fp)) {
391       // data size unknown, loop and eof
392       DBG("rewinding audio file...\n");
393       rewind();
394       goto read_block;
395     }
396 
397     if (data_size == -1 && autorewind.get() && feof(fp)) {
398       // data size unknown, autorewind and eof
399       DBG("autorewinding audio file...\n");
400       rewind();
401 
402       ret = -2; // eof
403     } else {
404       // read from file
405       int rs = fread((void*)((unsigned char*)samples),1,s,fp);
406       if (rs != s) {
407         DBG("marking data size as invalid as we read %d but should read %d", rs, s);
408         // we read less than we should => data size is probably broken
409         data_size = -1;
410         s = rs;
411       }
412 
413       ret = (!ferror(fp) ? s : -1);
414     }
415 
416 #if (defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN))
417 #define bswap_16(A)  ((((u_int16_t)(A) & 0xff00) >> 8) | \
418 		      (((u_int16_t)(A) & 0x00ff) << 8))
419 
420     unsigned int i;
421     for(i=0;i<=size/2;i++) {
422       ((u_int16_t *)((unsigned char*)samples))[i]=
423 	bswap_16(((u_int16_t *)((unsigned char*)samples))[i]);
424     }
425 
426 #endif
427   } else {
428     if (loop.get() && data_size>0) {
429       DBG("rewinding audio file...\n");
430       rewind();
431       goto read_block;
432     }
433 
434     if (autorewind.get() && data_size>0){
435       DBG("autorewinding audio file...\n");
436       rewind();
437     }
438 
439     ret = -2; // eof
440   }
441 
442   if(ret > 0 && s > 0 && (unsigned int)s < size){
443     DBG("0-stuffing packet: adding %i bytes (packet size=%i)\n",size-s,size);
444     memset((unsigned char*)samples + s,0,size-s);
445     return size;
446   }
447 
448   return ret;
449 }
450 
write(unsigned int user_ts,unsigned int size)451 int AmAudioFile::write(unsigned int user_ts, unsigned int size)
452 {
453   if(!fp){
454     ERROR("AmAudioFile::write: file is not opened\n");
455     return -1;
456   }
457 
458   if (getMode() != AmAudioFile::Write) {
459     return size;
460   }
461 
462   int s = fwrite((void*)((unsigned char*)samples),1,size,fp);
463   if(s>0)
464     data_size += s;
465   return (!ferror(fp) ? s : -1);
466 }
467 
getLength()468 int AmAudioFile::getLength()
469 {
470   if (!data_size || !fmt.get())
471     return 0;
472 
473   float rate = fmt->getRate() / 1000;
474   return (int) (fmt->bytes2samples(data_size)  / rate);
475 }
476