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