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