1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "webrtc/modules/media_file/source/media_file_utility.h"
12
13 #include <assert.h>
14 #include <sys/stat.h>
15 #include <sys/types.h>
16
17 #include "webrtc/common_types.h"
18 #include "webrtc/engine_configurations.h"
19 #include "webrtc/modules/interface/module_common_types.h"
20 #include "webrtc/system_wrappers/interface/file_wrapper.h"
21 #include "webrtc/system_wrappers/interface/trace.h"
22
23 #ifdef WEBRTC_MODULE_UTILITY_VIDEO
24 #include "avi_file.h"
25 #endif
26
27 namespace {
28 enum WaveFormats
29 {
30 kWaveFormatPcm = 0x0001,
31 kWaveFormatALaw = 0x0006,
32 kWaveFormatMuLaw = 0x0007
33 };
34
35 // First 16 bytes the WAVE header. ckID should be "RIFF", wave_ckID should be
36 // "WAVE" and ckSize is the chunk size (4 + n)
37 struct WAVE_RIFF_header
38 {
39 int8_t ckID[4];
40 int32_t ckSize;
41 int8_t wave_ckID[4];
42 };
43
44 // First 8 byte of the format chunk. fmt_ckID should be "fmt ". fmt_ckSize is
45 // the chunk size (16, 18 or 40 byte)
46 struct WAVE_CHUNK_header
47 {
48 int8_t fmt_ckID[4];
49 int32_t fmt_ckSize;
50 };
51 } // unnamed namespace
52
53 namespace webrtc {
ModuleFileUtility(const int32_t id)54 ModuleFileUtility::ModuleFileUtility(const int32_t id)
55 : _wavFormatObj(),
56 _dataSize(0),
57 _readSizeBytes(0),
58 _id(id),
59 _stopPointInMs(0),
60 _startPointInMs(0),
61 _playoutPositionMs(0),
62 _bytesWritten(0),
63 codec_info_(),
64 _codecId(kCodecNoCodec),
65 _bytesPerSample(0),
66 _readPos(0),
67 _reading(false),
68 _writing(false),
69 _tempData()
70 #ifdef WEBRTC_MODULE_UTILITY_VIDEO
71 ,
72 _aviAudioInFile(0),
73 _aviVideoInFile(0),
74 _aviOutFile(0)
75 #endif
76 {
77 WEBRTC_TRACE(kTraceMemory, kTraceFile, _id,
78 "ModuleFileUtility::ModuleFileUtility()");
79 memset(&codec_info_,0,sizeof(CodecInst));
80 codec_info_.pltype = -1;
81 #ifdef WEBRTC_MODULE_UTILITY_VIDEO
82 memset(&_videoCodec,0,sizeof(_videoCodec));
83 #endif
84 }
85
~ModuleFileUtility()86 ModuleFileUtility::~ModuleFileUtility()
87 {
88 WEBRTC_TRACE(kTraceMemory, kTraceFile, _id,
89 "ModuleFileUtility::~ModuleFileUtility()");
90 #ifdef WEBRTC_MODULE_UTILITY_VIDEO
91 delete _aviAudioInFile;
92 delete _aviVideoInFile;
93 #endif
94 }
95
96 #ifdef WEBRTC_MODULE_UTILITY_VIDEO
InitAviWriting(const char * filename,const CodecInst & audioCodecInst,const VideoCodec & videoCodecInst,const bool videoOnly)97 int32_t ModuleFileUtility::InitAviWriting(
98 const char* filename,
99 const CodecInst& audioCodecInst,
100 const VideoCodec& videoCodecInst,
101 const bool videoOnly /*= false*/)
102 {
103 _writing = false;
104
105 delete _aviOutFile;
106 _aviOutFile = new AviFile( );
107
108 AVISTREAMHEADER videoStreamHeader;
109 videoStreamHeader.fccType = AviFile::MakeFourCc('v', 'i', 'd', 's');
110
111 #ifdef VIDEOCODEC_I420
112 if (strncmp(videoCodecInst.plName, "I420", 7) == 0)
113 {
114 videoStreamHeader.fccHandler = AviFile::MakeFourCc('I','4','2','0');
115 }
116 #endif
117 #ifdef VIDEOCODEC_VP8
118 if (strncmp(videoCodecInst.plName, "VP8", 7) == 0)
119 {
120 videoStreamHeader.fccHandler = AviFile::MakeFourCc('V','P','8','0');
121 }
122 #endif
123 if (videoStreamHeader.fccHandler == 0)
124 {
125 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
126 "InitAviWriting() Codec not supported");
127
128 return -1;
129 }
130 videoStreamHeader.dwScale = 1;
131 videoStreamHeader.dwRate = videoCodecInst.maxFramerate;
132 videoStreamHeader.dwSuggestedBufferSize = videoCodecInst.height *
133 (videoCodecInst.width >> 1) * 3;
134 videoStreamHeader.dwQuality = (uint32_t)-1;
135 videoStreamHeader.dwSampleSize = 0;
136 videoStreamHeader.rcFrame.top = 0;
137 videoStreamHeader.rcFrame.bottom = videoCodecInst.height;
138 videoStreamHeader.rcFrame.left = 0;
139 videoStreamHeader.rcFrame.right = videoCodecInst.width;
140
141 BITMAPINFOHEADER bitMapInfoHeader;
142 bitMapInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
143 bitMapInfoHeader.biHeight = videoCodecInst.height;
144 bitMapInfoHeader.biWidth = videoCodecInst.width;
145 bitMapInfoHeader.biPlanes = 1;
146 bitMapInfoHeader.biBitCount = 12;
147 bitMapInfoHeader.biClrImportant = 0;
148 bitMapInfoHeader.biClrUsed = 0;
149 bitMapInfoHeader.biCompression = videoStreamHeader.fccHandler;
150 bitMapInfoHeader.biSizeImage = bitMapInfoHeader.biWidth *
151 bitMapInfoHeader.biHeight * bitMapInfoHeader.biBitCount / 8;
152
153 if (_aviOutFile->CreateVideoStream(
154 videoStreamHeader,
155 bitMapInfoHeader,
156 NULL,
157 0) != 0)
158 {
159 return -1;
160 }
161
162 if(!videoOnly)
163 {
164 AVISTREAMHEADER audioStreamHeader;
165 audioStreamHeader.fccType = AviFile::MakeFourCc('a', 'u', 'd', 's');
166 // fccHandler is the FOURCC of the codec for decoding the stream.
167 // It's an optional parameter that is not used by audio streams.
168 audioStreamHeader.fccHandler = 0;
169 audioStreamHeader.dwScale = 1;
170
171 WAVEFORMATEX waveFormatHeader;
172 waveFormatHeader.cbSize = 0;
173 waveFormatHeader.nChannels = 1;
174
175 if (strncmp(audioCodecInst.plname, "PCMU", 4) == 0)
176 {
177 audioStreamHeader.dwSampleSize = 1;
178 audioStreamHeader.dwRate = 8000;
179 audioStreamHeader.dwQuality = (uint32_t)-1;
180 audioStreamHeader.dwSuggestedBufferSize = 80;
181
182 waveFormatHeader.nAvgBytesPerSec = 8000;
183 waveFormatHeader.nSamplesPerSec = 8000;
184 waveFormatHeader.wBitsPerSample = 8;
185 waveFormatHeader.nBlockAlign = 1;
186 waveFormatHeader.wFormatTag = kWaveFormatMuLaw;
187
188 } else if (strncmp(audioCodecInst.plname, "PCMA", 4) == 0)
189 {
190 audioStreamHeader.dwSampleSize = 1;
191 audioStreamHeader.dwRate = 8000;
192 audioStreamHeader.dwQuality = (uint32_t)-1;
193 audioStreamHeader.dwSuggestedBufferSize = 80;
194
195 waveFormatHeader.nAvgBytesPerSec = 8000;
196 waveFormatHeader.nSamplesPerSec = 8000;
197 waveFormatHeader.wBitsPerSample = 8;
198 waveFormatHeader.nBlockAlign = 1;
199 waveFormatHeader.wFormatTag = kWaveFormatALaw;
200
201 } else if (strncmp(audioCodecInst.plname, "L16", 3) == 0)
202 {
203 audioStreamHeader.dwSampleSize = 2;
204 audioStreamHeader.dwRate = audioCodecInst.plfreq;
205 audioStreamHeader.dwQuality = (uint32_t)-1;
206 audioStreamHeader.dwSuggestedBufferSize =
207 (audioCodecInst.plfreq/100) * 2;
208
209 waveFormatHeader.nAvgBytesPerSec = audioCodecInst.plfreq * 2;
210 waveFormatHeader.nSamplesPerSec = audioCodecInst.plfreq;
211 waveFormatHeader.wBitsPerSample = 16;
212 waveFormatHeader.nBlockAlign = 2;
213 waveFormatHeader.wFormatTag = kWaveFormatPcm;
214 } else
215 {
216 return -1;
217 }
218
219 if(_aviOutFile->CreateAudioStream(
220 audioStreamHeader,
221 waveFormatHeader) != 0)
222 {
223 return -1;
224 }
225
226
227 if( InitWavCodec(waveFormatHeader.nSamplesPerSec,
228 waveFormatHeader.nChannels,
229 waveFormatHeader.wBitsPerSample,
230 waveFormatHeader.wFormatTag) != 0)
231 {
232 return -1;
233 }
234 }
235 _aviOutFile->Create(filename);
236 _writing = true;
237 return 0;
238 }
239
WriteAviAudioData(const int8_t * buffer,uint32_t bufferLengthInBytes)240 int32_t ModuleFileUtility::WriteAviAudioData(
241 const int8_t* buffer,
242 uint32_t bufferLengthInBytes)
243 {
244 if( _aviOutFile != 0)
245 {
246 return _aviOutFile->WriteAudio(
247 reinterpret_cast<const uint8_t*>(buffer),
248 bufferLengthInBytes);
249 }
250 else
251 {
252 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "AVI file not initialized");
253 return -1;
254 }
255 }
256
WriteAviVideoData(const int8_t * buffer,uint32_t bufferLengthInBytes)257 int32_t ModuleFileUtility::WriteAviVideoData(
258 const int8_t* buffer,
259 uint32_t bufferLengthInBytes)
260 {
261 if( _aviOutFile != 0)
262 {
263 return _aviOutFile->WriteVideo(
264 reinterpret_cast<const uint8_t*>(buffer),
265 bufferLengthInBytes);
266 }
267 else
268 {
269 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "AVI file not initialized");
270 return -1;
271 }
272 }
273
274
CloseAviFile()275 int32_t ModuleFileUtility::CloseAviFile( )
276 {
277 if( _reading && _aviAudioInFile)
278 {
279 delete _aviAudioInFile;
280 _aviAudioInFile = 0;
281 }
282
283 if( _reading && _aviVideoInFile)
284 {
285 delete _aviVideoInFile;
286 _aviVideoInFile = 0;
287 }
288
289 if( _writing && _aviOutFile)
290 {
291 delete _aviOutFile;
292 _aviOutFile = 0;
293 }
294 return 0;
295 }
296
297
InitAviReading(const char * filename,bool videoOnly,bool loop)298 int32_t ModuleFileUtility::InitAviReading(const char* filename, bool videoOnly,
299 bool loop)
300 {
301 _reading = false;
302 delete _aviVideoInFile;
303 _aviVideoInFile = new AviFile( );
304
305 if ((_aviVideoInFile != 0) && _aviVideoInFile->Open(AviFile::AVI_VIDEO,
306 filename, loop) == -1)
307 {
308 WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
309 "Unable to open AVI file (video)");
310 return -1;
311 }
312
313
314 AVISTREAMHEADER videoInStreamHeader;
315 BITMAPINFOHEADER bitmapInfo;
316 char codecConfigParameters[AviFile::CODEC_CONFIG_LENGTH] = {};
317 int32_t configLength = 0;
318 if( _aviVideoInFile->GetVideoStreamInfo(videoInStreamHeader, bitmapInfo,
319 codecConfigParameters,
320 configLength) != 0)
321 {
322 return -1;
323 }
324 _videoCodec.width = static_cast<uint16_t>(
325 videoInStreamHeader.rcFrame.right);
326 _videoCodec.height = static_cast<uint16_t>(
327 videoInStreamHeader.rcFrame.bottom);
328 _videoCodec.maxFramerate = static_cast<uint8_t>(
329 videoInStreamHeader.dwRate);
330
331 const size_t plnameLen = sizeof(_videoCodec.plName) / sizeof(char);
332 if (bitmapInfo.biCompression == AviFile::MakeFourCc('I','4','2','0'))
333 {
334 strncpy(_videoCodec.plName, "I420", plnameLen);
335 _videoCodec.codecType = kVideoCodecI420;
336 }
337 else if (bitmapInfo.biCompression ==
338 AviFile::MakeFourCc('V', 'P', '8', '0'))
339 {
340 strncpy(_videoCodec.plName, "VP8", plnameLen);
341 _videoCodec.codecType = kVideoCodecVP8;
342 }
343 else
344 {
345 return -1;
346 }
347
348 if(!videoOnly)
349 {
350 delete _aviAudioInFile;
351 _aviAudioInFile = new AviFile();
352
353 if ( (_aviAudioInFile != 0) &&
354 _aviAudioInFile->Open(AviFile::AVI_AUDIO, filename, loop) == -1)
355 {
356 WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
357 "Unable to open AVI file (audio)");
358 return -1;
359 }
360
361 WAVEFORMATEX waveHeader;
362 if(_aviAudioInFile->GetAudioStreamInfo(waveHeader) != 0)
363 {
364 return -1;
365 }
366 if(InitWavCodec(waveHeader.nSamplesPerSec, waveHeader.nChannels,
367 waveHeader.wBitsPerSample, waveHeader.wFormatTag) != 0)
368 {
369 return -1;
370 }
371 }
372 _reading = true;
373 return 0;
374 }
375
ReadAviAudioData(int8_t * outBuffer,const uint32_t bufferLengthInBytes)376 int32_t ModuleFileUtility::ReadAviAudioData(
377 int8_t* outBuffer,
378 const uint32_t bufferLengthInBytes)
379 {
380 if(_aviAudioInFile == 0)
381 {
382 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "AVI file not opened.");
383 return -1;
384 }
385
386 int32_t length = bufferLengthInBytes;
387 if(_aviAudioInFile->ReadAudio(
388 reinterpret_cast<uint8_t*>(outBuffer),
389 length) != 0)
390 {
391 return -1;
392 }
393 else
394 {
395 return length;
396 }
397 }
398
ReadAviVideoData(int8_t * outBuffer,const uint32_t bufferLengthInBytes)399 int32_t ModuleFileUtility::ReadAviVideoData(
400 int8_t* outBuffer,
401 const uint32_t bufferLengthInBytes)
402 {
403 if(_aviVideoInFile == 0)
404 {
405 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "AVI file not opened.");
406 return -1;
407 }
408
409 int32_t length = bufferLengthInBytes;
410 if( _aviVideoInFile->ReadVideo(
411 reinterpret_cast<uint8_t*>(outBuffer),
412 length) != 0)
413 {
414 return -1;
415 } else {
416 return length;
417 }
418 }
419
VideoCodecInst(VideoCodec & codecInst)420 int32_t ModuleFileUtility::VideoCodecInst(VideoCodec& codecInst)
421 {
422 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
423 "ModuleFileUtility::CodecInst(codecInst= 0x%x)", &codecInst);
424
425 if(!_reading)
426 {
427 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
428 "CodecInst: not currently reading audio file!");
429 return -1;
430 }
431 memcpy(&codecInst,&_videoCodec,sizeof(VideoCodec));
432 return 0;
433 }
434 #endif
435
ReadWavHeader(InStream & wav)436 int32_t ModuleFileUtility::ReadWavHeader(InStream& wav)
437 {
438 WAVE_RIFF_header RIFFheaderObj;
439 WAVE_CHUNK_header CHUNKheaderObj;
440 // TODO (hellner): tmpStr and tmpStr2 seems unnecessary here.
441 char tmpStr[6] = "FOUR";
442 unsigned char tmpStr2[4];
443 int32_t i, len;
444 bool dataFound = false;
445 bool fmtFound = false;
446 int8_t dummyRead;
447
448
449 _dataSize = 0;
450 len = wav.Read(&RIFFheaderObj, sizeof(WAVE_RIFF_header));
451 if(len != sizeof(WAVE_RIFF_header))
452 {
453 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
454 "Not a wave file (too short)");
455 return -1;
456 }
457
458 for (i = 0; i < 4; i++)
459 {
460 tmpStr[i] = RIFFheaderObj.ckID[i];
461 }
462 if(strcmp(tmpStr, "RIFF") != 0)
463 {
464 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
465 "Not a wave file (does not have RIFF)");
466 return -1;
467 }
468 for (i = 0; i < 4; i++)
469 {
470 tmpStr[i] = RIFFheaderObj.wave_ckID[i];
471 }
472 if(strcmp(tmpStr, "WAVE") != 0)
473 {
474 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
475 "Not a wave file (does not have WAVE)");
476 return -1;
477 }
478
479 len = wav.Read(&CHUNKheaderObj, sizeof(WAVE_CHUNK_header));
480
481 // WAVE files are stored in little endian byte order. Make sure that the
482 // data can be read on big endian as well.
483 // TODO (hellner): little endian to system byte order should be done in
484 // in a subroutine.
485 memcpy(tmpStr2, &CHUNKheaderObj.fmt_ckSize, 4);
486 CHUNKheaderObj.fmt_ckSize =
487 (int32_t) ((uint32_t) tmpStr2[0] +
488 (((uint32_t)tmpStr2[1])<<8) +
489 (((uint32_t)tmpStr2[2])<<16) +
490 (((uint32_t)tmpStr2[3])<<24));
491
492 memcpy(tmpStr, CHUNKheaderObj.fmt_ckID, 4);
493
494 while ((len == sizeof(WAVE_CHUNK_header)) && (!fmtFound || !dataFound))
495 {
496 if(strcmp(tmpStr, "fmt ") == 0)
497 {
498 len = wav.Read(&_wavFormatObj, sizeof(WAVE_FMTINFO_header));
499
500 memcpy(tmpStr2, &_wavFormatObj.formatTag, 2);
501 _wavFormatObj.formatTag =
502 (WaveFormats) ((uint32_t)tmpStr2[0] +
503 (((uint32_t)tmpStr2[1])<<8));
504 memcpy(tmpStr2, &_wavFormatObj.nChannels, 2);
505 _wavFormatObj.nChannels =
506 (int16_t) ((uint32_t)tmpStr2[0] +
507 (((uint32_t)tmpStr2[1])<<8));
508 memcpy(tmpStr2, &_wavFormatObj.nSamplesPerSec, 4);
509 _wavFormatObj.nSamplesPerSec =
510 (int32_t) ((uint32_t)tmpStr2[0] +
511 (((uint32_t)tmpStr2[1])<<8) +
512 (((uint32_t)tmpStr2[2])<<16) +
513 (((uint32_t)tmpStr2[3])<<24));
514 memcpy(tmpStr2, &_wavFormatObj.nAvgBytesPerSec, 4);
515 _wavFormatObj.nAvgBytesPerSec =
516 (int32_t) ((uint32_t)tmpStr2[0] +
517 (((uint32_t)tmpStr2[1])<<8) +
518 (((uint32_t)tmpStr2[2])<<16) +
519 (((uint32_t)tmpStr2[3])<<24));
520 memcpy(tmpStr2, &_wavFormatObj.nBlockAlign, 2);
521 _wavFormatObj.nBlockAlign =
522 (int16_t) ((uint32_t)tmpStr2[0] +
523 (((uint32_t)tmpStr2[1])<<8));
524 memcpy(tmpStr2, &_wavFormatObj.nBitsPerSample, 2);
525 _wavFormatObj.nBitsPerSample =
526 (int16_t) ((uint32_t)tmpStr2[0] +
527 (((uint32_t)tmpStr2[1])<<8));
528
529 for (i = 0;
530 i < (CHUNKheaderObj.fmt_ckSize -
531 (int32_t)sizeof(WAVE_FMTINFO_header));
532 i++)
533 {
534 len = wav.Read(&dummyRead, 1);
535 if(len != 1)
536 {
537 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
538 "File corrupted, reached EOF (reading fmt)");
539 return -1;
540 }
541 }
542 fmtFound = true;
543 }
544 else if(strcmp(tmpStr, "data") == 0)
545 {
546 _dataSize = CHUNKheaderObj.fmt_ckSize;
547 dataFound = true;
548 break;
549 }
550 else
551 {
552 for (i = 0; i < (CHUNKheaderObj.fmt_ckSize); i++)
553 {
554 len = wav.Read(&dummyRead, 1);
555 if(len != 1)
556 {
557 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
558 "File corrupted, reached EOF (reading other)");
559 return -1;
560 }
561 }
562 }
563
564 len = wav.Read(&CHUNKheaderObj, sizeof(WAVE_CHUNK_header));
565
566 memcpy(tmpStr2, &CHUNKheaderObj.fmt_ckSize, 4);
567 CHUNKheaderObj.fmt_ckSize =
568 (int32_t) ((uint32_t)tmpStr2[0] +
569 (((uint32_t)tmpStr2[1])<<8) +
570 (((uint32_t)tmpStr2[2])<<16) +
571 (((uint32_t)tmpStr2[3])<<24));
572
573 memcpy(tmpStr, CHUNKheaderObj.fmt_ckID, 4);
574 }
575
576 // Either a proper format chunk has been read or a data chunk was come
577 // across.
578 if( (_wavFormatObj.formatTag != kWaveFormatPcm) &&
579 (_wavFormatObj.formatTag != kWaveFormatALaw) &&
580 (_wavFormatObj.formatTag != kWaveFormatMuLaw))
581 {
582 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
583 "Coding formatTag value=%d not supported!",
584 _wavFormatObj.formatTag);
585 return -1;
586 }
587 if((_wavFormatObj.nChannels < 1) ||
588 (_wavFormatObj.nChannels > 2))
589 {
590 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
591 "nChannels value=%d not supported!",
592 _wavFormatObj.nChannels);
593 return -1;
594 }
595
596 if((_wavFormatObj.nBitsPerSample != 8) &&
597 (_wavFormatObj.nBitsPerSample != 16))
598 {
599 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
600 "nBitsPerSample value=%d not supported!",
601 _wavFormatObj.nBitsPerSample);
602 return -1;
603 }
604
605 // Calculate the number of bytes that 10 ms of audio data correspond to.
606 if(_wavFormatObj.formatTag == kWaveFormatPcm)
607 {
608 // TODO (hellner): integer division for 22050 and 11025 would yield
609 // the same result as the else statement. Remove those
610 // special cases?
611 if(_wavFormatObj.nSamplesPerSec == 44100)
612 {
613 _readSizeBytes = 440 * _wavFormatObj.nChannels *
614 (_wavFormatObj.nBitsPerSample / 8);
615 } else if(_wavFormatObj.nSamplesPerSec == 22050) {
616 _readSizeBytes = 220 * _wavFormatObj.nChannels *
617 (_wavFormatObj.nBitsPerSample / 8);
618 } else if(_wavFormatObj.nSamplesPerSec == 11025) {
619 _readSizeBytes = 110 * _wavFormatObj.nChannels *
620 (_wavFormatObj.nBitsPerSample / 8);
621 } else {
622 _readSizeBytes = (_wavFormatObj.nSamplesPerSec/100) *
623 _wavFormatObj.nChannels * (_wavFormatObj.nBitsPerSample / 8);
624 }
625
626 } else {
627 _readSizeBytes = (_wavFormatObj.nSamplesPerSec/100) *
628 _wavFormatObj.nChannels * (_wavFormatObj.nBitsPerSample / 8);
629 }
630 return 0;
631 }
632
InitWavCodec(uint32_t samplesPerSec,uint32_t channels,uint32_t bitsPerSample,uint32_t formatTag)633 int32_t ModuleFileUtility::InitWavCodec(uint32_t samplesPerSec,
634 uint32_t channels,
635 uint32_t bitsPerSample,
636 uint32_t formatTag)
637 {
638 codec_info_.pltype = -1;
639 codec_info_.plfreq = samplesPerSec;
640 codec_info_.channels = channels;
641 codec_info_.rate = bitsPerSample * samplesPerSec;
642
643 // Calculate the packet size for 10ms frames
644 switch(formatTag)
645 {
646 case kWaveFormatALaw:
647 strcpy(codec_info_.plname, "PCMA");
648 _codecId = kCodecPcma;
649 codec_info_.pltype = 8;
650 codec_info_.pacsize = codec_info_.plfreq / 100;
651 break;
652 case kWaveFormatMuLaw:
653 strcpy(codec_info_.plname, "PCMU");
654 _codecId = kCodecPcmu;
655 codec_info_.pltype = 0;
656 codec_info_.pacsize = codec_info_.plfreq / 100;
657 break;
658 case kWaveFormatPcm:
659 codec_info_.pacsize = (bitsPerSample * (codec_info_.plfreq / 100)) / 8;
660 if(samplesPerSec == 8000)
661 {
662 strcpy(codec_info_.plname, "L16");
663 _codecId = kCodecL16_8Khz;
664 }
665 else if(samplesPerSec == 16000)
666 {
667 strcpy(codec_info_.plname, "L16");
668 _codecId = kCodecL16_16kHz;
669 }
670 else if(samplesPerSec == 32000)
671 {
672 strcpy(codec_info_.plname, "L16");
673 _codecId = kCodecL16_32Khz;
674 }
675 // Set the packet size for "odd" sampling frequencies so that it
676 // properly corresponds to _readSizeBytes.
677 else if(samplesPerSec == 11025)
678 {
679 strcpy(codec_info_.plname, "L16");
680 _codecId = kCodecL16_16kHz;
681 codec_info_.pacsize = 110;
682 codec_info_.plfreq = 11000;
683 }
684 else if(samplesPerSec == 22050)
685 {
686 strcpy(codec_info_.plname, "L16");
687 _codecId = kCodecL16_16kHz;
688 codec_info_.pacsize = 220;
689 codec_info_.plfreq = 22000;
690 }
691 else if(samplesPerSec == 44100)
692 {
693 strcpy(codec_info_.plname, "L16");
694 _codecId = kCodecL16_16kHz;
695 codec_info_.pacsize = 440;
696 codec_info_.plfreq = 44000;
697 }
698 else if(samplesPerSec == 48000)
699 {
700 strcpy(codec_info_.plname, "L16");
701 _codecId = kCodecL16_16kHz;
702 codec_info_.pacsize = 480;
703 codec_info_.plfreq = 48000;
704 }
705 else
706 {
707 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
708 "Unsupported PCM frequency!");
709 return -1;
710 }
711 break;
712 default:
713 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
714 "unknown WAV format TAG!");
715 return -1;
716 break;
717 }
718 return 0;
719 }
720
InitWavReading(InStream & wav,const uint32_t start,const uint32_t stop)721 int32_t ModuleFileUtility::InitWavReading(InStream& wav,
722 const uint32_t start,
723 const uint32_t stop)
724 {
725
726 _reading = false;
727
728 if(ReadWavHeader(wav) == -1)
729 {
730 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
731 "failed to read WAV header!");
732 return -1;
733 }
734
735 _playoutPositionMs = 0;
736 _readPos = 0;
737
738 if(start > 0)
739 {
740 uint8_t dummy[WAV_MAX_BUFFER_SIZE];
741 int32_t readLength;
742 if(_readSizeBytes <= WAV_MAX_BUFFER_SIZE)
743 {
744 while (_playoutPositionMs < start)
745 {
746 readLength = wav.Read(dummy, _readSizeBytes);
747 if(readLength == _readSizeBytes)
748 {
749 _readPos += readLength;
750 _playoutPositionMs += 10;
751 }
752 else // Must have reached EOF before start position!
753 {
754 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
755 "InitWavReading(), EOF before start position");
756 return -1;
757 }
758 }
759 }
760 else
761 {
762 return -1;
763 }
764 }
765 if( InitWavCodec(_wavFormatObj.nSamplesPerSec, _wavFormatObj.nChannels,
766 _wavFormatObj.nBitsPerSample,
767 _wavFormatObj.formatTag) != 0)
768 {
769 return -1;
770 }
771 _bytesPerSample = _wavFormatObj.nBitsPerSample / 8;
772
773
774 _startPointInMs = start;
775 _stopPointInMs = stop;
776 _reading = true;
777 return 0;
778 }
779
ReadWavDataAsMono(InStream & wav,int8_t * outData,const uint32_t bufferSize)780 int32_t ModuleFileUtility::ReadWavDataAsMono(
781 InStream& wav,
782 int8_t* outData,
783 const uint32_t bufferSize)
784 {
785 WEBRTC_TRACE(
786 kTraceStream,
787 kTraceFile,
788 _id,
789 "ModuleFileUtility::ReadWavDataAsMono(wav= 0x%x, outData= 0x%d,\
790 bufSize= %ld)",
791 &wav,
792 outData,
793 bufferSize);
794
795 // The number of bytes that should be read from file.
796 const uint32_t totalBytesNeeded = _readSizeBytes;
797 // The number of bytes that will be written to outData.
798 const uint32_t bytesRequested = (codec_info_.channels == 2) ?
799 totalBytesNeeded >> 1 : totalBytesNeeded;
800 if(bufferSize < bytesRequested)
801 {
802 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
803 "ReadWavDataAsMono: output buffer is too short!");
804 return -1;
805 }
806 if(outData == NULL)
807 {
808 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
809 "ReadWavDataAsMono: output buffer NULL!");
810 return -1;
811 }
812
813 if(!_reading)
814 {
815 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
816 "ReadWavDataAsMono: no longer reading file.");
817 return -1;
818 }
819
820 int32_t bytesRead = ReadWavData(
821 wav,
822 (codec_info_.channels == 2) ? _tempData : (uint8_t*)outData,
823 totalBytesNeeded);
824 if(bytesRead == 0)
825 {
826 return 0;
827 }
828 if(bytesRead < 0)
829 {
830 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
831 "ReadWavDataAsMono: failed to read data from WAV file.");
832 return -1;
833 }
834 // Output data is should be mono.
835 if(codec_info_.channels == 2)
836 {
837 for (uint32_t i = 0; i < bytesRequested / _bytesPerSample; i++)
838 {
839 // Sample value is the average of left and right buffer rounded to
840 // closest integer value. Note samples can be either 1 or 2 byte.
841 if(_bytesPerSample == 1)
842 {
843 _tempData[i] = ((_tempData[2 * i] + _tempData[(2 * i) + 1] +
844 1) >> 1);
845 }
846 else
847 {
848 int16_t* sampleData = (int16_t*) _tempData;
849 sampleData[i] = ((sampleData[2 * i] + sampleData[(2 * i) + 1] +
850 1) >> 1);
851 }
852 }
853 memcpy(outData, _tempData, bytesRequested);
854 }
855 return bytesRequested;
856 }
857
ReadWavDataAsStereo(InStream & wav,int8_t * outDataLeft,int8_t * outDataRight,const uint32_t bufferSize)858 int32_t ModuleFileUtility::ReadWavDataAsStereo(
859 InStream& wav,
860 int8_t* outDataLeft,
861 int8_t* outDataRight,
862 const uint32_t bufferSize)
863 {
864 WEBRTC_TRACE(
865 kTraceStream,
866 kTraceFile,
867 _id,
868 "ModuleFileUtility::ReadWavDataAsStereo(wav= 0x%x, outLeft= 0x%x,\
869 outRight= 0x%x, bufSize= %ld)",
870 &wav,
871 outDataLeft,
872 outDataRight,
873 bufferSize);
874
875 if((outDataLeft == NULL) ||
876 (outDataRight == NULL))
877 {
878 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
879 "ReadWavDataAsMono: an input buffer is NULL!");
880 return -1;
881 }
882 if(codec_info_.channels != 2)
883 {
884 WEBRTC_TRACE(
885 kTraceError,
886 kTraceFile,
887 _id,
888 "ReadWavDataAsStereo: WAV file does not contain stereo data!");
889 return -1;
890 }
891 if(! _reading)
892 {
893 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
894 "ReadWavDataAsStereo: no longer reading file.");
895 return -1;
896 }
897
898 // The number of bytes that should be read from file.
899 const uint32_t totalBytesNeeded = _readSizeBytes;
900 // The number of bytes that will be written to the left and the right
901 // buffers.
902 const uint32_t bytesRequested = totalBytesNeeded >> 1;
903 if(bufferSize < bytesRequested)
904 {
905 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
906 "ReadWavData: Output buffers are too short!");
907 assert(false);
908 return -1;
909 }
910
911 int32_t bytesRead = ReadWavData(wav, _tempData, totalBytesNeeded);
912 if(bytesRead <= 0)
913 {
914 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
915 "ReadWavDataAsStereo: failed to read data from WAV file.");
916 return -1;
917 }
918
919 // Turn interleaved audio to left and right buffer. Note samples can be
920 // either 1 or 2 bytes
921 if(_bytesPerSample == 1)
922 {
923 for (uint32_t i = 0; i < bytesRequested; i++)
924 {
925 outDataLeft[i] = _tempData[2 * i];
926 outDataRight[i] = _tempData[(2 * i) + 1];
927 }
928 }
929 else if(_bytesPerSample == 2)
930 {
931 int16_t* sampleData = reinterpret_cast<int16_t*>(_tempData);
932 int16_t* outLeft = reinterpret_cast<int16_t*>(outDataLeft);
933 int16_t* outRight = reinterpret_cast<int16_t*>(
934 outDataRight);
935
936 // Bytes requested to samples requested.
937 uint32_t sampleCount = bytesRequested >> 1;
938 for (uint32_t i = 0; i < sampleCount; i++)
939 {
940 outLeft[i] = sampleData[2 * i];
941 outRight[i] = sampleData[(2 * i) + 1];
942 }
943 } else {
944 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
945 "ReadWavStereoData: unsupported sample size %d!",
946 _bytesPerSample);
947 assert(false);
948 return -1;
949 }
950 return bytesRequested;
951 }
952
ReadWavData(InStream & wav,uint8_t * buffer,const uint32_t dataLengthInBytes)953 int32_t ModuleFileUtility::ReadWavData(
954 InStream& wav,
955 uint8_t* buffer,
956 const uint32_t dataLengthInBytes)
957 {
958 WEBRTC_TRACE(
959 kTraceStream,
960 kTraceFile,
961 _id,
962 "ModuleFileUtility::ReadWavData(wav= 0x%x, buffer= 0x%x, dataLen= %ld)",
963 &wav,
964 buffer,
965 dataLengthInBytes);
966
967
968 if(buffer == NULL)
969 {
970 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
971 "ReadWavDataAsMono: output buffer NULL!");
972 return -1;
973 }
974
975 // Make sure that a read won't return too few samples.
976 // TODO (hellner): why not read the remaining bytes needed from the start
977 // of the file?
978 if((_dataSize - _readPos) < (int32_t)dataLengthInBytes)
979 {
980 // Rewind() being -1 may be due to the file not supposed to be looped.
981 if(wav.Rewind() == -1)
982 {
983 _reading = false;
984 return 0;
985 }
986 if(InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1)
987 {
988 _reading = false;
989 return -1;
990 }
991 }
992
993 int32_t bytesRead = wav.Read(buffer, dataLengthInBytes);
994 if(bytesRead < 0)
995 {
996 _reading = false;
997 return -1;
998 }
999
1000 // This should never happen due to earlier sanity checks.
1001 // TODO (hellner): change to an assert and fail here since this should
1002 // never happen...
1003 if(bytesRead < (int32_t)dataLengthInBytes)
1004 {
1005 if((wav.Rewind() == -1) ||
1006 (InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1))
1007 {
1008 _reading = false;
1009 return -1;
1010 }
1011 else
1012 {
1013 bytesRead = wav.Read(buffer, dataLengthInBytes);
1014 if(bytesRead < (int32_t)dataLengthInBytes)
1015 {
1016 _reading = false;
1017 return -1;
1018 }
1019 }
1020 }
1021
1022 _readPos += bytesRead;
1023
1024 // TODO (hellner): Why is dataLengthInBytes let dictate the number of bytes
1025 // to read when exactly 10ms should be read?!
1026 _playoutPositionMs += 10;
1027 if((_stopPointInMs > 0) &&
1028 (_playoutPositionMs >= _stopPointInMs))
1029 {
1030 if((wav.Rewind() == -1) ||
1031 (InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1))
1032 {
1033 _reading = false;
1034 }
1035 }
1036 return bytesRead;
1037 }
1038
InitWavWriting(OutStream & wav,const CodecInst & codecInst)1039 int32_t ModuleFileUtility::InitWavWriting(OutStream& wav,
1040 const CodecInst& codecInst)
1041 {
1042
1043 if(set_codec_info(codecInst) != 0)
1044 {
1045 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1046 "codecInst identifies unsupported codec!");
1047 return -1;
1048 }
1049 _writing = false;
1050 uint32_t channels = (codecInst.channels == 0) ?
1051 1 : codecInst.channels;
1052
1053 if(STR_CASE_CMP(codecInst.plname, "PCMU") == 0)
1054 {
1055 _bytesPerSample = 1;
1056 if(WriteWavHeader(wav, 8000, _bytesPerSample, channels,
1057 kWaveFormatMuLaw, 0) == -1)
1058 {
1059 return -1;
1060 }
1061 }else if(STR_CASE_CMP(codecInst.plname, "PCMA") == 0)
1062 {
1063 _bytesPerSample = 1;
1064 if(WriteWavHeader(wav, 8000, _bytesPerSample, channels, kWaveFormatALaw,
1065 0) == -1)
1066 {
1067 return -1;
1068 }
1069 }
1070 else if(STR_CASE_CMP(codecInst.plname, "L16") == 0)
1071 {
1072 _bytesPerSample = 2;
1073 if(WriteWavHeader(wav, codecInst.plfreq, _bytesPerSample, channels,
1074 kWaveFormatPcm, 0) == -1)
1075 {
1076 return -1;
1077 }
1078 }
1079 else
1080 {
1081 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1082 "codecInst identifies unsupported codec for WAV file!");
1083 return -1;
1084 }
1085 _writing = true;
1086 _bytesWritten = 0;
1087 return 0;
1088 }
1089
WriteWavData(OutStream & out,const int8_t * buffer,const uint32_t dataLength)1090 int32_t ModuleFileUtility::WriteWavData(OutStream& out,
1091 const int8_t* buffer,
1092 const uint32_t dataLength)
1093 {
1094 WEBRTC_TRACE(
1095 kTraceStream,
1096 kTraceFile,
1097 _id,
1098 "ModuleFileUtility::WriteWavData(out= 0x%x, buf= 0x%x, dataLen= %d)",
1099 &out,
1100 buffer,
1101 dataLength);
1102
1103 if(buffer == NULL)
1104 {
1105 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1106 "WriteWavData: input buffer NULL!");
1107 return -1;
1108 }
1109
1110 if(!out.Write(buffer, dataLength))
1111 {
1112 return -1;
1113 }
1114 _bytesWritten += dataLength;
1115 return dataLength;
1116 }
1117
1118
WriteWavHeader(OutStream & wav,const uint32_t freq,const uint32_t bytesPerSample,const uint32_t channels,const uint32_t format,const uint32_t lengthInBytes)1119 int32_t ModuleFileUtility::WriteWavHeader(
1120 OutStream& wav,
1121 const uint32_t freq,
1122 const uint32_t bytesPerSample,
1123 const uint32_t channels,
1124 const uint32_t format,
1125 const uint32_t lengthInBytes)
1126 {
1127
1128 // Frame size in bytes for 10 ms of audio.
1129 // TODO (hellner): 44.1 kHz has 440 samples frame size. Doesn't seem to
1130 // be taken into consideration here!
1131 int32_t frameSize = (freq / 100) * bytesPerSample * channels;
1132
1133 // Calculate the number of full frames that the wave file contain.
1134 const int32_t dataLengthInBytes = frameSize *
1135 (lengthInBytes / frameSize);
1136
1137 int8_t tmpStr[4];
1138 int8_t tmpChar;
1139 uint32_t tmpLong;
1140
1141 memcpy(tmpStr, "RIFF", 4);
1142 wav.Write(tmpStr, 4);
1143
1144 tmpLong = dataLengthInBytes + 36;
1145 tmpChar = (int8_t)(tmpLong);
1146 wav.Write(&tmpChar, 1);
1147 tmpChar = (int8_t)(tmpLong >> 8);
1148 wav.Write(&tmpChar, 1);
1149 tmpChar = (int8_t)(tmpLong >> 16);
1150 wav.Write(&tmpChar, 1);
1151 tmpChar = (int8_t)(tmpLong >> 24);
1152 wav.Write(&tmpChar, 1);
1153
1154 memcpy(tmpStr, "WAVE", 4);
1155 wav.Write(tmpStr, 4);
1156
1157 memcpy(tmpStr, "fmt ", 4);
1158 wav.Write(tmpStr, 4);
1159
1160 tmpChar = 16;
1161 wav.Write(&tmpChar, 1);
1162 tmpChar = 0;
1163 wav.Write(&tmpChar, 1);
1164 tmpChar = 0;
1165 wav.Write(&tmpChar, 1);
1166 tmpChar = 0;
1167 wav.Write(&tmpChar, 1);
1168
1169 tmpChar = (int8_t)(format);
1170 wav.Write(&tmpChar, 1);
1171 tmpChar = 0;
1172 wav.Write(&tmpChar, 1);
1173
1174 tmpChar = (int8_t)(channels);
1175 wav.Write(&tmpChar, 1);
1176 tmpChar = 0;
1177 wav.Write(&tmpChar, 1);
1178
1179 tmpLong = freq;
1180 tmpChar = (int8_t)(tmpLong);
1181 wav.Write(&tmpChar, 1);
1182 tmpChar = (int8_t)(tmpLong >> 8);
1183 wav.Write(&tmpChar, 1);
1184 tmpChar = (int8_t)(tmpLong >> 16);
1185 wav.Write(&tmpChar, 1);
1186 tmpChar = (int8_t)(tmpLong >> 24);
1187 wav.Write(&tmpChar, 1);
1188
1189 // nAverageBytesPerSec = Sample rate * Bytes per sample * Channels
1190 tmpLong = bytesPerSample * freq * channels;
1191 tmpChar = (int8_t)(tmpLong);
1192 wav.Write(&tmpChar, 1);
1193 tmpChar = (int8_t)(tmpLong >> 8);
1194 wav.Write(&tmpChar, 1);
1195 tmpChar = (int8_t)(tmpLong >> 16);
1196 wav.Write(&tmpChar, 1);
1197 tmpChar = (int8_t)(tmpLong >> 24);
1198 wav.Write(&tmpChar, 1);
1199
1200 // nBlockAlign = Bytes per sample * Channels
1201 tmpChar = (int8_t)(bytesPerSample * channels);
1202 wav.Write(&tmpChar, 1);
1203 tmpChar = 0;
1204 wav.Write(&tmpChar, 1);
1205
1206 tmpChar = (int8_t)(bytesPerSample*8);
1207 wav.Write(&tmpChar, 1);
1208 tmpChar = 0;
1209 wav.Write(&tmpChar, 1);
1210
1211 memcpy(tmpStr, "data", 4);
1212 wav.Write(tmpStr, 4);
1213
1214 tmpLong = dataLengthInBytes;
1215 tmpChar = (int8_t)(tmpLong);
1216 wav.Write(&tmpChar, 1);
1217 tmpChar = (int8_t)(tmpLong >> 8);
1218 wav.Write(&tmpChar, 1);
1219 tmpChar = (int8_t)(tmpLong >> 16);
1220 wav.Write(&tmpChar, 1);
1221 tmpChar = (int8_t)(tmpLong >> 24);
1222 wav.Write(&tmpChar, 1);
1223
1224 return 0;
1225 }
1226
UpdateWavHeader(OutStream & wav)1227 int32_t ModuleFileUtility::UpdateWavHeader(OutStream& wav)
1228 {
1229 int32_t res = -1;
1230 if(wav.Rewind() == -1)
1231 {
1232 return -1;
1233 }
1234 uint32_t channels = (codec_info_.channels == 0) ?
1235 1 : codec_info_.channels;
1236
1237 if(STR_CASE_CMP(codec_info_.plname, "L16") == 0)
1238 {
1239 res = WriteWavHeader(wav, codec_info_.plfreq, 2, channels,
1240 kWaveFormatPcm, _bytesWritten);
1241 } else if(STR_CASE_CMP(codec_info_.plname, "PCMU") == 0) {
1242 res = WriteWavHeader(wav, 8000, 1, channels, kWaveFormatMuLaw,
1243 _bytesWritten);
1244 } else if(STR_CASE_CMP(codec_info_.plname, "PCMA") == 0) {
1245 res = WriteWavHeader(wav, 8000, 1, channels, kWaveFormatALaw,
1246 _bytesWritten);
1247 } else {
1248 // Allow calling this API even if not writing to a WAVE file.
1249 // TODO (hellner): why?!
1250 return 0;
1251 }
1252 return res;
1253 }
1254
1255
InitPreEncodedReading(InStream & in,const CodecInst & cinst)1256 int32_t ModuleFileUtility::InitPreEncodedReading(InStream& in,
1257 const CodecInst& cinst)
1258 {
1259
1260 uint8_t preEncodedID;
1261 in.Read(&preEncodedID, 1);
1262
1263 MediaFileUtility_CodecType codecType =
1264 (MediaFileUtility_CodecType)preEncodedID;
1265
1266 if(set_codec_info(cinst) != 0)
1267 {
1268 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1269 "Pre-encoded file send codec mismatch!");
1270 return -1;
1271 }
1272 if(codecType != _codecId)
1273 {
1274 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1275 "Pre-encoded file format codec mismatch!");
1276 return -1;
1277 }
1278 memcpy(&codec_info_,&cinst,sizeof(CodecInst));
1279 _reading = true;
1280 return 0;
1281 }
1282
ReadPreEncodedData(InStream & in,int8_t * outData,const uint32_t bufferSize)1283 int32_t ModuleFileUtility::ReadPreEncodedData(
1284 InStream& in,
1285 int8_t* outData,
1286 const uint32_t bufferSize)
1287 {
1288 WEBRTC_TRACE(
1289 kTraceStream,
1290 kTraceFile,
1291 _id,
1292 "ModuleFileUtility::ReadPreEncodedData(in= 0x%x, outData= 0x%x,\
1293 bufferSize= %d)",
1294 &in,
1295 outData,
1296 bufferSize);
1297
1298 if(outData == NULL)
1299 {
1300 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "output buffer NULL");
1301 }
1302
1303 uint32_t frameLen;
1304 uint8_t buf[64];
1305 // Each frame has a two byte header containing the frame length.
1306 int32_t res = in.Read(buf, 2);
1307 if(res != 2)
1308 {
1309 if(!in.Rewind())
1310 {
1311 // The first byte is the codec identifier.
1312 in.Read(buf, 1);
1313 res = in.Read(buf, 2);
1314 }
1315 else
1316 {
1317 return -1;
1318 }
1319 }
1320 frameLen = buf[0] + buf[1] * 256;
1321 if(bufferSize < frameLen)
1322 {
1323 WEBRTC_TRACE(
1324 kTraceError,
1325 kTraceFile,
1326 _id,
1327 "buffer not large enough to read %d bytes of pre-encoded data!",
1328 frameLen);
1329 return -1;
1330 }
1331 return in.Read(outData, frameLen);
1332 }
1333
InitPreEncodedWriting(OutStream & out,const CodecInst & codecInst)1334 int32_t ModuleFileUtility::InitPreEncodedWriting(
1335 OutStream& out,
1336 const CodecInst& codecInst)
1337 {
1338
1339 if(set_codec_info(codecInst) != 0)
1340 {
1341 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "CodecInst not recognized!");
1342 return -1;
1343 }
1344 _writing = true;
1345 _bytesWritten = 1;
1346 out.Write(&_codecId, 1);
1347 return 0;
1348 }
1349
WritePreEncodedData(OutStream & out,const int8_t * buffer,const uint32_t dataLength)1350 int32_t ModuleFileUtility::WritePreEncodedData(
1351 OutStream& out,
1352 const int8_t* buffer,
1353 const uint32_t dataLength)
1354 {
1355 WEBRTC_TRACE(
1356 kTraceStream,
1357 kTraceFile,
1358 _id,
1359 "ModuleFileUtility::WritePreEncodedData(out= 0x%x, inData= 0x%x,\
1360 dataLen= %d)",
1361 &out,
1362 buffer,
1363 dataLength);
1364
1365 if(buffer == NULL)
1366 {
1367 WEBRTC_TRACE(kTraceError, kTraceFile, _id,"buffer NULL");
1368 }
1369
1370 int32_t bytesWritten = 0;
1371 // The first two bytes is the size of the frame.
1372 int16_t lengthBuf;
1373 lengthBuf = (int16_t)dataLength;
1374 if(!out.Write(&lengthBuf, 2))
1375 {
1376 return -1;
1377 }
1378 bytesWritten = 2;
1379
1380 if(!out.Write(buffer, dataLength))
1381 {
1382 return -1;
1383 }
1384 bytesWritten += dataLength;
1385 return bytesWritten;
1386 }
1387
InitCompressedReading(InStream & in,const uint32_t start,const uint32_t stop)1388 int32_t ModuleFileUtility::InitCompressedReading(
1389 InStream& in,
1390 const uint32_t start,
1391 const uint32_t stop)
1392 {
1393 WEBRTC_TRACE(
1394 kTraceDebug,
1395 kTraceFile,
1396 _id,
1397 "ModuleFileUtility::InitCompressedReading(in= 0x%x, start= %d,\
1398 stop= %d)",
1399 &in,
1400 start,
1401 stop);
1402
1403 #if defined(WEBRTC_CODEC_AMR) || defined(WEBRTC_CODEC_AMRWB) || \
1404 defined(WEBRTC_CODEC_ILBC)
1405 int16_t read_len = 0;
1406 #endif
1407 _codecId = kCodecNoCodec;
1408 _playoutPositionMs = 0;
1409 _reading = false;
1410
1411 _startPointInMs = start;
1412 _stopPointInMs = stop;
1413
1414 #ifdef WEBRTC_CODEC_AMR
1415 int32_t AMRmode2bytes[9]={12,13,15,17,19,20,26,31,5};
1416 #endif
1417 #ifdef WEBRTC_CODEC_AMRWB
1418 int32_t AMRWBmode2bytes[10]={17,23,32,36,40,46,50,58,60,6};
1419 #endif
1420
1421 // Read the codec name
1422 int32_t cnt = 0;
1423 char buf[64];
1424 do
1425 {
1426 in.Read(&buf[cnt++], 1);
1427 } while ((buf[cnt-1] != '\n') && (64 > cnt));
1428
1429 if(cnt==64)
1430 {
1431 return -1;
1432 } else {
1433 buf[cnt]=0;
1434 }
1435
1436 #ifdef WEBRTC_CODEC_AMR
1437 if(!strcmp("#!AMR\n", buf))
1438 {
1439 strcpy(codec_info_.plname, "amr");
1440 codec_info_.pacsize = 160;
1441 _codecId = kCodecAmr;
1442 codec_info_.pltype = 112;
1443 codec_info_.rate = 12200;
1444 codec_info_.plfreq = 8000;
1445 codec_info_.channels = 1;
1446
1447 int16_t mode = 0;
1448 if(_startPointInMs > 0)
1449 {
1450 while (_playoutPositionMs <= _startPointInMs)
1451 {
1452 // First read byte contain the AMR mode.
1453 read_len = in.Read(buf, 1);
1454 if(read_len != 1)
1455 {
1456 return -1;
1457 }
1458
1459 mode = (buf[0]>>3)&0xF;
1460 if((mode < 0) || (mode > 8))
1461 {
1462 if(mode != 15)
1463 {
1464 return -1;
1465 }
1466 }
1467 if(mode != 15)
1468 {
1469 read_len = in.Read(&buf[1], AMRmode2bytes[mode]);
1470 if(read_len != AMRmode2bytes[mode])
1471 {
1472 return -1;
1473 }
1474 }
1475 _playoutPositionMs += 20;
1476 }
1477 }
1478 }
1479 #endif
1480 #ifdef WEBRTC_CODEC_AMRWB
1481 if(!strcmp("#!AMRWB\n", buf))
1482 {
1483 strcpy(codec_info_.plname, "amr-wb");
1484 codec_info_.pacsize = 320;
1485 _codecId = kCodecAmrWb;
1486 codec_info_.pltype = 120;
1487 codec_info_.rate = 20000;
1488 codec_info_.plfreq = 16000;
1489 codec_info_.channels = 1;
1490
1491 int16_t mode = 0;
1492 if(_startPointInMs > 0)
1493 {
1494 while (_playoutPositionMs <= _startPointInMs)
1495 {
1496 // First read byte contain the AMR mode.
1497 read_len = in.Read(buf, 1);
1498 if(read_len != 1)
1499 {
1500 return -1;
1501 }
1502
1503 mode = (buf[0]>>3)&0xF;
1504 if((mode < 0) || (mode > 9))
1505 {
1506 if(mode != 15)
1507 {
1508 return -1;
1509 }
1510 }
1511 if(mode != 15)
1512 {
1513 read_len = in.Read(&buf[1], AMRWBmode2bytes[mode]);
1514 if(read_len != AMRWBmode2bytes[mode])
1515 {
1516 return -1;
1517 }
1518 }
1519 _playoutPositionMs += 20;
1520 }
1521 }
1522 }
1523 #endif
1524 #ifdef WEBRTC_CODEC_ILBC
1525 if(!strcmp("#!iLBC20\n", buf))
1526 {
1527 codec_info_.pltype = 102;
1528 strcpy(codec_info_.plname, "ilbc");
1529 codec_info_.plfreq = 8000;
1530 codec_info_.pacsize = 160;
1531 codec_info_.channels = 1;
1532 codec_info_.rate = 13300;
1533 _codecId = kCodecIlbc20Ms;
1534
1535 if(_startPointInMs > 0)
1536 {
1537 while (_playoutPositionMs <= _startPointInMs)
1538 {
1539 read_len = in.Read(buf, 38);
1540 if(read_len == 38)
1541 {
1542 _playoutPositionMs += 20;
1543 }
1544 else
1545 {
1546 return -1;
1547 }
1548 }
1549 }
1550 }
1551
1552 if(!strcmp("#!iLBC30\n", buf))
1553 {
1554 codec_info_.pltype = 102;
1555 strcpy(codec_info_.plname, "ilbc");
1556 codec_info_.plfreq = 8000;
1557 codec_info_.pacsize = 240;
1558 codec_info_.channels = 1;
1559 codec_info_.rate = 13300;
1560 _codecId = kCodecIlbc30Ms;
1561
1562 if(_startPointInMs > 0)
1563 {
1564 while (_playoutPositionMs <= _startPointInMs)
1565 {
1566 read_len = in.Read(buf, 50);
1567 if(read_len == 50)
1568 {
1569 _playoutPositionMs += 20;
1570 }
1571 else
1572 {
1573 return -1;
1574 }
1575 }
1576 }
1577 }
1578 #endif
1579 if(_codecId == kCodecNoCodec)
1580 {
1581 return -1;
1582 }
1583 _reading = true;
1584 return 0;
1585 }
1586
ReadCompressedData(InStream & in,int8_t * outData,uint32_t bufferSize)1587 int32_t ModuleFileUtility::ReadCompressedData(InStream& in,
1588 int8_t* outData,
1589 uint32_t bufferSize)
1590 {
1591 WEBRTC_TRACE(
1592 kTraceStream,
1593 kTraceFile,
1594 _id,
1595 "ModuleFileUtility::ReadCompressedData(in=0x%x, outData=0x%x,\
1596 bytes=%ld)",
1597 &in,
1598 outData,
1599 bufferSize);
1600
1601 #ifdef WEBRTC_CODEC_AMR
1602 uint32_t AMRmode2bytes[9]={12,13,15,17,19,20,26,31,5};
1603 #endif
1604 #ifdef WEBRTC_CODEC_AMRWB
1605 uint32_t AMRWBmode2bytes[10]={17,23,32,36,40,46,50,58,60,6};
1606 #endif
1607 uint32_t bytesRead = 0;
1608
1609 if(! _reading)
1610 {
1611 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "not currently reading!");
1612 return -1;
1613 }
1614
1615 #ifdef WEBRTC_CODEC_AMR
1616 if(_codecId == kCodecAmr)
1617 {
1618 int32_t res = in.Read(outData, 1);
1619 if(res != 1)
1620 {
1621 if(!in.Rewind())
1622 {
1623 InitCompressedReading(in, _startPointInMs, _stopPointInMs);
1624 res = in.Read(outData, 1);
1625 if(res != 1)
1626 {
1627 _reading = false;
1628 return -1;
1629 }
1630 }
1631 else
1632 {
1633 _reading = false;
1634 return -1;
1635 }
1636 }
1637 const int16_t mode = (outData[0]>>3)&0xF;
1638 if((mode < 0) ||
1639 (mode > 8))
1640 {
1641 if(mode != 15)
1642 {
1643 return -1;
1644 }
1645 }
1646 if(mode != 15)
1647 {
1648 if(bufferSize < AMRmode2bytes[mode] + 1)
1649 {
1650 WEBRTC_TRACE(
1651 kTraceError,
1652 kTraceFile,
1653 _id,
1654 "output buffer is too short to read AMR compressed data.");
1655 assert(false);
1656 return -1;
1657 }
1658 bytesRead = in.Read(&outData[1], AMRmode2bytes[mode]);
1659 if(bytesRead != AMRmode2bytes[mode])
1660 {
1661 _reading = false;
1662 return -1;
1663 }
1664 // Count the mode byte to bytes read.
1665 bytesRead++;
1666 }
1667 else
1668 {
1669 bytesRead = 1;
1670 }
1671 }
1672 #endif
1673 #ifdef WEBRTC_CODEC_AMRWB
1674 if(_codecId == kCodecAmrWb)
1675 {
1676 int32_t res = in.Read(outData, 1);
1677 if(res != 1)
1678 {
1679 if(!in.Rewind())
1680 {
1681 InitCompressedReading(in, _startPointInMs, _stopPointInMs);
1682 res = in.Read(outData, 1);
1683 if(res != 1)
1684 {
1685 _reading = false;
1686 return -1;
1687 }
1688 }
1689 else
1690 {
1691 _reading = false;
1692 return -1;
1693 }
1694 }
1695 int16_t mode = (outData[0]>>3)&0xF;
1696 if((mode < 0) ||
1697 (mode > 8))
1698 {
1699 if(mode != 15)
1700 {
1701 return -1;
1702 }
1703 }
1704 if(mode != 15)
1705 {
1706 if(bufferSize < AMRWBmode2bytes[mode] + 1)
1707 {
1708 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1709 "output buffer is too short to read AMRWB\
1710 compressed.");
1711 assert(false);
1712 return -1;
1713 }
1714 bytesRead = in.Read(&outData[1], AMRWBmode2bytes[mode]);
1715 if(bytesRead != AMRWBmode2bytes[mode])
1716 {
1717 _reading = false;
1718 return -1;
1719 }
1720 bytesRead++;
1721 }
1722 else
1723 {
1724 bytesRead = 1;
1725 }
1726 }
1727 #endif
1728 #ifdef WEBRTC_CODEC_ILBC
1729 if((_codecId == kCodecIlbc20Ms) ||
1730 (_codecId == kCodecIlbc30Ms))
1731 {
1732 uint32_t byteSize = 0;
1733 if(_codecId == kCodecIlbc30Ms)
1734 {
1735 byteSize = 50;
1736 }
1737 if(_codecId == kCodecIlbc20Ms)
1738 {
1739 byteSize = 38;
1740 }
1741 if(bufferSize < byteSize)
1742 {
1743 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1744 "output buffer is too short to read ILBC compressed\
1745 data.");
1746 assert(false);
1747 return -1;
1748 }
1749
1750 bytesRead = in.Read(outData, byteSize);
1751 if(bytesRead != byteSize)
1752 {
1753 if(!in.Rewind())
1754 {
1755 InitCompressedReading(in, _startPointInMs, _stopPointInMs);
1756 bytesRead = in.Read(outData, byteSize);
1757 if(bytesRead != byteSize)
1758 {
1759 _reading = false;
1760 return -1;
1761 }
1762 }
1763 else
1764 {
1765 _reading = false;
1766 return -1;
1767 }
1768 }
1769 }
1770 #endif
1771 if(bytesRead == 0)
1772 {
1773 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1774 "ReadCompressedData() no bytes read, codec not supported");
1775 return -1;
1776 }
1777
1778 _playoutPositionMs += 20;
1779 if((_stopPointInMs > 0) &&
1780 (_playoutPositionMs >= _stopPointInMs))
1781 {
1782 if(!in.Rewind())
1783 {
1784 InitCompressedReading(in, _startPointInMs, _stopPointInMs);
1785 }
1786 else
1787 {
1788 _reading = false;
1789 }
1790 }
1791 return bytesRead;
1792 }
1793
InitCompressedWriting(OutStream & out,const CodecInst & codecInst)1794 int32_t ModuleFileUtility::InitCompressedWriting(
1795 OutStream& out,
1796 const CodecInst& codecInst)
1797 {
1798 WEBRTC_TRACE(kTraceDebug, kTraceFile, _id,
1799 "ModuleFileUtility::InitCompressedWriting(out= 0x%x,\
1800 codecName= %s)",
1801 &out, codecInst.plname);
1802
1803 _writing = false;
1804
1805 #ifdef WEBRTC_CODEC_AMR
1806 if(STR_CASE_CMP(codecInst.plname, "amr") == 0)
1807 {
1808 if(codecInst.pacsize == 160)
1809 {
1810 memcpy(&codec_info_,&codecInst,sizeof(CodecInst));
1811 _codecId = kCodecAmr;
1812 out.Write("#!AMR\n",6);
1813 _writing = true;
1814 return 0;
1815 }
1816 }
1817 #endif
1818 #ifdef WEBRTC_CODEC_AMRWB
1819 if(STR_CASE_CMP(codecInst.plname, "amr-wb") == 0)
1820 {
1821 if(codecInst.pacsize == 320)
1822 {
1823 memcpy(&codec_info_,&codecInst,sizeof(CodecInst));
1824 _codecId = kCodecAmrWb;
1825 out.Write("#!AMRWB\n",8);
1826 _writing = true;
1827 return 0;
1828 }
1829 }
1830 #endif
1831 #ifdef WEBRTC_CODEC_ILBC
1832 if(STR_CASE_CMP(codecInst.plname, "ilbc") == 0)
1833 {
1834 if(codecInst.pacsize == 160)
1835 {
1836 _codecId = kCodecIlbc20Ms;
1837 out.Write("#!iLBC20\n",9);
1838 }
1839 else if(codecInst.pacsize == 240)
1840 {
1841 _codecId = kCodecIlbc30Ms;
1842 out.Write("#!iLBC30\n",9);
1843 }
1844 else
1845 {
1846 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1847 "codecInst defines unsupported compression codec!");
1848 return -1;
1849 }
1850 memcpy(&codec_info_,&codecInst,sizeof(CodecInst));
1851 _writing = true;
1852 return 0;
1853 }
1854 #endif
1855
1856 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1857 "codecInst defines unsupported compression codec!");
1858 return -1;
1859 }
1860
WriteCompressedData(OutStream & out,const int8_t * buffer,const uint32_t dataLength)1861 int32_t ModuleFileUtility::WriteCompressedData(
1862 OutStream& out,
1863 const int8_t* buffer,
1864 const uint32_t dataLength)
1865 {
1866 WEBRTC_TRACE(
1867 kTraceStream,
1868 kTraceFile,
1869 _id,
1870 "ModuleFileUtility::WriteCompressedData(out= 0x%x, buf= 0x%x,\
1871 dataLen= %d)",
1872 &out,
1873 buffer,
1874 dataLength);
1875
1876 if(buffer == NULL)
1877 {
1878 WEBRTC_TRACE(kTraceError, kTraceFile, _id,"buffer NULL");
1879 }
1880
1881 if(!out.Write(buffer, dataLength))
1882 {
1883 return -1;
1884 }
1885 return dataLength;
1886 }
1887
InitPCMReading(InStream & pcm,const uint32_t start,const uint32_t stop,uint32_t freq)1888 int32_t ModuleFileUtility::InitPCMReading(InStream& pcm,
1889 const uint32_t start,
1890 const uint32_t stop,
1891 uint32_t freq)
1892 {
1893 WEBRTC_TRACE(
1894 kTraceInfo,
1895 kTraceFile,
1896 _id,
1897 "ModuleFileUtility::InitPCMReading(pcm= 0x%x, start=%d, stop=%d,\
1898 freq=%d)",
1899 &pcm,
1900 start,
1901 stop,
1902 freq);
1903
1904 int8_t dummy[320];
1905 int32_t read_len;
1906
1907 _playoutPositionMs = 0;
1908 _startPointInMs = start;
1909 _stopPointInMs = stop;
1910 _reading = false;
1911
1912 if(freq == 8000)
1913 {
1914 strcpy(codec_info_.plname, "L16");
1915 codec_info_.pltype = -1;
1916 codec_info_.plfreq = 8000;
1917 codec_info_.pacsize = 160;
1918 codec_info_.channels = 1;
1919 codec_info_.rate = 128000;
1920 _codecId = kCodecL16_8Khz;
1921 }
1922 else if(freq == 16000)
1923 {
1924 strcpy(codec_info_.plname, "L16");
1925 codec_info_.pltype = -1;
1926 codec_info_.plfreq = 16000;
1927 codec_info_.pacsize = 320;
1928 codec_info_.channels = 1;
1929 codec_info_.rate = 256000;
1930 _codecId = kCodecL16_16kHz;
1931 }
1932 else if(freq == 32000)
1933 {
1934 strcpy(codec_info_.plname, "L16");
1935 codec_info_.pltype = -1;
1936 codec_info_.plfreq = 32000;
1937 codec_info_.pacsize = 320;
1938 codec_info_.channels = 1;
1939 codec_info_.rate = 512000;
1940 _codecId = kCodecL16_32Khz;
1941 }
1942
1943 // Readsize for 10ms of audio data (2 bytes per sample).
1944 _readSizeBytes = 2 * codec_info_. plfreq / 100;
1945 if(_startPointInMs > 0)
1946 {
1947 while (_playoutPositionMs < _startPointInMs)
1948 {
1949 read_len = pcm.Read(dummy, _readSizeBytes);
1950 if(read_len == _readSizeBytes)
1951 {
1952 _playoutPositionMs += 10;
1953 }
1954 else // Must have reached EOF before start position!
1955 {
1956 return -1;
1957 }
1958 }
1959 }
1960 _reading = true;
1961 return 0;
1962 }
1963
ReadPCMData(InStream & pcm,int8_t * outData,uint32_t bufferSize)1964 int32_t ModuleFileUtility::ReadPCMData(InStream& pcm,
1965 int8_t* outData,
1966 uint32_t bufferSize)
1967 {
1968 WEBRTC_TRACE(
1969 kTraceStream,
1970 kTraceFile,
1971 _id,
1972 "ModuleFileUtility::ReadPCMData(pcm= 0x%x, outData= 0x%x, bufSize= %d)",
1973 &pcm,
1974 outData,
1975 bufferSize);
1976
1977 if(outData == NULL)
1978 {
1979 WEBRTC_TRACE(kTraceError, kTraceFile, _id,"buffer NULL");
1980 }
1981
1982 // Readsize for 10ms of audio data (2 bytes per sample).
1983 uint32_t bytesRequested = 2 * codec_info_.plfreq / 100;
1984 if(bufferSize < bytesRequested)
1985 {
1986 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1987 "ReadPCMData: buffer not long enough for a 10ms frame.");
1988 assert(false);
1989 return -1;
1990 }
1991
1992 uint32_t bytesRead = pcm.Read(outData, bytesRequested);
1993 if(bytesRead < bytesRequested)
1994 {
1995 if(pcm.Rewind() == -1)
1996 {
1997 _reading = false;
1998 }
1999 else
2000 {
2001 if(InitPCMReading(pcm, _startPointInMs, _stopPointInMs,
2002 codec_info_.plfreq) == -1)
2003 {
2004 _reading = false;
2005 }
2006 else
2007 {
2008 int32_t rest = bytesRequested - bytesRead;
2009 int32_t len = pcm.Read(&(outData[bytesRead]), rest);
2010 if(len == rest)
2011 {
2012 bytesRead += len;
2013 }
2014 else
2015 {
2016 _reading = false;
2017 }
2018 }
2019 if(bytesRead <= 0)
2020 {
2021 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
2022 "ReadPCMData: Failed to rewind audio file.");
2023 return -1;
2024 }
2025 }
2026 }
2027
2028 if(bytesRead <= 0)
2029 {
2030 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
2031 "ReadPCMData: end of file");
2032 return -1;
2033 }
2034 _playoutPositionMs += 10;
2035 if(_stopPointInMs && _playoutPositionMs >= _stopPointInMs)
2036 {
2037 if(!pcm.Rewind())
2038 {
2039 if(InitPCMReading(pcm, _startPointInMs, _stopPointInMs,
2040 codec_info_.plfreq) == -1)
2041 {
2042 _reading = false;
2043 }
2044 }
2045 }
2046 return bytesRead;
2047 }
2048
InitPCMWriting(OutStream & out,uint32_t freq)2049 int32_t ModuleFileUtility::InitPCMWriting(OutStream& out, uint32_t freq)
2050 {
2051
2052 if(freq == 8000)
2053 {
2054 strcpy(codec_info_.plname, "L16");
2055 codec_info_.pltype = -1;
2056 codec_info_.plfreq = 8000;
2057 codec_info_.pacsize = 160;
2058 codec_info_.channels = 1;
2059 codec_info_.rate = 128000;
2060
2061 _codecId = kCodecL16_8Khz;
2062 }
2063 else if(freq == 16000)
2064 {
2065 strcpy(codec_info_.plname, "L16");
2066 codec_info_.pltype = -1;
2067 codec_info_.plfreq = 16000;
2068 codec_info_.pacsize = 320;
2069 codec_info_.channels = 1;
2070 codec_info_.rate = 256000;
2071
2072 _codecId = kCodecL16_16kHz;
2073 }
2074 else if(freq == 32000)
2075 {
2076 strcpy(codec_info_.plname, "L16");
2077 codec_info_.pltype = -1;
2078 codec_info_.plfreq = 32000;
2079 codec_info_.pacsize = 320;
2080 codec_info_.channels = 1;
2081 codec_info_.rate = 512000;
2082
2083 _codecId = kCodecL16_32Khz;
2084 }
2085 if((_codecId != kCodecL16_8Khz) &&
2086 (_codecId != kCodecL16_16kHz) &&
2087 (_codecId != kCodecL16_32Khz))
2088 {
2089 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
2090 "CodecInst is not 8KHz PCM or 16KHz PCM!");
2091 return -1;
2092 }
2093 _writing = true;
2094 _bytesWritten = 0;
2095 return 0;
2096 }
2097
WritePCMData(OutStream & out,const int8_t * buffer,const uint32_t dataLength)2098 int32_t ModuleFileUtility::WritePCMData(OutStream& out,
2099 const int8_t* buffer,
2100 const uint32_t dataLength)
2101 {
2102 WEBRTC_TRACE(
2103 kTraceStream,
2104 kTraceFile,
2105 _id,
2106 "ModuleFileUtility::WritePCMData(out= 0x%x, buf= 0x%x, dataLen= %d)",
2107 &out,
2108 buffer,
2109 dataLength);
2110
2111 if(buffer == NULL)
2112 {
2113 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "buffer NULL");
2114 }
2115
2116 if(!out.Write(buffer, dataLength))
2117 {
2118 return -1;
2119 }
2120
2121 _bytesWritten += dataLength;
2122 return dataLength;
2123 }
2124
codec_info(CodecInst & codecInst)2125 int32_t ModuleFileUtility::codec_info(CodecInst& codecInst)
2126 {
2127 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
2128 "ModuleFileUtility::codec_info(codecInst= 0x%x)", &codecInst);
2129
2130 if(!_reading && !_writing)
2131 {
2132 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
2133 "CodecInst: not currently reading audio file!");
2134 return -1;
2135 }
2136 memcpy(&codecInst,&codec_info_,sizeof(CodecInst));
2137 return 0;
2138 }
2139
set_codec_info(const CodecInst & codecInst)2140 int32_t ModuleFileUtility::set_codec_info(const CodecInst& codecInst)
2141 {
2142
2143 _codecId = kCodecNoCodec;
2144 if(STR_CASE_CMP(codecInst.plname, "PCMU") == 0)
2145 {
2146 _codecId = kCodecPcmu;
2147 }
2148 else if(STR_CASE_CMP(codecInst.plname, "PCMA") == 0)
2149 {
2150 _codecId = kCodecPcma;
2151 }
2152 else if(STR_CASE_CMP(codecInst.plname, "L16") == 0)
2153 {
2154 if(codecInst.plfreq == 8000)
2155 {
2156 _codecId = kCodecL16_8Khz;
2157 }
2158 else if(codecInst.plfreq == 16000)
2159 {
2160 _codecId = kCodecL16_16kHz;
2161 }
2162 else if(codecInst.plfreq == 32000)
2163 {
2164 _codecId = kCodecL16_32Khz;
2165 }
2166 }
2167 #ifdef WEBRTC_CODEC_AMR
2168 else if(STR_CASE_CMP(codecInst.plname, "amr") == 0)
2169 {
2170 _codecId = kCodecAmr;
2171 }
2172 #endif
2173 #ifdef WEBRTC_CODEC_AMRWB
2174 else if(STR_CASE_CMP(codecInst.plname, "amr-wb") == 0)
2175 {
2176 _codecId = kCodecAmrWb;
2177 }
2178 #endif
2179 #ifdef WEBRTC_CODEC_ILBC
2180 else if(STR_CASE_CMP(codecInst.plname, "ilbc") == 0)
2181 {
2182 if(codecInst.pacsize == 160)
2183 {
2184 _codecId = kCodecIlbc20Ms;
2185 }
2186 else if(codecInst.pacsize == 240)
2187 {
2188 _codecId = kCodecIlbc30Ms;
2189 }
2190 }
2191 #endif
2192 #if(defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
2193 else if(STR_CASE_CMP(codecInst.plname, "isac") == 0)
2194 {
2195 if(codecInst.plfreq == 16000)
2196 {
2197 _codecId = kCodecIsac;
2198 }
2199 else if(codecInst.plfreq == 32000)
2200 {
2201 _codecId = kCodecIsacSwb;
2202 }
2203 }
2204 #endif
2205 #ifdef WEBRTC_CODEC_ISACLC
2206 else if(STR_CASE_CMP(codecInst.plname, "isaclc") == 0)
2207 {
2208 _codecId = kCodecIsacLc;
2209 }
2210 #endif
2211 #ifdef WEBRTC_CODEC_G722
2212 else if(STR_CASE_CMP(codecInst.plname, "G722") == 0)
2213 {
2214 _codecId = kCodecG722;
2215 }
2216 #endif
2217 else if(STR_CASE_CMP(codecInst.plname, "G7221") == 0)
2218 {
2219 #ifdef WEBRTC_CODEC_G722_1
2220 if(codecInst.plfreq == 16000)
2221 {
2222 if(codecInst.rate == 16000)
2223 {
2224 _codecId = kCodecG722_1_16Kbps;
2225 }
2226 else if(codecInst.rate == 24000)
2227 {
2228 _codecId = kCodecG722_1_24Kbps;
2229 }
2230 else if(codecInst.rate == 32000)
2231 {
2232 _codecId = kCodecG722_1_32Kbps;
2233 }
2234 }
2235 #endif
2236 #ifdef WEBRTC_CODEC_G722_1C
2237 if(codecInst.plfreq == 32000)
2238 {
2239 if(codecInst.rate == 48000)
2240 {
2241 _codecId = kCodecG722_1c_48;
2242 }
2243 else if(codecInst.rate == 32000)
2244 {
2245 _codecId = kCodecG722_1c_32;
2246 }
2247 else if(codecInst.rate == 24000)
2248 {
2249 _codecId = kCodecG722_1c_24;
2250 }
2251 }
2252 #endif
2253 }
2254 #ifdef WEBRTC_CODEC_G726
2255 else if(STR_CASE_CMP(codecInst.plname, "G726-40") == 0)
2256 {
2257 _codecId = kCodecG726_40;
2258 }
2259 else if(STR_CASE_CMP(codecInst.plname, "G726-32") == 0)
2260 {
2261 _codecId = kCodecG726_24;
2262 }
2263 else if(STR_CASE_CMP(codecInst.plname, "G726-24") == 0)
2264 {
2265 _codecId = kCodecG726_32;
2266 }
2267 else if(STR_CASE_CMP(codecInst.plname, "G726-16") == 0)
2268 {
2269 _codecId = kCodecG726_16;
2270 }
2271 #endif
2272 #ifdef WEBRTC_CODEC_G729
2273 else if(STR_CASE_CMP(codecInst.plname, "G729") == 0)
2274 {
2275 _codecId = kCodecG729;
2276 }
2277 #endif
2278 #ifdef WEBRTC_CODEC_G729_1
2279 else if(STR_CASE_CMP(codecInst.plname, "G7291") == 0)
2280 {
2281 _codecId = kCodecG729_1;
2282 }
2283 #endif
2284 #ifdef WEBRTC_CODEC_SPEEX
2285 else if(STR_CASE_CMP(codecInst.plname, "speex") == 0)
2286 {
2287 if(codecInst.plfreq == 8000)
2288 {
2289 _codecId = kCodecSpeex8Khz;
2290 }
2291 else if(codecInst.plfreq == 16000)
2292 {
2293 _codecId = kCodecSpeex16Khz;
2294 }
2295 }
2296 #endif
2297 if(_codecId == kCodecNoCodec)
2298 {
2299 return -1;
2300 }
2301 memcpy(&codec_info_, &codecInst, sizeof(CodecInst));
2302 return 0;
2303 }
2304
FileDurationMs(const char * fileName,const FileFormats fileFormat,const uint32_t freqInHz)2305 int32_t ModuleFileUtility::FileDurationMs(const char* fileName,
2306 const FileFormats fileFormat,
2307 const uint32_t freqInHz)
2308 {
2309
2310 if(fileName == NULL)
2311 {
2312 WEBRTC_TRACE(kTraceError, kTraceFile, _id, "filename NULL");
2313 return -1;
2314 }
2315
2316 int32_t time_in_ms = -1;
2317 struct stat file_size;
2318 if(stat(fileName,&file_size) == -1)
2319 {
2320 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
2321 "failed to retrieve file size with stat!");
2322 return -1;
2323 }
2324 FileWrapper* inStreamObj = FileWrapper::Create();
2325 if(inStreamObj == NULL)
2326 {
2327 WEBRTC_TRACE(kTraceMemory, kTraceFile, _id,
2328 "failed to create InStream object!");
2329 return -1;
2330 }
2331 if(inStreamObj->OpenFile(fileName, true) == -1)
2332 {
2333 delete inStreamObj;
2334 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
2335 "failed to open file %s!", fileName);
2336 return -1;
2337 }
2338
2339 switch (fileFormat)
2340 {
2341 case kFileFormatWavFile:
2342 {
2343 if(ReadWavHeader(*inStreamObj) == -1)
2344 {
2345 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
2346 "failed to read WAV file header!");
2347 return -1;
2348 }
2349 time_in_ms = ((file_size.st_size - 44) /
2350 (_wavFormatObj.nAvgBytesPerSec/1000));
2351 break;
2352 }
2353 case kFileFormatPcm16kHzFile:
2354 {
2355 // 16 samples per ms. 2 bytes per sample.
2356 int32_t denominator = 16*2;
2357 time_in_ms = (file_size.st_size)/denominator;
2358 break;
2359 }
2360 case kFileFormatPcm8kHzFile:
2361 {
2362 // 8 samples per ms. 2 bytes per sample.
2363 int32_t denominator = 8*2;
2364 time_in_ms = (file_size.st_size)/denominator;
2365 break;
2366 }
2367 case kFileFormatCompressedFile:
2368 {
2369 int32_t cnt = 0;
2370 int32_t read_len = 0;
2371 char buf[64];
2372 do
2373 {
2374 read_len = inStreamObj->Read(&buf[cnt++], 1);
2375 if(read_len != 1)
2376 {
2377 return -1;
2378 }
2379 } while ((buf[cnt-1] != '\n') && (64 > cnt));
2380
2381 if(cnt == 64)
2382 {
2383 return -1;
2384 }
2385 else
2386 {
2387 buf[cnt] = 0;
2388 }
2389 #ifdef WEBRTC_CODEC_AMR
2390 if(!strcmp("#!AMR\n", buf))
2391 {
2392 uint8_t dummy;
2393 read_len = inStreamObj->Read(&dummy, 1);
2394 if(read_len != 1)
2395 {
2396 return -1;
2397 }
2398
2399 int16_t AMRMode = (dummy>>3)&0xF;
2400
2401 // TODO (hellner): use tables instead of hardcoding like this!
2402 // Additionally, this calculation does not
2403 // take octet alignment into consideration.
2404 switch (AMRMode)
2405 {
2406 // Mode 0: 4.75 kbit/sec -> 95 bits per 20 ms frame.
2407 // 20 ms = 95 bits ->
2408 // file size in bytes * 8 / 95 is the number of
2409 // 20 ms frames in the file ->
2410 // time_in_ms = file size * 8 / 95 * 20
2411 case 0:
2412 time_in_ms = ((file_size.st_size)*160)/95;
2413 break;
2414 // Mode 1: 5.15 kbit/sec -> 103 bits per 20 ms frame.
2415 case 1:
2416 time_in_ms = ((file_size.st_size)*160)/103;
2417 break;
2418 // Mode 2: 5.90 kbit/sec -> 118 bits per 20 ms frame.
2419 case 2:
2420 time_in_ms = ((file_size.st_size)*160)/118;
2421 break;
2422 // Mode 3: 6.70 kbit/sec -> 134 bits per 20 ms frame.
2423 case 3:
2424 time_in_ms = ((file_size.st_size)*160)/134;
2425 break;
2426 // Mode 4: 7.40 kbit/sec -> 148 bits per 20 ms frame.
2427 case 4:
2428 time_in_ms = ((file_size.st_size)*160)/148;
2429 break;
2430 // Mode 5: 7.95 bit/sec -> 159 bits per 20 ms frame.
2431 case 5:
2432 time_in_ms = ((file_size.st_size)*160)/159;
2433 break;
2434 // Mode 6: 10.2 bit/sec -> 204 bits per 20 ms frame.
2435 case 6:
2436 time_in_ms = ((file_size.st_size)*160)/204;
2437 break;
2438 // Mode 7: 12.2 bit/sec -> 244 bits per 20 ms frame.
2439 case 7:
2440 time_in_ms = ((file_size.st_size)*160)/244;
2441 break;
2442 // Mode 8: SID Mode -> 39 bits per 20 ms frame.
2443 case 8:
2444 time_in_ms = ((file_size.st_size)*160)/39;
2445 break;
2446 default:
2447 break;
2448 }
2449 }
2450 #endif
2451 #ifdef WEBRTC_CODEC_AMRWB
2452 if(!strcmp("#!AMRWB\n", buf))
2453 {
2454 uint8_t dummy;
2455 read_len = inStreamObj->Read(&dummy, 1);
2456 if(read_len != 1)
2457 {
2458 return -1;
2459 }
2460
2461 // TODO (hellner): use tables instead of hardcoding like this!
2462 int16_t AMRWBMode = (dummy>>3)&0xF;
2463 switch(AMRWBMode)
2464 {
2465 // Mode 0: 6.6 kbit/sec -> 132 bits per 20 ms frame.
2466 case 0:
2467 time_in_ms = ((file_size.st_size)*160)/132;
2468 break;
2469 // Mode 1: 8.85 kbit/sec -> 177 bits per 20 ms frame.
2470 case 1:
2471 time_in_ms = ((file_size.st_size)*160)/177;
2472 break;
2473 // Mode 2: 12.65 kbit/sec -> 253 bits per 20 ms frame.
2474 case 2:
2475 time_in_ms = ((file_size.st_size)*160)/253;
2476 break;
2477 // Mode 3: 14.25 kbit/sec -> 285 bits per 20 ms frame.
2478 case 3:
2479 time_in_ms = ((file_size.st_size)*160)/285;
2480 break;
2481 // Mode 4: 15.85 kbit/sec -> 317 bits per 20 ms frame.
2482 case 4:
2483 time_in_ms = ((file_size.st_size)*160)/317;
2484 break;
2485 // Mode 5: 18.25 kbit/sec -> 365 bits per 20 ms frame.
2486 case 5:
2487 time_in_ms = ((file_size.st_size)*160)/365;
2488 break;
2489 // Mode 6: 19.85 kbit/sec -> 397 bits per 20 ms frame.
2490 case 6:
2491 time_in_ms = ((file_size.st_size)*160)/397;
2492 break;
2493 // Mode 7: 23.05 kbit/sec -> 461 bits per 20 ms frame.
2494 case 7:
2495 time_in_ms = ((file_size.st_size)*160)/461;
2496 break;
2497 // Mode 8: 23.85 kbit/sec -> 477 bits per 20 ms frame.
2498 case 8:
2499 time_in_ms = ((file_size.st_size)*160)/477;
2500 break;
2501 default:
2502 delete inStreamObj;
2503 return -1;
2504 }
2505 }
2506 #endif
2507 #ifdef WEBRTC_CODEC_ILBC
2508 if(!strcmp("#!iLBC20\n", buf))
2509 {
2510 // 20 ms is 304 bits
2511 time_in_ms = ((file_size.st_size)*160)/304;
2512 break;
2513 }
2514 if(!strcmp("#!iLBC30\n", buf))
2515 {
2516 // 30 ms takes 400 bits.
2517 // file size in bytes * 8 / 400 is the number of
2518 // 30 ms frames in the file ->
2519 // time_in_ms = file size * 8 / 400 * 30
2520 time_in_ms = ((file_size.st_size)*240)/400;
2521 break;
2522 }
2523 #endif
2524 break;
2525 }
2526 case kFileFormatPreencodedFile:
2527 {
2528 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
2529 "cannot determine duration of Pre-Encoded file!");
2530 break;
2531 }
2532 default:
2533 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
2534 "unsupported file format %d!", fileFormat);
2535 break;
2536 }
2537 inStreamObj->CloseFile();
2538 delete inStreamObj;
2539 return time_in_ms;
2540 }
2541
PlayoutPositionMs()2542 uint32_t ModuleFileUtility::PlayoutPositionMs()
2543 {
2544 WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
2545 "ModuleFileUtility::PlayoutPosition()");
2546
2547 if(_reading)
2548 {
2549 return _playoutPositionMs;
2550 }
2551 else
2552 {
2553 return 0;
2554 }
2555 }
2556 } // namespace webrtc
2557