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/engine_configurations.h"
22 #include "webrtc/modules/include/module_common_types.h"
23 #include "webrtc/system_wrappers/include/file_wrapper.h"
24 #include "webrtc/system_wrappers/include/trace.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;
304             codec_info_.plfreq = 11000;
305         }
306         else if(samplesPerSec == 22050)
307         {
308             strcpy(codec_info_.plname, "L16");
309             _codecId = kCodecL16_16kHz;
310             codec_info_.pacsize = 220;
311             codec_info_.plfreq = 22000;
312         }
313         else if(samplesPerSec == 44100)
314         {
315             strcpy(codec_info_.plname, "L16");
316             _codecId = kCodecL16_16kHz;
317             codec_info_.pacsize = 440;
318             codec_info_.plfreq = 44000;
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     // TODO (hellner): 44.1 kHz has 440 samples frame size. Doesn't seem to
740     //                 be taken into consideration here!
741     const size_t frameSize = (freq / 100) * channels;
742 
743     // Calculate the number of full frames that the wave file contain.
744     const size_t dataLengthInBytes = frameSize * (lengthInBytes / frameSize);
745 
746     uint8_t buf[kWavHeaderSize];
747     webrtc::WriteWavHeader(buf, channels, freq, static_cast<WavFormat>(format),
748                            bytesPerSample, dataLengthInBytes / bytesPerSample);
749     wav.Write(buf, kWavHeaderSize);
750     return 0;
751 }
752 
UpdateWavHeader(OutStream & wav)753 int32_t ModuleFileUtility::UpdateWavHeader(OutStream& wav)
754 {
755     int32_t res = -1;
756     if(wav.Rewind() == -1)
757     {
758         return -1;
759     }
760     size_t channels = (codec_info_.channels == 0) ? 1 : codec_info_.channels;
761 
762     if(STR_CASE_CMP(codec_info_.plname, "L16") == 0)
763     {
764         res = WriteWavHeader(wav, codec_info_.plfreq, 2, channels,
765                              kWavFormatPcm, _bytesWritten);
766     } else if(STR_CASE_CMP(codec_info_.plname, "PCMU") == 0) {
767             res = WriteWavHeader(wav, 8000, 1, channels, kWavFormatMuLaw,
768                                  _bytesWritten);
769     } else if(STR_CASE_CMP(codec_info_.plname, "PCMA") == 0) {
770             res = WriteWavHeader(wav, 8000, 1, channels, kWavFormatALaw,
771                                  _bytesWritten);
772     } else {
773         // Allow calling this API even if not writing to a WAVE file.
774         // TODO (hellner): why?!
775         return 0;
776     }
777     return res;
778 }
779 
780 
InitPreEncodedReading(InStream & in,const CodecInst & cinst)781 int32_t ModuleFileUtility::InitPreEncodedReading(InStream& in,
782                                                  const CodecInst& cinst)
783 {
784 
785     uint8_t preEncodedID;
786     in.Read(&preEncodedID, 1);
787 
788     MediaFileUtility_CodecType codecType =
789         (MediaFileUtility_CodecType)preEncodedID;
790 
791     if(set_codec_info(cinst) != 0)
792     {
793         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
794                      "Pre-encoded file send codec mismatch!");
795         return -1;
796     }
797     if(codecType != _codecId)
798     {
799         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
800                      "Pre-encoded file format codec mismatch!");
801         return -1;
802     }
803     memcpy(&codec_info_,&cinst,sizeof(CodecInst));
804     _reading = true;
805     return 0;
806 }
807 
ReadPreEncodedData(InStream & in,int8_t * outData,const size_t bufferSize)808 int32_t ModuleFileUtility::ReadPreEncodedData(
809     InStream& in,
810     int8_t* outData,
811     const size_t bufferSize)
812 {
813     WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
814                  "ModuleFileUtility::ReadPreEncodedData(in= 0x%x, "
815                  "outData= 0x%x, bufferSize= %" PRIuS ")", &in, outData,
816                  bufferSize);
817 
818     if(outData == NULL)
819     {
820         WEBRTC_TRACE(kTraceError, kTraceFile, _id, "output buffer NULL");
821     }
822 
823     size_t frameLen;
824     uint8_t buf[64];
825     // Each frame has a two byte header containing the frame length.
826     int32_t res = in.Read(buf, 2);
827     if(res != 2)
828     {
829         if(!in.Rewind())
830         {
831             // The first byte is the codec identifier.
832             in.Read(buf, 1);
833             res = in.Read(buf, 2);
834         }
835         else
836         {
837             return -1;
838         }
839     }
840     frameLen = buf[0] + buf[1] * 256;
841     if(bufferSize < frameLen)
842     {
843         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
844                      "buffer not large enough to read %" PRIuS " bytes of "
845                      "pre-encoded data!", frameLen);
846         return -1;
847     }
848     return in.Read(outData, frameLen);
849 }
850 
InitPreEncodedWriting(OutStream & out,const CodecInst & codecInst)851 int32_t ModuleFileUtility::InitPreEncodedWriting(
852     OutStream& out,
853     const CodecInst& codecInst)
854 {
855 
856     if(set_codec_info(codecInst) != 0)
857     {
858         WEBRTC_TRACE(kTraceError, kTraceFile, _id, "CodecInst not recognized!");
859         return -1;
860     }
861     _writing = true;
862     _bytesWritten = 1;
863     out.Write(&_codecId, 1);
864     return 0;
865 }
866 
WritePreEncodedData(OutStream & out,const int8_t * buffer,const size_t dataLength)867 int32_t ModuleFileUtility::WritePreEncodedData(
868     OutStream& out,
869     const int8_t* buffer,
870     const size_t dataLength)
871 {
872     WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
873                  "ModuleFileUtility::WritePreEncodedData(out= 0x%x, "
874                  "inData= 0x%x, dataLen= %" PRIuS ")", &out, buffer,
875                  dataLength);
876 
877     if(buffer == NULL)
878     {
879         WEBRTC_TRACE(kTraceError, kTraceFile, _id,"buffer NULL");
880     }
881 
882     size_t bytesWritten = 0;
883     // The first two bytes is the size of the frame.
884     int16_t lengthBuf;
885     lengthBuf = (int16_t)dataLength;
886     if(dataLength > static_cast<size_t>(std::numeric_limits<int16_t>::max()) ||
887        !out.Write(&lengthBuf, 2))
888     {
889        return -1;
890     }
891     bytesWritten = 2;
892 
893     if(!out.Write(buffer, dataLength))
894     {
895         return -1;
896     }
897     bytesWritten += dataLength;
898     return static_cast<int32_t>(bytesWritten);
899 }
900 
InitCompressedReading(InStream & in,const uint32_t start,const uint32_t stop)901 int32_t ModuleFileUtility::InitCompressedReading(
902     InStream& in,
903     const uint32_t start,
904     const uint32_t stop)
905 {
906     WEBRTC_TRACE(kTraceDebug, kTraceFile, _id,
907                  "ModuleFileUtility::InitCompressedReading(in= 0x%x, "
908                  "start= %d, stop= %d)", &in, start, stop);
909 
910 #if defined(WEBRTC_CODEC_ILBC)
911     int16_t read_len = 0;
912 #endif
913     _codecId = kCodecNoCodec;
914     _playoutPositionMs = 0;
915     _reading = false;
916 
917     _startPointInMs = start;
918     _stopPointInMs = stop;
919 
920     // Read the codec name
921     int32_t cnt = 0;
922     char buf[64];
923     do
924     {
925         in.Read(&buf[cnt++], 1);
926     } while ((buf[cnt-1] != '\n') && (64 > cnt));
927 
928     if(cnt==64)
929     {
930         return -1;
931     }
932     buf[cnt]=0;
933 
934 #ifdef WEBRTC_CODEC_ILBC
935     if(!strcmp("#!iLBC20\n", buf))
936     {
937         codec_info_.pltype = 102;
938         strcpy(codec_info_.plname, "ilbc");
939         codec_info_.plfreq   = 8000;
940         codec_info_.pacsize  = 160;
941         codec_info_.channels = 1;
942         codec_info_.rate     = 13300;
943         _codecId = kCodecIlbc20Ms;
944 
945         if(_startPointInMs > 0)
946         {
947             while (_playoutPositionMs <= _startPointInMs)
948             {
949                 read_len = in.Read(buf, 38);
950                 if(read_len != 38)
951                 {
952                     return -1;
953                 }
954                 _playoutPositionMs += 20;
955             }
956         }
957     }
958 
959     if(!strcmp("#!iLBC30\n", buf))
960     {
961         codec_info_.pltype = 102;
962         strcpy(codec_info_.plname, "ilbc");
963         codec_info_.plfreq   = 8000;
964         codec_info_.pacsize  = 240;
965         codec_info_.channels = 1;
966         codec_info_.rate     = 13300;
967         _codecId = kCodecIlbc30Ms;
968 
969         if(_startPointInMs > 0)
970         {
971             while (_playoutPositionMs <= _startPointInMs)
972             {
973                 read_len = in.Read(buf, 50);
974                 if(read_len != 50)
975                 {
976                     return -1;
977                 }
978                 _playoutPositionMs += 20;
979             }
980         }
981     }
982 #endif
983     if(_codecId == kCodecNoCodec)
984     {
985         return -1;
986     }
987     _reading = true;
988     return 0;
989 }
990 
ReadCompressedData(InStream & in,int8_t * outData,size_t bufferSize)991 int32_t ModuleFileUtility::ReadCompressedData(InStream& in,
992                                               int8_t* outData,
993                                               size_t bufferSize)
994 {
995     WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
996                  "ModuleFileUtility::ReadCompressedData(in=0x%x, outData=0x%x, "
997                  "bytes=%" PRIuS ")", &in, outData, bufferSize);
998 
999     int bytesRead = 0;
1000 
1001     if(! _reading)
1002     {
1003         WEBRTC_TRACE(kTraceError, kTraceFile, _id, "not currently reading!");
1004         return -1;
1005     }
1006 
1007 #ifdef WEBRTC_CODEC_ILBC
1008     if((_codecId == kCodecIlbc20Ms) ||
1009         (_codecId == kCodecIlbc30Ms))
1010     {
1011         size_t byteSize = 0;
1012         if(_codecId == kCodecIlbc30Ms)
1013         {
1014             byteSize = 50;
1015         }
1016         if(_codecId == kCodecIlbc20Ms)
1017         {
1018             byteSize = 38;
1019         }
1020         if(bufferSize < byteSize)
1021         {
1022             WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1023                          "output buffer is too short to read ILBC compressed "
1024                          "data.");
1025             assert(false);
1026             return -1;
1027         }
1028 
1029         bytesRead = in.Read(outData, byteSize);
1030         if(bytesRead != static_cast<int>(byteSize))
1031         {
1032             if(!in.Rewind())
1033             {
1034                 InitCompressedReading(in, _startPointInMs, _stopPointInMs);
1035                 bytesRead = in.Read(outData, byteSize);
1036                 if(bytesRead != static_cast<int>(byteSize))
1037                 {
1038                     _reading = false;
1039                     return -1;
1040                 }
1041             }
1042             else
1043             {
1044                 _reading = false;
1045                 return -1;
1046             }
1047         }
1048     }
1049 #endif
1050     if(bytesRead == 0)
1051     {
1052         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1053                      "ReadCompressedData() no bytes read, codec not supported");
1054         return -1;
1055     }
1056 
1057     _playoutPositionMs += 20;
1058     if((_stopPointInMs > 0) &&
1059         (_playoutPositionMs >= _stopPointInMs))
1060     {
1061         if(!in.Rewind())
1062         {
1063             InitCompressedReading(in, _startPointInMs, _stopPointInMs);
1064         }
1065         else
1066         {
1067             _reading = false;
1068         }
1069     }
1070     return bytesRead;
1071 }
1072 
InitCompressedWriting(OutStream & out,const CodecInst & codecInst)1073 int32_t ModuleFileUtility::InitCompressedWriting(
1074     OutStream& out,
1075     const CodecInst& codecInst)
1076 {
1077     WEBRTC_TRACE(kTraceDebug, kTraceFile, _id,
1078                  "ModuleFileUtility::InitCompressedWriting(out= 0x%x, "
1079                  "codecName= %s)", &out, codecInst.plname);
1080 
1081     _writing = false;
1082 
1083 #ifdef WEBRTC_CODEC_ILBC
1084     if(STR_CASE_CMP(codecInst.plname, "ilbc") == 0)
1085     {
1086         if(codecInst.pacsize == 160)
1087         {
1088             _codecId = kCodecIlbc20Ms;
1089             out.Write("#!iLBC20\n",9);
1090         }
1091         else if(codecInst.pacsize == 240)
1092         {
1093             _codecId = kCodecIlbc30Ms;
1094             out.Write("#!iLBC30\n",9);
1095         }
1096         else
1097         {
1098           WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1099                        "codecInst defines unsupported compression codec!");
1100             return -1;
1101         }
1102         memcpy(&codec_info_,&codecInst,sizeof(CodecInst));
1103         _writing = true;
1104         return 0;
1105     }
1106 #endif
1107 
1108     WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1109                  "codecInst defines unsupported compression codec!");
1110     return -1;
1111 }
1112 
WriteCompressedData(OutStream & out,const int8_t * buffer,const size_t dataLength)1113 int32_t ModuleFileUtility::WriteCompressedData(
1114     OutStream& out,
1115     const int8_t* buffer,
1116     const size_t dataLength)
1117 {
1118     WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1119                  "ModuleFileUtility::WriteCompressedData(out= 0x%x, buf= 0x%x, "
1120                  "dataLen= %" PRIuS ")", &out, buffer, dataLength);
1121 
1122     if(buffer == NULL)
1123     {
1124         WEBRTC_TRACE(kTraceError, kTraceFile, _id,"buffer NULL");
1125     }
1126 
1127     if(!out.Write(buffer, dataLength))
1128     {
1129         return -1;
1130     }
1131     return static_cast<int32_t>(dataLength);
1132 }
1133 
InitPCMReading(InStream & pcm,const uint32_t start,const uint32_t stop,uint32_t freq)1134 int32_t ModuleFileUtility::InitPCMReading(InStream& pcm,
1135                                           const uint32_t start,
1136                                           const uint32_t stop,
1137                                           uint32_t freq)
1138 {
1139     WEBRTC_TRACE(kTraceInfo, kTraceFile, _id,
1140                  "ModuleFileUtility::InitPCMReading(pcm= 0x%x, start=%d, "
1141                  "stop=%d, freq=%d)", &pcm, start, stop, freq);
1142 
1143     int8_t dummy[320];
1144     int read_len;
1145 
1146     _playoutPositionMs = 0;
1147     _startPointInMs = start;
1148     _stopPointInMs = stop;
1149     _reading = false;
1150 
1151     if(freq == 8000)
1152     {
1153         strcpy(codec_info_.plname, "L16");
1154         codec_info_.pltype   = -1;
1155         codec_info_.plfreq   = 8000;
1156         codec_info_.pacsize  = 160;
1157         codec_info_.channels = 1;
1158         codec_info_.rate     = 128000;
1159         _codecId = kCodecL16_8Khz;
1160     }
1161     else if(freq == 16000)
1162     {
1163         strcpy(codec_info_.plname, "L16");
1164         codec_info_.pltype   = -1;
1165         codec_info_.plfreq   = 16000;
1166         codec_info_.pacsize  = 320;
1167         codec_info_.channels = 1;
1168         codec_info_.rate     = 256000;
1169         _codecId = kCodecL16_16kHz;
1170     }
1171     else if(freq == 32000)
1172     {
1173         strcpy(codec_info_.plname, "L16");
1174         codec_info_.pltype   = -1;
1175         codec_info_.plfreq   = 32000;
1176         codec_info_.pacsize  = 320;
1177         codec_info_.channels = 1;
1178         codec_info_.rate     = 512000;
1179         _codecId = kCodecL16_32Khz;
1180     }
1181 
1182     // Readsize for 10ms of audio data (2 bytes per sample).
1183     _readSizeBytes = 2 * codec_info_. plfreq / 100;
1184     if(_startPointInMs > 0)
1185     {
1186         while (_playoutPositionMs < _startPointInMs)
1187         {
1188             read_len = pcm.Read(dummy, _readSizeBytes);
1189             if(read_len != static_cast<int>(_readSizeBytes))
1190             {
1191                 return -1;  // Must have reached EOF before start position!
1192             }
1193             _playoutPositionMs += 10;
1194         }
1195     }
1196     _reading = true;
1197     return 0;
1198 }
1199 
ReadPCMData(InStream & pcm,int8_t * outData,size_t bufferSize)1200 int32_t ModuleFileUtility::ReadPCMData(InStream& pcm,
1201                                        int8_t* outData,
1202                                        size_t bufferSize)
1203 {
1204     WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1205                  "ModuleFileUtility::ReadPCMData(pcm= 0x%x, outData= 0x%x, "
1206                  "bufSize= %" PRIuS ")", &pcm, outData, bufferSize);
1207 
1208     if(outData == NULL)
1209     {
1210         WEBRTC_TRACE(kTraceError, kTraceFile, _id, "buffer NULL");
1211     }
1212 
1213     // Readsize for 10ms of audio data (2 bytes per sample).
1214     size_t bytesRequested = static_cast<size_t>(2 * codec_info_.plfreq / 100);
1215     if(bufferSize <  bytesRequested)
1216     {
1217         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1218                    "ReadPCMData: buffer not long enough for a 10ms frame.");
1219         assert(false);
1220         return -1;
1221     }
1222 
1223     int bytesRead = pcm.Read(outData, bytesRequested);
1224     if(bytesRead < static_cast<int>(bytesRequested))
1225     {
1226         if(pcm.Rewind() == -1)
1227         {
1228             _reading = false;
1229         }
1230         else
1231         {
1232             if(InitPCMReading(pcm, _startPointInMs, _stopPointInMs,
1233                               codec_info_.plfreq) == -1)
1234             {
1235                 _reading = false;
1236             }
1237             else
1238             {
1239                 size_t rest = bytesRequested - bytesRead;
1240                 int len = pcm.Read(&(outData[bytesRead]), rest);
1241                 if(len == static_cast<int>(rest))
1242                 {
1243                     bytesRead += len;
1244                 }
1245                 else
1246                 {
1247                     _reading = false;
1248                 }
1249             }
1250             if(bytesRead <= 0)
1251             {
1252                 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1253                              "ReadPCMData: Failed to rewind audio file.");
1254                 return -1;
1255             }
1256         }
1257     }
1258 
1259     if(bytesRead <= 0)
1260     {
1261         WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1262                      "ReadPCMData: end of file");
1263         return -1;
1264     }
1265     _playoutPositionMs += 10;
1266     if(_stopPointInMs && _playoutPositionMs >= _stopPointInMs)
1267     {
1268         if(!pcm.Rewind())
1269         {
1270             if(InitPCMReading(pcm, _startPointInMs, _stopPointInMs,
1271                               codec_info_.plfreq) == -1)
1272             {
1273                 _reading = false;
1274             }
1275         }
1276     }
1277     return bytesRead;
1278 }
1279 
InitPCMWriting(OutStream & out,uint32_t freq)1280 int32_t ModuleFileUtility::InitPCMWriting(OutStream& out, uint32_t freq)
1281 {
1282 
1283     if(freq == 8000)
1284     {
1285         strcpy(codec_info_.plname, "L16");
1286         codec_info_.pltype   = -1;
1287         codec_info_.plfreq   = 8000;
1288         codec_info_.pacsize  = 160;
1289         codec_info_.channels = 1;
1290         codec_info_.rate     = 128000;
1291 
1292         _codecId = kCodecL16_8Khz;
1293     }
1294     else if(freq == 16000)
1295     {
1296         strcpy(codec_info_.plname, "L16");
1297         codec_info_.pltype   = -1;
1298         codec_info_.plfreq   = 16000;
1299         codec_info_.pacsize  = 320;
1300         codec_info_.channels = 1;
1301         codec_info_.rate     = 256000;
1302 
1303         _codecId = kCodecL16_16kHz;
1304     }
1305     else if(freq == 32000)
1306     {
1307         strcpy(codec_info_.plname, "L16");
1308         codec_info_.pltype   = -1;
1309         codec_info_.plfreq   = 32000;
1310         codec_info_.pacsize  = 320;
1311         codec_info_.channels = 1;
1312         codec_info_.rate     = 512000;
1313 
1314         _codecId = kCodecL16_32Khz;
1315     }
1316     if((_codecId != kCodecL16_8Khz) &&
1317        (_codecId != kCodecL16_16kHz) &&
1318        (_codecId != kCodecL16_32Khz))
1319     {
1320         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1321                      "CodecInst is not 8KHz PCM or 16KHz PCM!");
1322         return -1;
1323     }
1324     _writing = true;
1325     _bytesWritten = 0;
1326     return 0;
1327 }
1328 
WritePCMData(OutStream & out,const int8_t * buffer,const size_t dataLength)1329 int32_t ModuleFileUtility::WritePCMData(OutStream& out,
1330                                         const int8_t*  buffer,
1331                                         const size_t dataLength)
1332 {
1333     WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1334                  "ModuleFileUtility::WritePCMData(out= 0x%x, buf= 0x%x, "
1335                  "dataLen= %" PRIuS ")", &out, buffer, dataLength);
1336 
1337     if(buffer == NULL)
1338     {
1339         WEBRTC_TRACE(kTraceError, kTraceFile, _id, "buffer NULL");
1340     }
1341 
1342     if(!out.Write(buffer, dataLength))
1343     {
1344         return -1;
1345     }
1346 
1347     _bytesWritten += dataLength;
1348     return static_cast<int32_t>(dataLength);
1349 }
1350 
codec_info(CodecInst & codecInst)1351 int32_t ModuleFileUtility::codec_info(CodecInst& codecInst)
1352 {
1353     WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1354                  "ModuleFileUtility::codec_info(codecInst= 0x%x)", &codecInst);
1355 
1356     if(!_reading && !_writing)
1357     {
1358         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1359                      "CodecInst: not currently reading audio file!");
1360         return -1;
1361     }
1362     memcpy(&codecInst,&codec_info_,sizeof(CodecInst));
1363     return 0;
1364 }
1365 
set_codec_info(const CodecInst & codecInst)1366 int32_t ModuleFileUtility::set_codec_info(const CodecInst& codecInst)
1367 {
1368 
1369     _codecId = kCodecNoCodec;
1370     if(STR_CASE_CMP(codecInst.plname, "PCMU") == 0)
1371     {
1372         _codecId = kCodecPcmu;
1373     }
1374     else if(STR_CASE_CMP(codecInst.plname, "PCMA") == 0)
1375     {
1376         _codecId = kCodecPcma;
1377     }
1378     else if(STR_CASE_CMP(codecInst.plname, "L16") == 0)
1379     {
1380         if(codecInst.plfreq == 8000)
1381         {
1382             _codecId = kCodecL16_8Khz;
1383         }
1384         else if(codecInst.plfreq == 16000)
1385         {
1386             _codecId = kCodecL16_16kHz;
1387         }
1388         else if(codecInst.plfreq == 32000)
1389         {
1390             _codecId = kCodecL16_32Khz;
1391         }
1392     }
1393 #ifdef WEBRTC_CODEC_ILBC
1394     else if(STR_CASE_CMP(codecInst.plname, "ilbc") == 0)
1395     {
1396         if(codecInst.pacsize == 160)
1397         {
1398             _codecId = kCodecIlbc20Ms;
1399         }
1400         else if(codecInst.pacsize == 240)
1401         {
1402             _codecId = kCodecIlbc30Ms;
1403         }
1404     }
1405 #endif
1406 #if(defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
1407     else if(STR_CASE_CMP(codecInst.plname, "isac") == 0)
1408     {
1409         if(codecInst.plfreq == 16000)
1410         {
1411             _codecId = kCodecIsac;
1412         }
1413         else if(codecInst.plfreq == 32000)
1414         {
1415             _codecId = kCodecIsacSwb;
1416         }
1417     }
1418 #endif
1419 #ifdef WEBRTC_CODEC_G722
1420     else if(STR_CASE_CMP(codecInst.plname, "G722") == 0)
1421     {
1422         _codecId = kCodecG722;
1423     }
1424 #endif
1425     if(_codecId == kCodecNoCodec)
1426     {
1427         return -1;
1428     }
1429     memcpy(&codec_info_, &codecInst, sizeof(CodecInst));
1430     return 0;
1431 }
1432 
FileDurationMs(const char * fileName,const FileFormats fileFormat,const uint32_t freqInHz)1433 int32_t ModuleFileUtility::FileDurationMs(const char* fileName,
1434                                           const FileFormats fileFormat,
1435                                           const uint32_t freqInHz)
1436 {
1437 
1438     if(fileName == NULL)
1439     {
1440         WEBRTC_TRACE(kTraceError, kTraceFile, _id, "filename NULL");
1441         return -1;
1442     }
1443 
1444     int32_t time_in_ms = -1;
1445     struct stat file_size;
1446     if(stat(fileName,&file_size) == -1)
1447     {
1448         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1449                      "failed to retrieve file size with stat!");
1450         return -1;
1451     }
1452     FileWrapper* inStreamObj = FileWrapper::Create();
1453     if(inStreamObj == NULL)
1454     {
1455         WEBRTC_TRACE(kTraceMemory, kTraceFile, _id,
1456                      "failed to create InStream object!");
1457         return -1;
1458     }
1459     if(inStreamObj->OpenFile(fileName, true) == -1)
1460     {
1461         delete inStreamObj;
1462         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1463                      "failed to open file %s!", fileName);
1464         return -1;
1465     }
1466 
1467     switch (fileFormat)
1468     {
1469         case kFileFormatWavFile:
1470         {
1471             if(ReadWavHeader(*inStreamObj) == -1)
1472             {
1473                 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1474                              "failed to read WAV file header!");
1475                 return -1;
1476             }
1477             time_in_ms = ((file_size.st_size - 44) /
1478                           (_wavFormatObj.nAvgBytesPerSec/1000));
1479             break;
1480         }
1481         case kFileFormatPcm16kHzFile:
1482         {
1483             // 16 samples per ms. 2 bytes per sample.
1484             int32_t denominator = 16*2;
1485             time_in_ms = (file_size.st_size)/denominator;
1486             break;
1487         }
1488         case kFileFormatPcm8kHzFile:
1489         {
1490             // 8 samples per ms. 2 bytes per sample.
1491             int32_t denominator = 8*2;
1492             time_in_ms = (file_size.st_size)/denominator;
1493             break;
1494         }
1495         case kFileFormatCompressedFile:
1496         {
1497             int32_t cnt = 0;
1498             int read_len = 0;
1499             char buf[64];
1500             do
1501             {
1502                 read_len = inStreamObj->Read(&buf[cnt++], 1);
1503                 if(read_len != 1)
1504                 {
1505                     return -1;
1506                 }
1507             } while ((buf[cnt-1] != '\n') && (64 > cnt));
1508 
1509             if(cnt == 64)
1510             {
1511                 return -1;
1512             }
1513             else
1514             {
1515                 buf[cnt] = 0;
1516             }
1517 #ifdef WEBRTC_CODEC_ILBC
1518             if(!strcmp("#!iLBC20\n", buf))
1519             {
1520                 // 20 ms is 304 bits
1521                 time_in_ms = ((file_size.st_size)*160)/304;
1522                 break;
1523             }
1524             if(!strcmp("#!iLBC30\n", buf))
1525             {
1526                 // 30 ms takes 400 bits.
1527                 // file size in bytes * 8 / 400 is the number of
1528                 // 30 ms frames in the file ->
1529                 // time_in_ms = file size * 8 / 400 * 30
1530                 time_in_ms = ((file_size.st_size)*240)/400;
1531                 break;
1532             }
1533 #endif
1534             break;
1535         }
1536         case kFileFormatPreencodedFile:
1537         {
1538             WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1539                          "cannot determine duration of Pre-Encoded file!");
1540             break;
1541         }
1542         default:
1543             WEBRTC_TRACE(kTraceError, kTraceFile, _id,
1544                          "unsupported file format %d!", fileFormat);
1545             break;
1546     }
1547     inStreamObj->CloseFile();
1548     delete inStreamObj;
1549     return time_in_ms;
1550 }
1551 
PlayoutPositionMs()1552 uint32_t ModuleFileUtility::PlayoutPositionMs()
1553 {
1554     WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1555                  "ModuleFileUtility::PlayoutPosition()");
1556 
1557     return _reading ? _playoutPositionMs : 0;
1558 }
1559 }  // namespace webrtc
1560