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/media_file_utility.h"
12 
13 #include <assert.h>
14 #include <sys/stat.h>
15 #include <sys/types.h>
16 #include <limits>
17 
18 #include "webrtc/base/format_macros.h"
19 #include "webrtc/common_audio/wav_header.h"
20 #include "webrtc/common_types.h"
21 #include "webrtc/modules/include/module_common_types.h"
22 #include "webrtc/system_wrappers/include/file_wrapper.h"
23 #include "webrtc/system_wrappers/include/trace.h"
24 #include "webrtc/typedefs.h"
25 
26 namespace {
27 
28 // First 16 bytes the WAVE header. ckID should be "RIFF", wave_ckID should be
29 // "WAVE" and ckSize is the chunk size (4 + n)
30 struct WAVE_RIFF_header
31 {
32     int8_t  ckID[4];
33     int32_t ckSize;
34     int8_t  wave_ckID[4];
35 };
36 
37 // First 8 byte of the format chunk. fmt_ckID should be "fmt ". fmt_ckSize is
38 // the chunk size (16, 18 or 40 byte)
39 struct WAVE_CHUNK_header
40 {
41    int8_t   fmt_ckID[4];
42    uint32_t fmt_ckSize;
43 };
44 }  // unnamed namespace
45 
46 namespace webrtc {
ModuleFileUtility(const int32_t id)47 ModuleFileUtility::ModuleFileUtility(const int32_t id)
48     : _wavFormatObj(),
49       _dataSize(0),
50       _readSizeBytes(0),
51       _id(id),
52       _stopPointInMs(0),
53       _startPointInMs(0),
54       _playoutPositionMs(0),
55       _bytesWritten(0),
56       codec_info_(),
57       _codecId(kCodecNoCodec),
58       _bytesPerSample(0),
59       _readPos(0),
60       _reading(false),
61       _writing(false),
62       _tempData() {
63     WEBRTC_TRACE(kTraceMemory, kTraceFile, _id,
64                  "ModuleFileUtility::ModuleFileUtility()");
65     memset(&codec_info_,0,sizeof(CodecInst));
66     codec_info_.pltype = -1;
67 }
68 
~ModuleFileUtility()69 ModuleFileUtility::~ModuleFileUtility()
70 {
71     WEBRTC_TRACE(kTraceMemory, kTraceFile, _id,
72                  "ModuleFileUtility::~ModuleFileUtility()");
73 }
74 
ReadWavHeader(InStream & wav)75 int32_t ModuleFileUtility::ReadWavHeader(InStream& wav)
76 {
77     WAVE_RIFF_header RIFFheaderObj;
78     WAVE_CHUNK_header CHUNKheaderObj;
79     // TODO (hellner): tmpStr and tmpStr2 seems unnecessary here.
80     char tmpStr[6] = "FOUR";
81     unsigned char tmpStr2[4];
82     size_t i;
83     bool dataFound = false;
84     bool fmtFound = false;
85     int8_t dummyRead;
86 
87 
88     _dataSize = 0;
89     int len = wav.Read(&RIFFheaderObj, sizeof(WAVE_RIFF_header));
90     if (len != static_cast<int>(sizeof(WAVE_RIFF_header)))
91     {
92         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
93                      "Not a wave file (too short)");
94         return -1;
95     }
96 
97     for (i = 0; i < 4; i++)
98     {
99         tmpStr[i] = RIFFheaderObj.ckID[i];
100     }
101     if(strcmp(tmpStr, "RIFF") != 0)
102     {
103         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
104                      "Not a wave file (does not have RIFF)");
105         return -1;
106     }
107     for (i = 0; i < 4; i++)
108     {
109         tmpStr[i] = RIFFheaderObj.wave_ckID[i];
110     }
111     if(strcmp(tmpStr, "WAVE") != 0)
112     {
113         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
114                      "Not a wave file (does not have WAVE)");
115         return -1;
116     }
117 
118     len = wav.Read(&CHUNKheaderObj, sizeof(WAVE_CHUNK_header));
119 
120     // WAVE files are stored in little endian byte order. Make sure that the
121     // data can be read on big endian as well.
122     // TODO (hellner): little endian to system byte order should be done in
123     //                 in a subroutine.
124     memcpy(tmpStr2, &CHUNKheaderObj.fmt_ckSize, 4);
125     CHUNKheaderObj.fmt_ckSize =
126         (uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1]) << 8) +
127         (((uint32_t)tmpStr2[2]) << 16) + (((uint32_t)tmpStr2[3]) << 24);
128 
129     memcpy(tmpStr, CHUNKheaderObj.fmt_ckID, 4);
130 
131     while ((len == static_cast<int>(sizeof(WAVE_CHUNK_header))) &&
132            (!fmtFound || !dataFound))
133     {
134         if(strcmp(tmpStr, "fmt ") == 0)
135         {
136             len = wav.Read(&_wavFormatObj, sizeof(WAVE_FMTINFO_header));
137 
138             memcpy(tmpStr2, &_wavFormatObj.formatTag, 2);
139             _wavFormatObj.formatTag =
140                 (uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1])<<8);
141             memcpy(tmpStr2, &_wavFormatObj.nChannels, 2);
142             _wavFormatObj.nChannels =
143                 (int16_t) ((uint32_t)tmpStr2[0] +
144                                  (((uint32_t)tmpStr2[1])<<8));
145             memcpy(tmpStr2, &_wavFormatObj.nSamplesPerSec, 4);
146             _wavFormatObj.nSamplesPerSec =
147                 (int32_t) ((uint32_t)tmpStr2[0] +
148                                  (((uint32_t)tmpStr2[1])<<8) +
149                                  (((uint32_t)tmpStr2[2])<<16) +
150                                  (((uint32_t)tmpStr2[3])<<24));
151             memcpy(tmpStr2, &_wavFormatObj.nAvgBytesPerSec, 4);
152             _wavFormatObj.nAvgBytesPerSec =
153                 (int32_t) ((uint32_t)tmpStr2[0] +
154                                  (((uint32_t)tmpStr2[1])<<8) +
155                                  (((uint32_t)tmpStr2[2])<<16) +
156                                  (((uint32_t)tmpStr2[3])<<24));
157             memcpy(tmpStr2, &_wavFormatObj.nBlockAlign, 2);
158             _wavFormatObj.nBlockAlign =
159                 (int16_t) ((uint32_t)tmpStr2[0] +
160                                  (((uint32_t)tmpStr2[1])<<8));
161             memcpy(tmpStr2, &_wavFormatObj.nBitsPerSample, 2);
162             _wavFormatObj.nBitsPerSample =
163                 (int16_t) ((uint32_t)tmpStr2[0] +
164                                  (((uint32_t)tmpStr2[1])<<8));
165 
166             if (CHUNKheaderObj.fmt_ckSize < sizeof(WAVE_FMTINFO_header))
167             {
168                 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
169                              "Chunk size is too small");
170                 return -1;
171             }
172             for (i = 0;
173                  i < CHUNKheaderObj.fmt_ckSize - sizeof(WAVE_FMTINFO_header);
174                  i++)
175             {
176                 len = wav.Read(&dummyRead, 1);
177                 if(len != 1)
178                 {
179                     WEBRTC_TRACE(kTraceError, kTraceFile, _id,
180                                  "File corrupted, reached EOF (reading fmt)");
181                     return -1;
182                 }
183             }
184             fmtFound = true;
185         }
186         else if(strcmp(tmpStr, "data") == 0)
187         {
188             _dataSize = CHUNKheaderObj.fmt_ckSize;
189             dataFound = true;
190             break;
191         }
192         else
193         {
194             for (i = 0; i < CHUNKheaderObj.fmt_ckSize; i++)
195             {
196                 len = wav.Read(&dummyRead, 1);
197                 if(len != 1)
198                 {
199                     WEBRTC_TRACE(kTraceError, kTraceFile, _id,
200                                  "File corrupted, reached EOF (reading other)");
201                     return -1;
202                 }
203             }
204         }
205 
206         len = wav.Read(&CHUNKheaderObj, sizeof(WAVE_CHUNK_header));
207 
208         memcpy(tmpStr2, &CHUNKheaderObj.fmt_ckSize, 4);
209         CHUNKheaderObj.fmt_ckSize =
210             (uint32_t)tmpStr2[0] + (((uint32_t)tmpStr2[1]) << 8) +
211             (((uint32_t)tmpStr2[2]) << 16) + (((uint32_t)tmpStr2[3]) << 24);
212 
213         memcpy(tmpStr, CHUNKheaderObj.fmt_ckID, 4);
214     }
215 
216     // Either a proper format chunk has been read or a data chunk was come
217     // across.
218     if( (_wavFormatObj.formatTag != kWavFormatPcm) &&
219         (_wavFormatObj.formatTag != kWavFormatALaw) &&
220         (_wavFormatObj.formatTag != kWavFormatMuLaw))
221     {
222         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
223                      "Coding formatTag value=%d not supported!",
224                      _wavFormatObj.formatTag);
225         return -1;
226     }
227     if((_wavFormatObj.nChannels < 1) ||
228         (_wavFormatObj.nChannels > 2))
229     {
230         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
231                      "nChannels value=%d not supported!",
232                      _wavFormatObj.nChannels);
233         return -1;
234     }
235 
236     if((_wavFormatObj.nBitsPerSample != 8) &&
237         (_wavFormatObj.nBitsPerSample != 16))
238     {
239         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
240                      "nBitsPerSample value=%d not supported!",
241                      _wavFormatObj.nBitsPerSample);
242         return -1;
243     }
244 
245     // Calculate the number of bytes that 10 ms of audio data correspond to.
246     size_t samples_per_10ms =
247         ((_wavFormatObj.formatTag == kWavFormatPcm) &&
248          (_wavFormatObj.nSamplesPerSec == 44100)) ?
249         440 : static_cast<size_t>(_wavFormatObj.nSamplesPerSec / 100);
250     _readSizeBytes = samples_per_10ms * _wavFormatObj.nChannels *
251         (_wavFormatObj.nBitsPerSample / 8);
252     return 0;
253 }
254 
InitWavCodec(uint32_t samplesPerSec,size_t channels,uint32_t bitsPerSample,uint32_t formatTag)255 int32_t ModuleFileUtility::InitWavCodec(uint32_t samplesPerSec,
256                                         size_t channels,
257                                         uint32_t bitsPerSample,
258                                         uint32_t formatTag)
259 {
260     codec_info_.pltype   = -1;
261     codec_info_.plfreq   = samplesPerSec;
262     codec_info_.channels = channels;
263     codec_info_.rate     = bitsPerSample * samplesPerSec;
264 
265     // Calculate the packet size for 10ms frames
266     switch(formatTag)
267     {
268     case kWavFormatALaw:
269         strcpy(codec_info_.plname, "PCMA");
270         _codecId = kCodecPcma;
271         codec_info_.pltype = 8;
272         codec_info_.pacsize  = codec_info_.plfreq / 100;
273         break;
274     case kWavFormatMuLaw:
275         strcpy(codec_info_.plname, "PCMU");
276         _codecId = kCodecPcmu;
277         codec_info_.pltype = 0;
278         codec_info_.pacsize  = codec_info_.plfreq / 100;
279          break;
280     case kWavFormatPcm:
281         codec_info_.pacsize  = (bitsPerSample * (codec_info_.plfreq / 100)) / 8;
282         if(samplesPerSec == 8000)
283         {
284             strcpy(codec_info_.plname, "L16");
285             _codecId = kCodecL16_8Khz;
286         }
287         else if(samplesPerSec == 16000)
288         {
289             strcpy(codec_info_.plname, "L16");
290             _codecId = kCodecL16_16kHz;
291         }
292         else if(samplesPerSec == 32000)
293         {
294             strcpy(codec_info_.plname, "L16");
295             _codecId = kCodecL16_32Khz;
296         }
297         // Set the packet size for "odd" sampling frequencies so that it
298         // properly corresponds to _readSizeBytes.
299         else if(samplesPerSec == 11025)
300         {
301             strcpy(codec_info_.plname, "L16");
302             _codecId = kCodecL16_16kHz;
303             codec_info_.pacsize = 110; // XXX inexact!
304             codec_info_.plfreq = 11000; // XXX inexact!
305         }
306         else if(samplesPerSec == 22050)
307         {
308             strcpy(codec_info_.plname, "L16");
309             _codecId = kCodecL16_16kHz;
310             codec_info_.pacsize = 220; // XXX inexact!
311             codec_info_.plfreq = 22000; // XXX inexact!
312         }
313         else if(samplesPerSec == 44100)
314         {
315             strcpy(codec_info_.plname, "L16");
316             _codecId = kCodecL16_16kHz;
317             codec_info_.pacsize = 441;
318             codec_info_.plfreq = 44100;
319         }
320         else if(samplesPerSec == 48000)
321         {
322             strcpy(codec_info_.plname, "L16");
323             _codecId = kCodecL16_16kHz;
324             codec_info_.pacsize = 480;
325             codec_info_.plfreq = 48000;
326         }
327         else
328         {
329             WEBRTC_TRACE(kTraceError, kTraceFile, _id,
330                          "Unsupported PCM frequency!");
331             return -1;
332         }
333         break;
334         default:
335             WEBRTC_TRACE(kTraceError, kTraceFile, _id,
336                          "unknown WAV format TAG!");
337             return -1;
338             break;
339     }
340     return 0;
341 }
342 
InitWavReading(InStream & wav,const uint32_t start,const uint32_t stop)343 int32_t ModuleFileUtility::InitWavReading(InStream& wav,
344                                           const uint32_t start,
345                                           const uint32_t stop)
346 {
347 
348     _reading = false;
349 
350     if(ReadWavHeader(wav) == -1)
351     {
352         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
353                      "failed to read WAV header!");
354         return -1;
355     }
356 
357     _playoutPositionMs = 0;
358     _readPos = 0;
359 
360     if(start > 0)
361     {
362         uint8_t dummy[WAV_MAX_BUFFER_SIZE];
363         int readLength;
364         if(_readSizeBytes <= WAV_MAX_BUFFER_SIZE)
365         {
366             while (_playoutPositionMs < start)
367             {
368                 readLength = wav.Read(dummy, _readSizeBytes);
369                 if(readLength == static_cast<int>(_readSizeBytes))
370                 {
371                     _readPos += _readSizeBytes;
372                     _playoutPositionMs += 10;
373                 }
374                 else // Must have reached EOF before start position!
375                 {
376                     WEBRTC_TRACE(kTraceError, kTraceFile, _id,
377                        "InitWavReading(), EOF before start position");
378                     return -1;
379                 }
380             }
381         }
382         else
383         {
384             return -1;
385         }
386     }
387     if( InitWavCodec(_wavFormatObj.nSamplesPerSec, _wavFormatObj.nChannels,
388                      _wavFormatObj.nBitsPerSample,
389                      _wavFormatObj.formatTag) != 0)
390     {
391         return -1;
392     }
393     _bytesPerSample = static_cast<size_t>(_wavFormatObj.nBitsPerSample / 8);
394 
395 
396     _startPointInMs = start;
397     _stopPointInMs = stop;
398     _reading = true;
399     return 0;
400 }
401 
ReadWavDataAsMono(InStream & wav,int8_t * outData,const size_t bufferSize)402 int32_t ModuleFileUtility::ReadWavDataAsMono(
403     InStream& wav,
404     int8_t* outData,
405     const size_t bufferSize)
406 {
407     WEBRTC_TRACE(
408         kTraceStream,
409         kTraceFile,
410         _id,
411         "ModuleFileUtility::ReadWavDataAsMono(wav= 0x%x, outData= 0x%d, "
412         "bufSize= %" PRIuS ")",
413         &wav,
414         outData,
415         bufferSize);
416 
417     // The number of bytes that should be read from file.
418     const size_t totalBytesNeeded = _readSizeBytes;
419     // The number of bytes that will be written to outData.
420     const size_t bytesRequested = (codec_info_.channels == 2) ?
421         totalBytesNeeded >> 1 : totalBytesNeeded;
422     if(bufferSize < bytesRequested)
423     {
424         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
425                      "ReadWavDataAsMono: output buffer is too short!");
426         return -1;
427     }
428     if(outData == NULL)
429     {
430         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
431                      "ReadWavDataAsMono: output buffer NULL!");
432         return -1;
433     }
434 
435     if(!_reading)
436     {
437         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
438                      "ReadWavDataAsMono: no longer reading file.");
439         return -1;
440     }
441 
442     int32_t bytesRead = ReadWavData(
443         wav,
444         (codec_info_.channels == 2) ? _tempData : (uint8_t*)outData,
445         totalBytesNeeded);
446     if(bytesRead == 0)
447     {
448         return 0;
449     }
450     if(bytesRead < 0)
451     {
452         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
453                      "ReadWavDataAsMono: failed to read data from WAV file.");
454         return -1;
455     }
456     // Output data is should be mono.
457     if(codec_info_.channels == 2)
458     {
459         for (size_t i = 0; i < bytesRequested / _bytesPerSample; i++)
460         {
461             // Sample value is the average of left and right buffer rounded to
462             // closest integer value. Note samples can be either 1 or 2 byte.
463             if(_bytesPerSample == 1)
464             {
465                 _tempData[i] = ((_tempData[2 * i] + _tempData[(2 * i) + 1] +
466                                  1) >> 1);
467             }
468             else
469             {
470                 int16_t* sampleData = (int16_t*) _tempData;
471                 sampleData[i] = ((sampleData[2 * i] + sampleData[(2 * i) + 1] +
472                                   1) >> 1);
473             }
474         }
475         memcpy(outData, _tempData, bytesRequested);
476     }
477     return static_cast<int32_t>(bytesRequested);
478 }
479 
ReadWavDataAsStereo(InStream & wav,int8_t * outDataLeft,int8_t * outDataRight,const size_t bufferSize)480 int32_t ModuleFileUtility::ReadWavDataAsStereo(
481     InStream& wav,
482     int8_t* outDataLeft,
483     int8_t* outDataRight,
484     const size_t bufferSize)
485 {
486     WEBRTC_TRACE(
487         kTraceStream,
488         kTraceFile,
489         _id,
490         "ModuleFileUtility::ReadWavDataAsStereo(wav= 0x%x, outLeft= 0x%x, "
491         "outRight= 0x%x, bufSize= %" PRIuS ")",
492         &wav,
493         outDataLeft,
494         outDataRight,
495         bufferSize);
496 
497     if((outDataLeft == NULL) ||
498        (outDataRight == NULL))
499     {
500         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
501                      "ReadWavDataAsMono: an input buffer is NULL!");
502         return -1;
503     }
504     if(codec_info_.channels != 2)
505     {
506         WEBRTC_TRACE(
507             kTraceError,
508             kTraceFile,
509             _id,
510             "ReadWavDataAsStereo: WAV file does not contain stereo data!");
511         return -1;
512     }
513     if(! _reading)
514     {
515         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
516                      "ReadWavDataAsStereo: no longer reading file.");
517         return -1;
518     }
519 
520     // The number of bytes that should be read from file.
521     const size_t totalBytesNeeded = _readSizeBytes;
522     // The number of bytes that will be written to the left and the right
523     // buffers.
524     const size_t bytesRequested = totalBytesNeeded >> 1;
525     if(bufferSize < bytesRequested)
526     {
527         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
528                      "ReadWavData: Output buffers are too short!");
529         assert(false);
530         return -1;
531     }
532 
533     int32_t bytesRead = ReadWavData(wav, _tempData, totalBytesNeeded);
534     if(bytesRead <= 0)
535     {
536         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
537                      "ReadWavDataAsStereo: failed to read data from WAV file.");
538         return -1;
539     }
540 
541     // Turn interleaved audio to left and right buffer. Note samples can be
542     // either 1 or 2 bytes
543     if(_bytesPerSample == 1)
544     {
545         for (size_t i = 0; i < bytesRequested; i++)
546         {
547             outDataLeft[i]  = _tempData[2 * i];
548             outDataRight[i] = _tempData[(2 * i) + 1];
549         }
550     }
551     else if(_bytesPerSample == 2)
552     {
553         int16_t* sampleData = reinterpret_cast<int16_t*>(_tempData);
554         int16_t* outLeft = reinterpret_cast<int16_t*>(outDataLeft);
555         int16_t* outRight = reinterpret_cast<int16_t*>(
556             outDataRight);
557 
558         // Bytes requested to samples requested.
559         size_t sampleCount = bytesRequested >> 1;
560         for (size_t i = 0; i < sampleCount; i++)
561         {
562             outLeft[i] = sampleData[2 * i];
563             outRight[i] = sampleData[(2 * i) + 1];
564         }
565     } else {
566         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
567                    "ReadWavStereoData: unsupported sample size %" PRIuS "!",
568                    _bytesPerSample);
569         assert(false);
570         return -1;
571     }
572     return static_cast<int32_t>(bytesRequested);
573 }
574 
ReadWavData(InStream & wav,uint8_t * buffer,size_t dataLengthInBytes)575 int32_t ModuleFileUtility::ReadWavData(InStream& wav,
576                                        uint8_t* buffer,
577                                        size_t dataLengthInBytes)
578 {
579     WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
580                  "ModuleFileUtility::ReadWavData(wav= 0x%x, buffer= 0x%x, "
581                  "dataLen= %" PRIuS ")", &wav, buffer, dataLengthInBytes);
582 
583 
584     if(buffer == NULL)
585     {
586         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
587                      "ReadWavDataAsMono: output buffer NULL!");
588         return -1;
589     }
590 
591     // Make sure that a read won't return too few samples.
592     // TODO (hellner): why not read the remaining bytes needed from the start
593     //                 of the file?
594     if(_dataSize < (_readPos + dataLengthInBytes))
595     {
596         // Rewind() being -1 may be due to the file not supposed to be looped.
597         if(wav.Rewind() == -1)
598         {
599             _reading = false;
600             return 0;
601         }
602         if(InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1)
603         {
604             _reading = false;
605             return -1;
606         }
607     }
608 
609     int32_t bytesRead = wav.Read(buffer, dataLengthInBytes);
610     if(bytesRead < 0)
611     {
612         _reading = false;
613         return -1;
614     }
615 
616     // This should never happen due to earlier sanity checks.
617     // TODO (hellner): change to an assert and fail here since this should
618     //                 never happen...
619     if(bytesRead < (int32_t)dataLengthInBytes)
620     {
621         if((wav.Rewind() == -1) ||
622             (InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1))
623         {
624             _reading = false;
625             return -1;
626         }
627         else
628         {
629             bytesRead = wav.Read(buffer, dataLengthInBytes);
630             if(bytesRead < (int32_t)dataLengthInBytes)
631             {
632                 _reading = false;
633                 return -1;
634             }
635         }
636     }
637 
638     _readPos += bytesRead;
639 
640     // TODO (hellner): Why is dataLengthInBytes let dictate the number of bytes
641     //                 to read when exactly 10ms should be read?!
642     _playoutPositionMs += 10;
643     if((_stopPointInMs > 0) &&
644         (_playoutPositionMs >= _stopPointInMs))
645     {
646         if((wav.Rewind() == -1) ||
647             (InitWavReading(wav, _startPointInMs, _stopPointInMs) == -1))
648         {
649             _reading = false;
650         }
651     }
652     return bytesRead;
653 }
654 
InitWavWriting(OutStream & wav,const CodecInst & codecInst)655 int32_t ModuleFileUtility::InitWavWriting(OutStream& wav,
656                                           const CodecInst& codecInst)
657 {
658 
659     if(set_codec_info(codecInst) != 0)
660     {
661         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
662                      "codecInst identifies unsupported codec!");
663         return -1;
664     }
665     _writing = false;
666     size_t channels = (codecInst.channels == 0) ? 1 : codecInst.channels;
667 
668     if(STR_CASE_CMP(codecInst.plname, "PCMU") == 0)
669     {
670         _bytesPerSample = 1;
671         if(WriteWavHeader(wav, 8000, _bytesPerSample, channels,
672                           kWavFormatMuLaw, 0) == -1)
673         {
674             return -1;
675         }
676     }
677     else if(STR_CASE_CMP(codecInst.plname, "PCMA") == 0)
678     {
679         _bytesPerSample = 1;
680         if(WriteWavHeader(wav, 8000, _bytesPerSample, channels, kWavFormatALaw,
681                           0) == -1)
682         {
683             return -1;
684         }
685     }
686     else if(STR_CASE_CMP(codecInst.plname, "L16") == 0)
687     {
688         _bytesPerSample = 2;
689         if(WriteWavHeader(wav, codecInst.plfreq, _bytesPerSample, channels,
690                           kWavFormatPcm, 0) == -1)
691         {
692             return -1;
693         }
694     }
695     else
696     {
697         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
698                    "codecInst identifies unsupported codec for WAV file!");
699         return -1;
700     }
701     _writing = true;
702     _bytesWritten = 0;
703     return 0;
704 }
705 
WriteWavData(OutStream & out,const int8_t * buffer,const size_t dataLength)706 int32_t ModuleFileUtility::WriteWavData(OutStream& out,
707                                         const int8_t*  buffer,
708                                         const size_t dataLength)
709 {
710     WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
711                  "ModuleFileUtility::WriteWavData(out= 0x%x, buf= 0x%x, "
712                  "dataLen= %" PRIuS ")", &out, buffer, dataLength);
713 
714     if(buffer == NULL)
715     {
716         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
717                      "WriteWavData: input buffer NULL!");
718         return -1;
719     }
720 
721     if(!out.Write(buffer, dataLength))
722     {
723         return -1;
724     }
725     _bytesWritten += dataLength;
726     return static_cast<int32_t>(dataLength);
727 }
728 
729 
WriteWavHeader(OutStream & wav,uint32_t freq,size_t bytesPerSample,size_t channels,uint32_t format,size_t lengthInBytes)730 int32_t ModuleFileUtility::WriteWavHeader(
731     OutStream& wav,
732     uint32_t freq,
733     size_t bytesPerSample,
734     size_t channels,
735     uint32_t format,
736     size_t lengthInBytes)
737 {
738     // Frame size in bytes for 10 ms of audio.
739     const size_t frameSize = (freq / 100) * channels;
740 
741     // Calculate the number of full frames that the wave file contain.
742     const size_t dataLengthInBytes = frameSize * (lengthInBytes / frameSize);
743 
744     uint8_t buf[kWavHeaderSize];
745     webrtc::WriteWavHeader(buf, channels, freq, static_cast<WavFormat>(format),
746                            bytesPerSample, dataLengthInBytes / bytesPerSample);
747     wav.Write(buf, kWavHeaderSize);
748     return 0;
749 }
750 
UpdateWavHeader(OutStream & wav)751 int32_t ModuleFileUtility::UpdateWavHeader(OutStream& wav)
752 {
753     int32_t res = -1;
754     if(wav.Rewind() == -1)
755     {
756         return -1;
757     }
758     size_t channels = (codec_info_.channels == 0) ? 1 : codec_info_.channels;
759 
760     if(STR_CASE_CMP(codec_info_.plname, "L16") == 0)
761     {
762         res = WriteWavHeader(wav, codec_info_.plfreq, 2, channels,
763                              kWavFormatPcm, _bytesWritten);
764     } else if(STR_CASE_CMP(codec_info_.plname, "PCMU") == 0) {
765             res = WriteWavHeader(wav, 8000, 1, channels, kWavFormatMuLaw,
766                                  _bytesWritten);
767     } else if(STR_CASE_CMP(codec_info_.plname, "PCMA") == 0) {
768             res = WriteWavHeader(wav, 8000, 1, channels, kWavFormatALaw,
769                                  _bytesWritten);
770     } else {
771         // Allow calling this API even if not writing to a WAVE file.
772         // TODO (hellner): why?!
773         return 0;
774     }
775     return res;
776 }
777 
778 
InitPreEncodedReading(InStream & in,const CodecInst & cinst)779 int32_t ModuleFileUtility::InitPreEncodedReading(InStream& in,
780                                                  const CodecInst& cinst)
781 {
782 
783     uint8_t preEncodedID;
784     in.Read(&preEncodedID, 1);
785 
786     MediaFileUtility_CodecType codecType =
787         (MediaFileUtility_CodecType)preEncodedID;
788 
789     if(set_codec_info(cinst) != 0)
790     {
791         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
792                      "Pre-encoded file send codec mismatch!");
793         return -1;
794     }
795     if(codecType != _codecId)
796     {
797         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
798                      "Pre-encoded file format codec mismatch!");
799         return -1;
800     }
801     memcpy(&codec_info_,&cinst,sizeof(CodecInst));
802     _reading = true;
803     return 0;
804 }
805 
ReadPreEncodedData(InStream & in,int8_t * outData,const size_t bufferSize)806 int32_t ModuleFileUtility::ReadPreEncodedData(
807     InStream& in,
808     int8_t* outData,
809     const size_t bufferSize)
810 {
811     WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
812                  "ModuleFileUtility::ReadPreEncodedData(in= 0x%x, "
813                  "outData= 0x%x, bufferSize= %" PRIuS ")", &in, outData,
814                  bufferSize);
815 
816     if(outData == NULL)
817     {
818         WEBRTC_TRACE(kTraceError, kTraceFile, _id, "output buffer NULL");
819     }
820 
821     size_t frameLen;
822     uint8_t buf[64];
823     // Each frame has a two byte header containing the frame length.
824     int32_t res = in.Read(buf, 2);
825     if(res != 2)
826     {
827         if(!in.Rewind())
828         {
829             // The first byte is the codec identifier.
830             in.Read(buf, 1);
831             res = in.Read(buf, 2);
832         }
833         else
834         {
835             return -1;
836         }
837     }
838     frameLen = buf[0] + buf[1] * 256;
839     if(bufferSize < frameLen)
840     {
841         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
842                      "buffer not large enough to read %" PRIuS " bytes of "
843                      "pre-encoded data!", frameLen);
844         return -1;
845     }
846     return in.Read(outData, frameLen);
847 }
848 
InitPreEncodedWriting(OutStream & out,const CodecInst & codecInst)849 int32_t ModuleFileUtility::InitPreEncodedWriting(
850     OutStream& out,
851     const CodecInst& codecInst)
852 {
853 
854     if(set_codec_info(codecInst) != 0)
855     {
856         WEBRTC_TRACE(kTraceError, kTraceFile, _id, "CodecInst not recognized!");
857         return -1;
858     }
859     _writing = true;
860     _bytesWritten = 1;
861     out.Write(&_codecId, 1);
862     return 0;
863 }
864 
WritePreEncodedData(OutStream & out,const int8_t * buffer,const size_t dataLength)865 int32_t ModuleFileUtility::WritePreEncodedData(
866     OutStream& out,
867     const int8_t* buffer,
868     const size_t dataLength)
869 {
870     WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
871                  "ModuleFileUtility::WritePreEncodedData(out= 0x%x, "
872                  "inData= 0x%x, dataLen= %" PRIuS ")", &out, buffer,
873                  dataLength);
874 
875     if(buffer == NULL)
876     {
877         WEBRTC_TRACE(kTraceError, kTraceFile, _id,"buffer NULL");
878     }
879 
880     size_t bytesWritten = 0;
881     // The first two bytes is the size of the frame.
882     int16_t lengthBuf;
883     lengthBuf = (int16_t)dataLength;
884     if(dataLength > static_cast<size_t>(std::numeric_limits<int16_t>::max()) ||
885        !out.Write(&lengthBuf, 2))
886     {
887        return -1;
888     }
889     bytesWritten = 2;
890 
891     if(!out.Write(buffer, dataLength))
892     {
893         return -1;
894     }
895     bytesWritten += dataLength;
896     return static_cast<int32_t>(bytesWritten);
897 }
898 
InitCompressedReading(InStream & in,const uint32_t start,const uint32_t stop)899 int32_t ModuleFileUtility::InitCompressedReading(
900     InStream& in,
901     const uint32_t start,
902     const uint32_t stop)
903 {
904     WEBRTC_TRACE(kTraceDebug, kTraceFile, _id,
905                  "ModuleFileUtility::InitCompressedReading(in= 0x%x, "
906                  "start= %d, stop= %d)", &in, start, stop);
907 
908 #if defined(WEBRTC_CODEC_ILBC)
909     int16_t read_len = 0;
910 #endif
911     _codecId = kCodecNoCodec;
912     _playoutPositionMs = 0;
913     _reading = false;
914 
915     _startPointInMs = start;
916     _stopPointInMs = stop;
917 
918     // Read the codec name
919     int32_t cnt = 0;
920     char buf[64];
921     do
922     {
923         in.Read(&buf[cnt++], 1);
924     } while ((buf[cnt-1] != '\n') && (64 > cnt));
925 
926     if(cnt==64)
927     {
928         return -1;
929     }
930     buf[cnt]=0;
931 
932 #ifdef WEBRTC_CODEC_ILBC
933     if(!strcmp("#!iLBC20\n", buf))
934     {
935         codec_info_.pltype = 102;
936         strcpy(codec_info_.plname, "ilbc");
937         codec_info_.plfreq   = 8000;
938         codec_info_.pacsize  = 160;
939         codec_info_.channels = 1;
940         codec_info_.rate     = 13300;
941         _codecId = kCodecIlbc20Ms;
942 
943         if(_startPointInMs > 0)
944         {
945             while (_playoutPositionMs <= _startPointInMs)
946             {
947                 read_len = in.Read(buf, 38);
948                 if(read_len != 38)
949                 {
950                     return -1;
951                 }
952                 _playoutPositionMs += 20;
953             }
954         }
955     }
956 
957     if(!strcmp("#!iLBC30\n", buf))
958     {
959         codec_info_.pltype = 102;
960         strcpy(codec_info_.plname, "ilbc");
961         codec_info_.plfreq   = 8000;
962         codec_info_.pacsize  = 240;
963         codec_info_.channels = 1;
964         codec_info_.rate     = 13300;
965         _codecId = kCodecIlbc30Ms;
966 
967         if(_startPointInMs > 0)
968         {
969             while (_playoutPositionMs <= _startPointInMs)
970             {
971                 read_len = in.Read(buf, 50);
972                 if(read_len != 50)
973                 {
974                     return -1;
975                 }
976                 _playoutPositionMs += 20;
977             }
978         }
979     }
980 #endif
981     if(_codecId == kCodecNoCodec)
982     {
983         return -1;
984     }
985     _reading = true;
986     return 0;
987 }
988 
ReadCompressedData(InStream & in,int8_t * outData,size_t bufferSize)989 int32_t ModuleFileUtility::ReadCompressedData(InStream& in,
990                                               int8_t* outData,
991                                               size_t bufferSize)
992 {
993     WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
994                  "ModuleFileUtility::ReadCompressedData(in=0x%x, outData=0x%x, "
995                  "bytes=%" PRIuS ")", &in, outData, bufferSize);
996 
997     int bytesRead = 0;
998 
999     if(! _reading)
1000     {
1001         WEBRTC_TRACE(kTraceError, kTraceFile, _id, "not currently reading!");
1002         return -1;
1003     }
1004 
1005 #ifdef WEBRTC_CODEC_ILBC
1006     if((_codecId == kCodecIlbc20Ms) ||
1007         (_codecId == kCodecIlbc30Ms))
1008     {
1009         size_t byteSize = 0;
1010         if(_codecId == kCodecIlbc30Ms)
1011         {
1012             byteSize = 50;
1013         }
1014         if(_codecId == kCodecIlbc20Ms)
1015         {
1016             byteSize = 38;
1017         }
1018         if(bufferSize < byteSize)
1019         {
1020             WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1021                          "output buffer is too short to read ILBC compressed "
1022                          "data.");
1023             assert(false);
1024             return -1;
1025         }
1026 
1027         bytesRead = in.Read(outData, byteSize);
1028         if(bytesRead != static_cast<int>(byteSize))
1029         {
1030             if(!in.Rewind())
1031             {
1032                 InitCompressedReading(in, _startPointInMs, _stopPointInMs);
1033                 bytesRead = in.Read(outData, byteSize);
1034                 if(bytesRead != static_cast<int>(byteSize))
1035                 {
1036                     _reading = false;
1037                     return -1;
1038                 }
1039             }
1040             else
1041             {
1042                 _reading = false;
1043                 return -1;
1044             }
1045         }
1046     }
1047 #endif
1048     if(bytesRead == 0)
1049     {
1050         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1051                      "ReadCompressedData() no bytes read, codec not supported");
1052         return -1;
1053     }
1054 
1055     _playoutPositionMs += 20;
1056     if((_stopPointInMs > 0) &&
1057         (_playoutPositionMs >= _stopPointInMs))
1058     {
1059         if(!in.Rewind())
1060         {
1061             InitCompressedReading(in, _startPointInMs, _stopPointInMs);
1062         }
1063         else
1064         {
1065             _reading = false;
1066         }
1067     }
1068     return bytesRead;
1069 }
1070 
InitCompressedWriting(OutStream & out,const CodecInst & codecInst)1071 int32_t ModuleFileUtility::InitCompressedWriting(
1072     OutStream& out,
1073     const CodecInst& codecInst)
1074 {
1075     WEBRTC_TRACE(kTraceDebug, kTraceFile, _id,
1076                  "ModuleFileUtility::InitCompressedWriting(out= 0x%x, "
1077                  "codecName= %s)", &out, codecInst.plname);
1078 
1079     _writing = false;
1080 
1081 #ifdef WEBRTC_CODEC_ILBC
1082     if(STR_CASE_CMP(codecInst.plname, "ilbc") == 0)
1083     {
1084         if(codecInst.pacsize == 160)
1085         {
1086             _codecId = kCodecIlbc20Ms;
1087             out.Write("#!iLBC20\n",9);
1088         }
1089         else if(codecInst.pacsize == 240)
1090         {
1091             _codecId = kCodecIlbc30Ms;
1092             out.Write("#!iLBC30\n",9);
1093         }
1094         else
1095         {
1096           WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1097                        "codecInst defines unsupported compression codec!");
1098             return -1;
1099         }
1100         memcpy(&codec_info_,&codecInst,sizeof(CodecInst));
1101         _writing = true;
1102         return 0;
1103     }
1104 #endif
1105 
1106     WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1107                  "codecInst defines unsupported compression codec!");
1108     return -1;
1109 }
1110 
WriteCompressedData(OutStream & out,const int8_t * buffer,const size_t dataLength)1111 int32_t ModuleFileUtility::WriteCompressedData(
1112     OutStream& out,
1113     const int8_t* buffer,
1114     const size_t dataLength)
1115 {
1116     WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1117                  "ModuleFileUtility::WriteCompressedData(out= 0x%x, buf= 0x%x, "
1118                  "dataLen= %" PRIuS ")", &out, buffer, dataLength);
1119 
1120     if(buffer == NULL)
1121     {
1122         WEBRTC_TRACE(kTraceError, kTraceFile, _id,"buffer NULL");
1123     }
1124 
1125     if(!out.Write(buffer, dataLength))
1126     {
1127         return -1;
1128     }
1129     return static_cast<int32_t>(dataLength);
1130 }
1131 
InitPCMReading(InStream & pcm,const uint32_t start,const uint32_t stop,uint32_t freq)1132 int32_t ModuleFileUtility::InitPCMReading(InStream& pcm,
1133                                           const uint32_t start,
1134                                           const uint32_t stop,
1135                                           uint32_t freq)
1136 {
1137     WEBRTC_TRACE(kTraceInfo, kTraceFile, _id,
1138                  "ModuleFileUtility::InitPCMReading(pcm= 0x%x, start=%d, "
1139                  "stop=%d, freq=%d)", &pcm, start, stop, freq);
1140 
1141     int8_t dummy[320];
1142     int read_len;
1143 
1144     _playoutPositionMs = 0;
1145     _startPointInMs = start;
1146     _stopPointInMs = stop;
1147     _reading = false;
1148 
1149     if(freq == 8000)
1150     {
1151         strcpy(codec_info_.plname, "L16");
1152         codec_info_.pltype   = -1;
1153         codec_info_.plfreq   = 8000;
1154         codec_info_.pacsize  = 160;
1155         codec_info_.channels = 1;
1156         codec_info_.rate     = 128000;
1157         _codecId = kCodecL16_8Khz;
1158     }
1159     else if(freq == 16000)
1160     {
1161         strcpy(codec_info_.plname, "L16");
1162         codec_info_.pltype   = -1;
1163         codec_info_.plfreq   = 16000;
1164         codec_info_.pacsize  = 320;
1165         codec_info_.channels = 1;
1166         codec_info_.rate     = 256000;
1167         _codecId = kCodecL16_16kHz;
1168     }
1169     else if(freq == 32000)
1170     {
1171         strcpy(codec_info_.plname, "L16");
1172         codec_info_.pltype   = -1;
1173         codec_info_.plfreq   = 32000;
1174         codec_info_.pacsize  = 320;
1175         codec_info_.channels = 1;
1176         codec_info_.rate     = 512000;
1177         _codecId = kCodecL16_32Khz;
1178     }
1179 
1180     // Readsize for 10ms of audio data (2 bytes per sample).
1181     _readSizeBytes = 2 * codec_info_. plfreq / 100;
1182     if(_startPointInMs > 0)
1183     {
1184         while (_playoutPositionMs < _startPointInMs)
1185         {
1186             read_len = pcm.Read(dummy, _readSizeBytes);
1187             if(read_len != static_cast<int>(_readSizeBytes))
1188             {
1189                 return -1;  // Must have reached EOF before start position!
1190             }
1191             _playoutPositionMs += 10;
1192         }
1193     }
1194     _reading = true;
1195     return 0;
1196 }
1197 
ReadPCMData(InStream & pcm,int8_t * outData,size_t bufferSize)1198 int32_t ModuleFileUtility::ReadPCMData(InStream& pcm,
1199                                        int8_t* outData,
1200                                        size_t bufferSize)
1201 {
1202     WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1203                  "ModuleFileUtility::ReadPCMData(pcm= 0x%x, outData= 0x%x, "
1204                  "bufSize= %" PRIuS ")", &pcm, outData, bufferSize);
1205 
1206     if(outData == NULL)
1207     {
1208         WEBRTC_TRACE(kTraceError, kTraceFile, _id, "buffer NULL");
1209     }
1210 
1211     // Readsize for 10ms of audio data (2 bytes per sample).
1212     size_t bytesRequested = static_cast<size_t>(2 * codec_info_.plfreq / 100);
1213     if(bufferSize <  bytesRequested)
1214     {
1215         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1216                    "ReadPCMData: buffer not long enough for a 10ms frame.");
1217         assert(false);
1218         return -1;
1219     }
1220 
1221     int bytesRead = pcm.Read(outData, bytesRequested);
1222     if(bytesRead < static_cast<int>(bytesRequested))
1223     {
1224         if(pcm.Rewind() == -1)
1225         {
1226             _reading = false;
1227         }
1228         else
1229         {
1230             if(InitPCMReading(pcm, _startPointInMs, _stopPointInMs,
1231                               codec_info_.plfreq) == -1)
1232             {
1233                 _reading = false;
1234             }
1235             else
1236             {
1237                 size_t rest = bytesRequested - bytesRead;
1238                 int len = pcm.Read(&(outData[bytesRead]), rest);
1239                 if(len == static_cast<int>(rest))
1240                 {
1241                     bytesRead += len;
1242                 }
1243                 else
1244                 {
1245                     _reading = false;
1246                 }
1247             }
1248             if(bytesRead <= 0)
1249             {
1250                 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1251                              "ReadPCMData: Failed to rewind audio file.");
1252                 return -1;
1253             }
1254         }
1255     }
1256 
1257     if(bytesRead <= 0)
1258     {
1259         WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1260                      "ReadPCMData: end of file");
1261         return -1;
1262     }
1263     _playoutPositionMs += 10;
1264     if(_stopPointInMs && _playoutPositionMs >= _stopPointInMs)
1265     {
1266         if(!pcm.Rewind())
1267         {
1268             if(InitPCMReading(pcm, _startPointInMs, _stopPointInMs,
1269                               codec_info_.plfreq) == -1)
1270             {
1271                 _reading = false;
1272             }
1273         }
1274     }
1275     return bytesRead;
1276 }
1277 
InitPCMWriting(OutStream & out,uint32_t freq)1278 int32_t ModuleFileUtility::InitPCMWriting(OutStream& out, uint32_t freq)
1279 {
1280 
1281     if(freq == 8000)
1282     {
1283         strcpy(codec_info_.plname, "L16");
1284         codec_info_.pltype   = -1;
1285         codec_info_.plfreq   = 8000;
1286         codec_info_.pacsize  = 160;
1287         codec_info_.channels = 1;
1288         codec_info_.rate     = 128000;
1289 
1290         _codecId = kCodecL16_8Khz;
1291     }
1292     else if(freq == 16000)
1293     {
1294         strcpy(codec_info_.plname, "L16");
1295         codec_info_.pltype   = -1;
1296         codec_info_.plfreq   = 16000;
1297         codec_info_.pacsize  = 320;
1298         codec_info_.channels = 1;
1299         codec_info_.rate     = 256000;
1300 
1301         _codecId = kCodecL16_16kHz;
1302     }
1303     else if(freq == 32000)
1304     {
1305         strcpy(codec_info_.plname, "L16");
1306         codec_info_.pltype   = -1;
1307         codec_info_.plfreq   = 32000;
1308         codec_info_.pacsize  = 320;
1309         codec_info_.channels = 1;
1310         codec_info_.rate     = 512000;
1311 
1312         _codecId = kCodecL16_32Khz;
1313     }
1314     if((_codecId != kCodecL16_8Khz) &&
1315        (_codecId != kCodecL16_16kHz) &&
1316        (_codecId != kCodecL16_32Khz))
1317     {
1318         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1319                      "CodecInst is not 8KHz PCM or 16KHz PCM!");
1320         return -1;
1321     }
1322     _writing = true;
1323     _bytesWritten = 0;
1324     return 0;
1325 }
1326 
WritePCMData(OutStream & out,const int8_t * buffer,const size_t dataLength)1327 int32_t ModuleFileUtility::WritePCMData(OutStream& out,
1328                                         const int8_t*  buffer,
1329                                         const size_t dataLength)
1330 {
1331     WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1332                  "ModuleFileUtility::WritePCMData(out= 0x%x, buf= 0x%x, "
1333                  "dataLen= %" PRIuS ")", &out, buffer, dataLength);
1334 
1335     if(buffer == NULL)
1336     {
1337         WEBRTC_TRACE(kTraceError, kTraceFile, _id, "buffer NULL");
1338     }
1339 
1340     if(!out.Write(buffer, dataLength))
1341     {
1342         return -1;
1343     }
1344 
1345     _bytesWritten += dataLength;
1346     return static_cast<int32_t>(dataLength);
1347 }
1348 
codec_info(CodecInst & codecInst)1349 int32_t ModuleFileUtility::codec_info(CodecInst& codecInst)
1350 {
1351     WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1352                  "ModuleFileUtility::codec_info(codecInst= 0x%x)", &codecInst);
1353 
1354     if(!_reading && !_writing)
1355     {
1356         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1357                      "CodecInst: not currently reading audio file!");
1358         return -1;
1359     }
1360     memcpy(&codecInst,&codec_info_,sizeof(CodecInst));
1361     return 0;
1362 }
1363 
set_codec_info(const CodecInst & codecInst)1364 int32_t ModuleFileUtility::set_codec_info(const CodecInst& codecInst)
1365 {
1366 
1367     _codecId = kCodecNoCodec;
1368     if(STR_CASE_CMP(codecInst.plname, "PCMU") == 0)
1369     {
1370         _codecId = kCodecPcmu;
1371     }
1372     else if(STR_CASE_CMP(codecInst.plname, "PCMA") == 0)
1373     {
1374         _codecId = kCodecPcma;
1375     }
1376     else if(STR_CASE_CMP(codecInst.plname, "L16") == 0)
1377     {
1378         if(codecInst.plfreq == 8000)
1379         {
1380             _codecId = kCodecL16_8Khz;
1381         }
1382         else if(codecInst.plfreq == 16000)
1383         {
1384             _codecId = kCodecL16_16kHz;
1385         }
1386         else if(codecInst.plfreq == 32000)
1387         {
1388             _codecId = kCodecL16_32Khz;
1389         }
1390     }
1391 #ifdef WEBRTC_CODEC_ILBC
1392     else if(STR_CASE_CMP(codecInst.plname, "ilbc") == 0)
1393     {
1394         if(codecInst.pacsize == 160)
1395         {
1396             _codecId = kCodecIlbc20Ms;
1397         }
1398         else if(codecInst.pacsize == 240)
1399         {
1400             _codecId = kCodecIlbc30Ms;
1401         }
1402     }
1403 #endif
1404 #if(defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
1405     else if(STR_CASE_CMP(codecInst.plname, "isac") == 0)
1406     {
1407         if(codecInst.plfreq == 16000)
1408         {
1409             _codecId = kCodecIsac;
1410         }
1411         else if(codecInst.plfreq == 32000)
1412         {
1413             _codecId = kCodecIsacSwb;
1414         }
1415     }
1416 #endif
1417 #ifdef WEBRTC_CODEC_G722
1418     else if(STR_CASE_CMP(codecInst.plname, "G722") == 0)
1419     {
1420         _codecId = kCodecG722;
1421     }
1422 #endif
1423     if(_codecId == kCodecNoCodec)
1424     {
1425         return -1;
1426     }
1427     memcpy(&codec_info_, &codecInst, sizeof(CodecInst));
1428     return 0;
1429 }
1430 
FileDurationMs(const char * fileName,const FileFormats fileFormat,const uint32_t freqInHz)1431 int32_t ModuleFileUtility::FileDurationMs(const char* fileName,
1432                                           const FileFormats fileFormat,
1433                                           const uint32_t freqInHz)
1434 {
1435 
1436     if(fileName == NULL)
1437     {
1438         WEBRTC_TRACE(kTraceError, kTraceFile, _id, "filename NULL");
1439         return -1;
1440     }
1441 
1442     int32_t time_in_ms = -1;
1443     struct stat file_size;
1444     if(stat(fileName,&file_size) == -1)
1445     {
1446         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1447                      "failed to retrieve file size with stat!");
1448         return -1;
1449     }
1450     FileWrapper* inStreamObj = FileWrapper::Create();
1451     if(inStreamObj == NULL)
1452     {
1453         WEBRTC_TRACE(kTraceMemory, kTraceFile, _id,
1454                      "failed to create InStream object!");
1455         return -1;
1456     }
1457     if (!inStreamObj->OpenFile(fileName, true)) {
1458       delete inStreamObj;
1459       WEBRTC_TRACE(kTraceError, kTraceFile, _id, "failed to open file %s!",
1460                    fileName);
1461       return -1;
1462     }
1463 
1464     switch (fileFormat)
1465     {
1466         case kFileFormatWavFile:
1467         {
1468             if(ReadWavHeader(*inStreamObj) == -1)
1469             {
1470                 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1471                              "failed to read WAV file header!");
1472                 return -1;
1473             }
1474             time_in_ms = ((file_size.st_size - 44) /
1475                           (_wavFormatObj.nAvgBytesPerSec/1000));
1476             break;
1477         }
1478         case kFileFormatPcm16kHzFile:
1479         {
1480             // 16 samples per ms. 2 bytes per sample.
1481             int32_t denominator = 16*2;
1482             time_in_ms = (file_size.st_size)/denominator;
1483             break;
1484         }
1485         case kFileFormatPcm8kHzFile:
1486         {
1487             // 8 samples per ms. 2 bytes per sample.
1488             int32_t denominator = 8*2;
1489             time_in_ms = (file_size.st_size)/denominator;
1490             break;
1491         }
1492         case kFileFormatCompressedFile:
1493         {
1494             int32_t cnt = 0;
1495             int read_len = 0;
1496             char buf[64];
1497             do
1498             {
1499                 read_len = inStreamObj->Read(&buf[cnt++], 1);
1500                 if(read_len != 1)
1501                 {
1502                     return -1;
1503                 }
1504             } while ((buf[cnt-1] != '\n') && (64 > cnt));
1505 
1506             if(cnt == 64)
1507             {
1508                 return -1;
1509             }
1510             else
1511             {
1512                 buf[cnt] = 0;
1513             }
1514 #ifdef WEBRTC_CODEC_ILBC
1515             if(!strcmp("#!iLBC20\n", buf))
1516             {
1517                 // 20 ms is 304 bits
1518                 time_in_ms = ((file_size.st_size)*160)/304;
1519                 break;
1520             }
1521             if(!strcmp("#!iLBC30\n", buf))
1522             {
1523                 // 30 ms takes 400 bits.
1524                 // file size in bytes * 8 / 400 is the number of
1525                 // 30 ms frames in the file ->
1526                 // time_in_ms = file size * 8 / 400 * 30
1527                 time_in_ms = ((file_size.st_size)*240)/400;
1528                 break;
1529             }
1530 #endif
1531             break;
1532         }
1533         case kFileFormatPreencodedFile:
1534         {
1535             WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1536                          "cannot determine duration of Pre-Encoded file!");
1537             break;
1538         }
1539         default:
1540             WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1541                          "unsupported file format %d!", fileFormat);
1542             break;
1543     }
1544     inStreamObj->CloseFile();
1545     delete inStreamObj;
1546     return time_in_ms;
1547 }
1548 
PlayoutPositionMs()1549 uint32_t ModuleFileUtility::PlayoutPositionMs()
1550 {
1551     WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1552                  "ModuleFileUtility::PlayoutPosition()");
1553 
1554     return _reading ? _playoutPositionMs : 0;
1555 }
1556 }  // namespace webrtc
1557