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/utility/source/file_player_impl.h"
12#include "webrtc/system_wrappers/include/logging.h"
13
14namespace webrtc {
15FilePlayer* FilePlayer::CreateFilePlayer(uint32_t instanceID,
16                                         FileFormats fileFormat)
17{
18    switch(fileFormat)
19    {
20    case kFileFormatWavFile:
21    case kFileFormatCompressedFile:
22    case kFileFormatPreencodedFile:
23    case kFileFormatPcm16kHzFile:
24    case kFileFormatPcm8kHzFile:
25    case kFileFormatPcm32kHzFile:
26        // audio formats
27        return new FilePlayerImpl(instanceID, fileFormat);
28    default:
29        assert(false);
30        return NULL;
31    }
32}
33
34void FilePlayer::DestroyFilePlayer(FilePlayer* player)
35{
36    delete player;
37}
38
39FilePlayerImpl::FilePlayerImpl(const uint32_t instanceID,
40                               const FileFormats fileFormat)
41    : _instanceID(instanceID),
42      _fileFormat(fileFormat),
43      _fileModule(*MediaFile::CreateMediaFile(instanceID)),
44      _decodedLengthInMS(0),
45      _audioDecoder(instanceID),
46      _codec(),
47      _numberOf10MsPerFrame(0),
48      _numberOf10MsInDecoder(0),
49      _resampler(),
50      _scaling(1.0)
51{
52    _codec.plfreq = 0;
53}
54
55FilePlayerImpl::~FilePlayerImpl()
56{
57    MediaFile::DestroyMediaFile(&_fileModule);
58}
59
60int32_t FilePlayerImpl::Frequency() const
61{
62    if(_codec.plfreq == 0)
63    {
64        return -1;
65    }
66    // Make sure that sample rate is 8,16 or 32 kHz. E.g. WAVE files may have
67    // other sampling rates.
68    if(_codec.plfreq == 11000)
69    {
70        return 16000;
71    }
72    else if(_codec.plfreq == 22000)
73    {
74        return 32000;
75    }
76    else if(_codec.plfreq == 44000)
77    {
78        return 32000;
79    }
80    else if(_codec.plfreq == 48000)
81    {
82        return 32000;
83    }
84    else
85    {
86        return _codec.plfreq;
87    }
88}
89
90int32_t FilePlayerImpl::AudioCodec(CodecInst& audioCodec) const
91{
92    audioCodec = _codec;
93    return 0;
94}
95
96int32_t FilePlayerImpl::Get10msAudioFromFile(
97    int16_t* outBuffer,
98    size_t& lengthInSamples,
99    int frequencyInHz)
100{
101    if(_codec.plfreq == 0)
102    {
103        LOG(LS_WARNING) << "Get10msAudioFromFile() playing not started!"
104                        << " codec freq = " << _codec.plfreq
105                        << ", wanted freq = " << frequencyInHz;
106        return -1;
107    }
108
109    AudioFrame unresampledAudioFrame;
110    if(STR_CASE_CMP(_codec.plname, "L16") == 0)
111    {
112        unresampledAudioFrame.sample_rate_hz_ = _codec.plfreq;
113
114        // L16 is un-encoded data. Just pull 10 ms.
115        size_t lengthInBytes =
116            sizeof(unresampledAudioFrame.data_);
117        if (_fileModule.PlayoutAudioData(
118                (int8_t*)unresampledAudioFrame.data_,
119                lengthInBytes) == -1)
120        {
121            // End of file reached.
122            return -1;
123        }
124        if(lengthInBytes == 0)
125        {
126            lengthInSamples = 0;
127            return 0;
128        }
129        // One sample is two bytes.
130        unresampledAudioFrame.samples_per_channel_ = lengthInBytes >> 1;
131
132    } else {
133        // Decode will generate 10 ms of audio data. PlayoutAudioData(..)
134        // expects a full frame. If the frame size is larger than 10 ms,
135        // PlayoutAudioData(..) data should be called proportionally less often.
136        int16_t encodedBuffer[MAX_AUDIO_BUFFER_IN_SAMPLES];
137        size_t encodedLengthInBytes = 0;
138        if(++_numberOf10MsInDecoder >= _numberOf10MsPerFrame)
139        {
140            _numberOf10MsInDecoder = 0;
141            size_t bytesFromFile = sizeof(encodedBuffer);
142            if (_fileModule.PlayoutAudioData((int8_t*)encodedBuffer,
143                                             bytesFromFile) == -1)
144            {
145                // End of file reached.
146                return -1;
147            }
148            encodedLengthInBytes = bytesFromFile;
149        }
150        if(_audioDecoder.Decode(unresampledAudioFrame,frequencyInHz,
151                                (int8_t*)encodedBuffer,
152                                encodedLengthInBytes) == -1)
153        {
154            return -1;
155        }
156    }
157
158    size_t outLen = 0;
159    if(_resampler.ResetIfNeeded(unresampledAudioFrame.sample_rate_hz_,
160                                frequencyInHz, 1))
161    {
162        LOG(LS_WARNING) << "Get10msAudioFromFile() unexpected codec.";
163
164        // New sampling frequency. Update state.
165        outLen = static_cast<size_t>(frequencyInHz / 100);
166        memset(outBuffer, 0, outLen * sizeof(int16_t));
167        return 0;
168    }
169    _resampler.Push(unresampledAudioFrame.data_,
170                    unresampledAudioFrame.samples_per_channel_,
171                    outBuffer,
172                    MAX_AUDIO_BUFFER_IN_SAMPLES,
173                    outLen);
174
175    lengthInSamples = outLen;
176
177    if(_scaling != 1.0)
178    {
179        for (size_t i = 0;i < outLen; i++)
180        {
181            outBuffer[i] = (int16_t)(outBuffer[i] * _scaling);
182        }
183    }
184    _decodedLengthInMS += 10;
185    return 0;
186}
187
188int32_t FilePlayerImpl::RegisterModuleFileCallback(FileCallback* callback)
189{
190    return _fileModule.SetModuleFileCallback(callback);
191}
192
193int32_t FilePlayerImpl::SetAudioScaling(float scaleFactor)
194{
195    if((scaleFactor >= 0)&&(scaleFactor <= 2.0))
196    {
197        _scaling = scaleFactor;
198        return 0;
199    }
200    LOG(LS_WARNING) << "SetAudioScaling() non-allowed scale factor.";
201    return -1;
202}
203
204int32_t FilePlayerImpl::StartPlayingFile(const char* fileName,
205                                         bool loop,
206                                         uint32_t startPosition,
207                                         float volumeScaling,
208                                         uint32_t notification,
209                                         uint32_t stopPosition,
210                                         const CodecInst* codecInst)
211{
212    if (_fileFormat == kFileFormatPcm16kHzFile ||
213        _fileFormat == kFileFormatPcm8kHzFile||
214        _fileFormat == kFileFormatPcm32kHzFile )
215    {
216        CodecInst codecInstL16;
217        strncpy(codecInstL16.plname,"L16",32);
218        codecInstL16.pltype   = 93;
219        codecInstL16.channels = 1;
220
221        if (_fileFormat == kFileFormatPcm8kHzFile)
222        {
223            codecInstL16.rate     = 128000;
224            codecInstL16.plfreq   = 8000;
225            codecInstL16.pacsize  = 80;
226
227        } else if(_fileFormat == kFileFormatPcm16kHzFile)
228        {
229            codecInstL16.rate     = 256000;
230            codecInstL16.plfreq   = 16000;
231            codecInstL16.pacsize  = 160;
232
233        }else if(_fileFormat == kFileFormatPcm32kHzFile)
234        {
235            codecInstL16.rate     = 512000;
236            codecInstL16.plfreq   = 32000;
237            codecInstL16.pacsize  = 160;
238        } else
239        {
240            LOG(LS_ERROR) << "StartPlayingFile() sample frequency not "
241                          << "supported for PCM format.";
242            return -1;
243        }
244
245        if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
246                                              _fileFormat, &codecInstL16,
247                                              startPosition,
248                                              stopPosition) == -1)
249        {
250            LOG(LS_WARNING) << "StartPlayingFile() failed to initialize "
251                            << "pcm file " << fileName;
252            return -1;
253        }
254        SetAudioScaling(volumeScaling);
255    }else if(_fileFormat == kFileFormatPreencodedFile)
256    {
257        if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
258                                              _fileFormat, codecInst) == -1)
259        {
260            LOG(LS_WARNING) << "StartPlayingFile() failed to initialize "
261                            << "pre-encoded file " << fileName;
262            return -1;
263        }
264    } else
265    {
266        CodecInst* no_inst = NULL;
267        if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
268                                              _fileFormat, no_inst,
269                                              startPosition,
270                                              stopPosition) == -1)
271        {
272            LOG(LS_WARNING) << "StartPlayingFile() failed to initialize file "
273                            << fileName;
274            return -1;
275        }
276        SetAudioScaling(volumeScaling);
277    }
278    if (SetUpAudioDecoder() == -1)
279    {
280        StopPlayingFile();
281        return -1;
282    }
283    return 0;
284}
285
286int32_t FilePlayerImpl::StartPlayingFile(InStream& sourceStream,
287                                         uint32_t startPosition,
288                                         float volumeScaling,
289                                         uint32_t notification,
290                                         uint32_t stopPosition,
291                                         const CodecInst* codecInst)
292{
293    if (_fileFormat == kFileFormatPcm16kHzFile ||
294        _fileFormat == kFileFormatPcm32kHzFile ||
295        _fileFormat == kFileFormatPcm8kHzFile)
296    {
297        CodecInst codecInstL16;
298        strncpy(codecInstL16.plname,"L16",32);
299        codecInstL16.pltype   = 93;
300        codecInstL16.channels = 1;
301
302        if (_fileFormat == kFileFormatPcm8kHzFile)
303        {
304            codecInstL16.rate     = 128000;
305            codecInstL16.plfreq   = 8000;
306            codecInstL16.pacsize  = 80;
307
308        }else if (_fileFormat == kFileFormatPcm16kHzFile)
309        {
310            codecInstL16.rate     = 256000;
311            codecInstL16.plfreq   = 16000;
312            codecInstL16.pacsize  = 160;
313
314        }else if (_fileFormat == kFileFormatPcm32kHzFile)
315        {
316            codecInstL16.rate     = 512000;
317            codecInstL16.plfreq   = 32000;
318            codecInstL16.pacsize  = 160;
319        }else
320        {
321            LOG(LS_ERROR) << "StartPlayingFile() sample frequency not "
322                          << "supported for PCM format.";
323            return -1;
324        }
325        if (_fileModule.StartPlayingAudioStream(sourceStream, notification,
326                                                _fileFormat, &codecInstL16,
327                                                startPosition,
328                                                stopPosition) == -1)
329        {
330            LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream "
331                          << "playout.";
332            return -1;
333        }
334
335    }else if(_fileFormat == kFileFormatPreencodedFile)
336    {
337        if (_fileModule.StartPlayingAudioStream(sourceStream, notification,
338                                                _fileFormat, codecInst) == -1)
339        {
340            LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream "
341                          << "playout.";
342            return -1;
343        }
344    } else {
345        CodecInst* no_inst = NULL;
346        if (_fileModule.StartPlayingAudioStream(sourceStream, notification,
347                                                _fileFormat, no_inst,
348                                                startPosition,
349                                                stopPosition) == -1)
350        {
351            LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream "
352                          << "playout.";
353            return -1;
354        }
355    }
356    SetAudioScaling(volumeScaling);
357
358    if (SetUpAudioDecoder() == -1)
359    {
360        StopPlayingFile();
361        return -1;
362    }
363    return 0;
364}
365
366int32_t FilePlayerImpl::StopPlayingFile()
367{
368    memset(&_codec, 0, sizeof(CodecInst));
369    _numberOf10MsPerFrame  = 0;
370    _numberOf10MsInDecoder = 0;
371    return _fileModule.StopPlaying();
372}
373
374bool FilePlayerImpl::IsPlayingFile() const
375{
376    return _fileModule.IsPlaying();
377}
378
379int32_t FilePlayerImpl::GetPlayoutPosition(uint32_t& durationMs)
380{
381    return _fileModule.PlayoutPositionMs(durationMs);
382}
383
384int32_t FilePlayerImpl::SetUpAudioDecoder()
385{
386    if ((_fileModule.codec_info(_codec) == -1))
387    {
388        LOG(LS_WARNING) << "Failed to retrieve codec info of file data.";
389        return -1;
390    }
391    if( STR_CASE_CMP(_codec.plname, "L16") != 0 &&
392        _audioDecoder.SetDecodeCodec(_codec) == -1)
393    {
394        LOG(LS_WARNING) << "SetUpAudioDecoder() codec " << _codec.plname
395                        << " not supported.";
396        return -1;
397    }
398    _numberOf10MsPerFrame = _codec.pacsize / (_codec.plfreq / 100);
399    _numberOf10MsInDecoder = 0;
400    return 0;
401}
402}  // namespace webrtc
403