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
26namespace {
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)
30struct 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)
39struct WAVE_CHUNK_header
40{
41   int8_t   fmt_ckID[4];
42   uint32_t fmt_ckSize;
43};
44}  // unnamed namespace
45
46namespace webrtc {
47ModuleFileUtility::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
69ModuleFileUtility::~ModuleFileUtility()
70{
71    WEBRTC_TRACE(kTraceMemory, kTraceFile, _id,
72                 "ModuleFileUtility::~ModuleFileUtility()");
73}
74
75int32_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
255int32_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
343int32_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
402int32_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
480int32_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
575int32_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
655int32_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
706int32_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
730int32_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
753int32_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
781int32_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
808int32_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
851int32_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
867int32_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
901int32_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
991int32_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
1073int32_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
1113int32_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
1134int32_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
1200int32_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
1280int32_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
1329int32_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
1351int32_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
1366int32_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
1433int32_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
1552uint32_t ModuleFileUtility::PlayoutPositionMs()
1553{
1554    WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
1555                 "ModuleFileUtility::PlayoutPosition()");
1556
1557    return _reading ? _playoutPositionMs : 0;
1558}
1559}  // namespace webrtc
1560