blob: df6a5bfbcaf8beed8872124214b392ec9891fb73 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
mflodman@webrtc.org1f992802012-01-27 13:42:53 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
pbos@webrtc.org8b062002013-07-12 08:28:10 +000011#include "webrtc/modules/utility/source/file_player_impl.h"
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +000012#include "webrtc/system_wrappers/interface/logging.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000013
niklase@google.com470e71d2011-07-07 08:21:25 +000014namespace webrtc {
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +000015FilePlayer* FilePlayer::CreateFilePlayer(uint32_t instanceID,
niklase@google.com470e71d2011-07-07 08:21:25 +000016 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);
andresp@webrtc.orge8f50df2015-03-02 13:07:02 +000028 default:
mflodman@webrtc.orgc80d9d92012-02-06 10:11:25 +000029 assert(false);
niklase@google.com470e71d2011-07-07 08:21:25 +000030 return NULL;
31 }
32}
33
34void FilePlayer::DestroyFilePlayer(FilePlayer* player)
35{
36 delete player;
37}
38
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +000039FilePlayerImpl::FilePlayerImpl(const uint32_t instanceID,
niklase@google.com470e71d2011-07-07 08:21:25 +000040 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),
henrike@webrtc.org6b9253e2012-02-15 18:48:16 +000049 _resampler(),
niklase@google.com470e71d2011-07-07 08:21:25 +000050 _scaling(1.0)
51{
52 _codec.plfreq = 0;
53}
54
55FilePlayerImpl::~FilePlayerImpl()
56{
57 MediaFile::DestroyMediaFile(&_fileModule);
58}
59
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +000060int32_t FilePlayerImpl::Frequency() const
niklase@google.com470e71d2011-07-07 08:21:25 +000061{
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
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +000090int32_t FilePlayerImpl::AudioCodec(CodecInst& audioCodec) const
niklase@google.com470e71d2011-07-07 08:21:25 +000091{
92 audioCodec = _codec;
93 return 0;
94}
95
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +000096int32_t FilePlayerImpl::Get10msAudioFromFile(
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +000097 int16_t* outBuffer,
98 int& lengthInSamples,
99 int frequencyInHz)
niklase@google.com470e71d2011-07-07 08:21:25 +0000100{
101 if(_codec.plfreq == 0)
102 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000103 LOG(LS_WARNING) << "Get10msAudioFromFile() playing not started!"
104 << " codec freq = " << _codec.plfreq
105 << ", wanted freq = " << frequencyInHz;
niklase@google.com470e71d2011-07-07 08:21:25 +0000106 return -1;
107 }
108
109 AudioFrame unresampledAudioFrame;
110 if(STR_CASE_CMP(_codec.plname, "L16") == 0)
111 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000112 unresampledAudioFrame.sample_rate_hz_ = _codec.plfreq;
niklase@google.com470e71d2011-07-07 08:21:25 +0000113
114 // L16 is un-encoded data. Just pull 10 ms.
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000115 size_t lengthInBytes =
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000116 sizeof(unresampledAudioFrame.data_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000117 if (_fileModule.PlayoutAudioData(
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000118 (int8_t*)unresampledAudioFrame.data_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000119 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.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000130 unresampledAudioFrame.samples_per_channel_ =
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000131 (uint16_t)lengthInBytes >> 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000132
Andrew MacDonald2c9c83d2015-03-30 10:08:22 -0700133 } else {
niklase@google.com470e71d2011-07-07 08:21:25 +0000134 // Decode will generate 10 ms of audio data. PlayoutAudioData(..)
135 // expects a full frame. If the frame size is larger than 10 ms,
136 // PlayoutAudioData(..) data should be called proportionally less often.
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000137 int16_t encodedBuffer[MAX_AUDIO_BUFFER_IN_SAMPLES];
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000138 size_t encodedLengthInBytes = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000139 if(++_numberOf10MsInDecoder >= _numberOf10MsPerFrame)
140 {
141 _numberOf10MsInDecoder = 0;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000142 size_t bytesFromFile = sizeof(encodedBuffer);
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000143 if (_fileModule.PlayoutAudioData((int8_t*)encodedBuffer,
niklase@google.com470e71d2011-07-07 08:21:25 +0000144 bytesFromFile) == -1)
145 {
146 // End of file reached.
147 return -1;
148 }
149 encodedLengthInBytes = bytesFromFile;
150 }
151 if(_audioDecoder.Decode(unresampledAudioFrame,frequencyInHz,
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000152 (int8_t*)encodedBuffer,
niklase@google.com470e71d2011-07-07 08:21:25 +0000153 encodedLengthInBytes) == -1)
154 {
155 return -1;
156 }
157 }
158
159 int outLen = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000160 if(_resampler.ResetIfNeeded(unresampledAudioFrame.sample_rate_hz_,
Andrew MacDonald2c9c83d2015-03-30 10:08:22 -0700161 frequencyInHz, 1))
niklase@google.com470e71d2011-07-07 08:21:25 +0000162 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000163 LOG(LS_WARNING) << "Get10msAudioFromFile() unexpected codec.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000164
165 // New sampling frequency. Update state.
166 outLen = frequencyInHz / 100;
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000167 memset(outBuffer, 0, outLen * sizeof(int16_t));
niklase@google.com470e71d2011-07-07 08:21:25 +0000168 return 0;
169 }
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000170 _resampler.Push(unresampledAudioFrame.data_,
171 unresampledAudioFrame.samples_per_channel_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000172 outBuffer,
173 MAX_AUDIO_BUFFER_IN_SAMPLES,
174 outLen);
175
176 lengthInSamples = outLen;
177
178 if(_scaling != 1.0)
179 {
180 for (int i = 0;i < outLen; i++)
181 {
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000182 outBuffer[i] = (int16_t)(outBuffer[i] * _scaling);
niklase@google.com470e71d2011-07-07 08:21:25 +0000183 }
184 }
185 _decodedLengthInMS += 10;
186 return 0;
187}
188
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000189int32_t FilePlayerImpl::RegisterModuleFileCallback(FileCallback* callback)
niklase@google.com470e71d2011-07-07 08:21:25 +0000190{
191 return _fileModule.SetModuleFileCallback(callback);
192}
193
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000194int32_t FilePlayerImpl::SetAudioScaling(float scaleFactor)
niklase@google.com470e71d2011-07-07 08:21:25 +0000195{
196 if((scaleFactor >= 0)&&(scaleFactor <= 2.0))
197 {
198 _scaling = scaleFactor;
199 return 0;
200 }
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000201 LOG(LS_WARNING) << "SetAudioScaling() non-allowed scale factor.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000202 return -1;
203}
204
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000205int32_t FilePlayerImpl::StartPlayingFile(const char* fileName,
206 bool loop,
207 uint32_t startPosition,
208 float volumeScaling,
209 uint32_t notification,
210 uint32_t stopPosition,
211 const CodecInst* codecInst)
niklase@google.com470e71d2011-07-07 08:21:25 +0000212{
213 if (_fileFormat == kFileFormatPcm16kHzFile ||
214 _fileFormat == kFileFormatPcm8kHzFile||
215 _fileFormat == kFileFormatPcm32kHzFile )
216 {
217 CodecInst codecInstL16;
218 strncpy(codecInstL16.plname,"L16",32);
219 codecInstL16.pltype = 93;
220 codecInstL16.channels = 1;
221
222 if (_fileFormat == kFileFormatPcm8kHzFile)
223 {
224 codecInstL16.rate = 128000;
225 codecInstL16.plfreq = 8000;
226 codecInstL16.pacsize = 80;
227
228 } else if(_fileFormat == kFileFormatPcm16kHzFile)
229 {
230 codecInstL16.rate = 256000;
231 codecInstL16.plfreq = 16000;
232 codecInstL16.pacsize = 160;
233
234 }else if(_fileFormat == kFileFormatPcm32kHzFile)
235 {
236 codecInstL16.rate = 512000;
237 codecInstL16.plfreq = 32000;
238 codecInstL16.pacsize = 160;
239 } else
240 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000241 LOG(LS_ERROR) << "StartPlayingFile() sample frequency not "
242 << "supported for PCM format.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000243 return -1;
244 }
245
246 if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
247 _fileFormat, &codecInstL16,
248 startPosition,
249 stopPosition) == -1)
250 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000251 LOG(LS_WARNING) << "StartPlayingFile() failed to initialize "
252 << "pcm file " << fileName;
niklase@google.com470e71d2011-07-07 08:21:25 +0000253 return -1;
254 }
255 SetAudioScaling(volumeScaling);
256 }else if(_fileFormat == kFileFormatPreencodedFile)
257 {
258 if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
259 _fileFormat, codecInst) == -1)
260 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000261 LOG(LS_WARNING) << "StartPlayingFile() failed to initialize "
262 << "pre-encoded file " << fileName;
niklase@google.com470e71d2011-07-07 08:21:25 +0000263 return -1;
264 }
265 } else
266 {
267 CodecInst* no_inst = NULL;
268 if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
269 _fileFormat, no_inst,
270 startPosition,
271 stopPosition) == -1)
272 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000273 LOG(LS_WARNING) << "StartPlayingFile() failed to initialize file "
274 << fileName;
niklase@google.com470e71d2011-07-07 08:21:25 +0000275 return -1;
276 }
277 SetAudioScaling(volumeScaling);
278 }
279 if (SetUpAudioDecoder() == -1)
280 {
281 StopPlayingFile();
282 return -1;
283 }
284 return 0;
285}
286
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000287int32_t FilePlayerImpl::StartPlayingFile(InStream& sourceStream,
288 uint32_t startPosition,
289 float volumeScaling,
290 uint32_t notification,
291 uint32_t stopPosition,
292 const CodecInst* codecInst)
niklase@google.com470e71d2011-07-07 08:21:25 +0000293{
294 if (_fileFormat == kFileFormatPcm16kHzFile ||
295 _fileFormat == kFileFormatPcm32kHzFile ||
296 _fileFormat == kFileFormatPcm8kHzFile)
297 {
298 CodecInst codecInstL16;
299 strncpy(codecInstL16.plname,"L16",32);
300 codecInstL16.pltype = 93;
301 codecInstL16.channels = 1;
302
303 if (_fileFormat == kFileFormatPcm8kHzFile)
304 {
305 codecInstL16.rate = 128000;
306 codecInstL16.plfreq = 8000;
307 codecInstL16.pacsize = 80;
308
309 }else if (_fileFormat == kFileFormatPcm16kHzFile)
310 {
311 codecInstL16.rate = 256000;
312 codecInstL16.plfreq = 16000;
313 codecInstL16.pacsize = 160;
314
315 }else if (_fileFormat == kFileFormatPcm32kHzFile)
316 {
317 codecInstL16.rate = 512000;
318 codecInstL16.plfreq = 32000;
319 codecInstL16.pacsize = 160;
320 }else
321 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000322 LOG(LS_ERROR) << "StartPlayingFile() sample frequency not "
323 << "supported for PCM format.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000324 return -1;
325 }
326 if (_fileModule.StartPlayingAudioStream(sourceStream, notification,
327 _fileFormat, &codecInstL16,
328 startPosition,
329 stopPosition) == -1)
330 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000331 LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream "
332 << "playout.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000333 return -1;
334 }
335
336 }else if(_fileFormat == kFileFormatPreencodedFile)
337 {
338 if (_fileModule.StartPlayingAudioStream(sourceStream, notification,
339 _fileFormat, codecInst) == -1)
340 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000341 LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream "
342 << "playout.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000343 return -1;
344 }
345 } else {
346 CodecInst* no_inst = NULL;
347 if (_fileModule.StartPlayingAudioStream(sourceStream, notification,
348 _fileFormat, no_inst,
349 startPosition,
350 stopPosition) == -1)
351 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000352 LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream "
353 << "playout.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000354 return -1;
355 }
356 }
357 SetAudioScaling(volumeScaling);
358
359 if (SetUpAudioDecoder() == -1)
360 {
361 StopPlayingFile();
362 return -1;
363 }
364 return 0;
365}
366
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000367int32_t FilePlayerImpl::StopPlayingFile()
niklase@google.com470e71d2011-07-07 08:21:25 +0000368{
369 memset(&_codec, 0, sizeof(CodecInst));
370 _numberOf10MsPerFrame = 0;
371 _numberOf10MsInDecoder = 0;
372 return _fileModule.StopPlaying();
373}
374
375bool FilePlayerImpl::IsPlayingFile() const
376{
377 return _fileModule.IsPlaying();
378}
379
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000380int32_t FilePlayerImpl::GetPlayoutPosition(uint32_t& durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000381{
382 return _fileModule.PlayoutPositionMs(durationMs);
383}
384
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000385int32_t FilePlayerImpl::SetUpAudioDecoder()
niklase@google.com470e71d2011-07-07 08:21:25 +0000386{
387 if ((_fileModule.codec_info(_codec) == -1))
388 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000389 LOG(LS_WARNING) << "Failed to retrieve codec info of file data.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000390 return -1;
391 }
392 if( STR_CASE_CMP(_codec.plname, "L16") != 0 &&
393 _audioDecoder.SetDecodeCodec(_codec,AMRFileStorage) == -1)
394 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000395 LOG(LS_WARNING) << "SetUpAudioDecoder() codec " << _codec.plname
396 << " not supported.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000397 return -1;
398 }
399 _numberOf10MsPerFrame = _codec.pacsize / (_codec.plfreq / 100);
400 _numberOf10MsInDecoder = 0;
401 return 0;
402}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000403} // namespace webrtc