blob: 6d9aaae6b898c2f0077e62bfc32946b15603ed63 [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
kwiberg97744472017-01-10 01:12:51 -080011#include "webrtc/voice_engine/file_player.h"
kwiberg144dd272016-08-17 02:46:53 -070012
13#include "webrtc/common_audio/resampler/include/resampler.h"
14#include "webrtc/common_types.h"
kwiberg144dd272016-08-17 02:46:53 -070015#include "webrtc/modules/media_file/media_file.h"
16#include "webrtc/modules/media_file/media_file_defines.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020017#include "webrtc/rtc_base/logging.h"
kwiberg144dd272016-08-17 02:46:53 -070018#include "webrtc/typedefs.h"
kwiberg97744472017-01-10 01:12:51 -080019#include "webrtc/voice_engine/coder.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000020
niklase@google.com470e71d2011-07-07 08:21:25 +000021namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000022
kwiberg144dd272016-08-17 02:46:53 -070023namespace {
24
25class FilePlayerImpl : public FilePlayer {
26 public:
27 FilePlayerImpl(uint32_t instanceID, FileFormats fileFormat);
kwiberg4ec01d92016-08-22 08:43:54 -070028 ~FilePlayerImpl() override;
kwiberg144dd272016-08-17 02:46:53 -070029
kwiberg4ec01d92016-08-22 08:43:54 -070030 int Get10msAudioFromFile(int16_t* outBuffer,
31 size_t* lengthInSamples,
32 int frequencyInHz) override;
33 int32_t RegisterModuleFileCallback(FileCallback* callback) override;
34 int32_t StartPlayingFile(const char* fileName,
35 bool loop,
36 uint32_t startPosition,
37 float volumeScaling,
38 uint32_t notification,
39 uint32_t stopPosition,
40 const CodecInst* codecInst) override;
41 int32_t StartPlayingFile(InStream* sourceStream,
42 uint32_t startPosition,
43 float volumeScaling,
44 uint32_t notification,
45 uint32_t stopPosition,
46 const CodecInst* codecInst) override;
47 int32_t StopPlayingFile() override;
48 bool IsPlayingFile() const override;
49 int32_t GetPlayoutPosition(uint32_t* durationMs) override;
50 int32_t AudioCodec(CodecInst* audioCodec) const override;
51 int32_t Frequency() const override;
52 int32_t SetAudioScaling(float scaleFactor) override;
kwiberg144dd272016-08-17 02:46:53 -070053
kwiberg5a25d952016-08-17 07:31:12 -070054 private:
kwiberg144dd272016-08-17 02:46:53 -070055 int32_t SetUpAudioDecoder();
56
kwiberg144dd272016-08-17 02:46:53 -070057 const FileFormats _fileFormat;
58 MediaFile& _fileModule;
59
60 uint32_t _decodedLengthInMS;
61
kwiberg144dd272016-08-17 02:46:53 -070062 AudioCoder _audioDecoder;
63
64 CodecInst _codec;
65 int32_t _numberOf10MsPerFrame;
66 int32_t _numberOf10MsInDecoder;
67
68 Resampler _resampler;
69 float _scaling;
70};
niklase@google.com470e71d2011-07-07 08:21:25 +000071
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +000072FilePlayerImpl::FilePlayerImpl(const uint32_t instanceID,
niklase@google.com470e71d2011-07-07 08:21:25 +000073 const FileFormats fileFormat)
kwiberg5a25d952016-08-17 07:31:12 -070074 : _fileFormat(fileFormat),
niklase@google.com470e71d2011-07-07 08:21:25 +000075 _fileModule(*MediaFile::CreateMediaFile(instanceID)),
76 _decodedLengthInMS(0),
77 _audioDecoder(instanceID),
78 _codec(),
79 _numberOf10MsPerFrame(0),
80 _numberOf10MsInDecoder(0),
henrike@webrtc.org6b9253e2012-02-15 18:48:16 +000081 _resampler(),
kwiberga06ce492016-08-16 05:35:24 -070082 _scaling(1.0) {
83 _codec.plfreq = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000084}
85
kwiberga06ce492016-08-16 05:35:24 -070086FilePlayerImpl::~FilePlayerImpl() {
87 MediaFile::DestroyMediaFile(&_fileModule);
niklase@google.com470e71d2011-07-07 08:21:25 +000088}
89
kwiberga06ce492016-08-16 05:35:24 -070090int32_t FilePlayerImpl::Frequency() const {
91 if (_codec.plfreq == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +000092 return -1;
kwiberga06ce492016-08-16 05:35:24 -070093 }
94 // Make sure that sample rate is 8,16 or 32 kHz. E.g. WAVE files may have
95 // other sampling rates.
96 if (_codec.plfreq == 11000) {
97 return 16000;
98 } else if (_codec.plfreq == 22000) {
99 return 32000;
100 } else if (_codec.plfreq == 44000) {
101 return 32000;
102 } else if (_codec.plfreq == 48000) {
lliuubc436ed2017-03-31 16:32:28 -0700103 return 32000;
kwiberga06ce492016-08-16 05:35:24 -0700104 } else {
105 return _codec.plfreq;
106 }
107}
108
kwiberg4ec01d92016-08-22 08:43:54 -0700109int32_t FilePlayerImpl::AudioCodec(CodecInst* audioCodec) const {
110 *audioCodec = _codec;
kwiberga06ce492016-08-16 05:35:24 -0700111 return 0;
112}
113
114int32_t FilePlayerImpl::Get10msAudioFromFile(int16_t* outBuffer,
kwiberg4ec01d92016-08-22 08:43:54 -0700115 size_t* lengthInSamples,
kwiberga06ce492016-08-16 05:35:24 -0700116 int frequencyInHz) {
117 if (_codec.plfreq == 0) {
118 LOG(LS_WARNING) << "Get10msAudioFromFile() playing not started!"
119 << " codec freq = " << _codec.plfreq
120 << ", wanted freq = " << frequencyInHz;
121 return -1;
122 }
123
124 AudioFrame unresampledAudioFrame;
125 if (STR_CASE_CMP(_codec.plname, "L16") == 0) {
126 unresampledAudioFrame.sample_rate_hz_ = _codec.plfreq;
127
128 // L16 is un-encoded data. Just pull 10 ms.
yujo36b1a5f2017-06-12 12:45:32 -0700129 size_t lengthInBytes = AudioFrame::kMaxDataSizeBytes;
kwiberg4ec01d92016-08-22 08:43:54 -0700130 if (_fileModule.PlayoutAudioData(
yujo36b1a5f2017-06-12 12:45:32 -0700131 reinterpret_cast<int8_t*>(unresampledAudioFrame.mutable_data()),
kwiberg4ec01d92016-08-22 08:43:54 -0700132 lengthInBytes) == -1) {
kwiberga06ce492016-08-16 05:35:24 -0700133 // End of file reached.
134 return -1;
135 }
136 if (lengthInBytes == 0) {
kwiberg4ec01d92016-08-22 08:43:54 -0700137 *lengthInSamples = 0;
kwiberga06ce492016-08-16 05:35:24 -0700138 return 0;
139 }
140 // One sample is two bytes.
141 unresampledAudioFrame.samples_per_channel_ = lengthInBytes >> 1;
142
143 } else {
144 // Decode will generate 10 ms of audio data. PlayoutAudioData(..)
145 // expects a full frame. If the frame size is larger than 10 ms,
146 // PlayoutAudioData(..) data should be called proportionally less often.
147 int16_t encodedBuffer[MAX_AUDIO_BUFFER_IN_SAMPLES];
148 size_t encodedLengthInBytes = 0;
149 if (++_numberOf10MsInDecoder >= _numberOf10MsPerFrame) {
150 _numberOf10MsInDecoder = 0;
151 size_t bytesFromFile = sizeof(encodedBuffer);
kwiberg4ec01d92016-08-22 08:43:54 -0700152 if (_fileModule.PlayoutAudioData(reinterpret_cast<int8_t*>(encodedBuffer),
153 bytesFromFile) == -1) {
kwiberga06ce492016-08-16 05:35:24 -0700154 // End of file reached.
155 return -1;
156 }
157 encodedLengthInBytes = bytesFromFile;
158 }
kwiberg4ec01d92016-08-22 08:43:54 -0700159 if (_audioDecoder.Decode(&unresampledAudioFrame, frequencyInHz,
160 reinterpret_cast<int8_t*>(encodedBuffer),
kwiberga06ce492016-08-16 05:35:24 -0700161 encodedLengthInBytes) == -1) {
162 return -1;
163 }
164 }
165
166 size_t outLen = 0;
167 if (_resampler.ResetIfNeeded(unresampledAudioFrame.sample_rate_hz_,
168 frequencyInHz, 1)) {
169 LOG(LS_WARNING) << "Get10msAudioFromFile() unexpected codec.";
170
171 // New sampling frequency. Update state.
172 outLen = static_cast<size_t>(frequencyInHz / 100);
173 memset(outBuffer, 0, outLen * sizeof(int16_t));
174 return 0;
175 }
yujo36b1a5f2017-06-12 12:45:32 -0700176 _resampler.Push(unresampledAudioFrame.data(),
kwiberga06ce492016-08-16 05:35:24 -0700177 unresampledAudioFrame.samples_per_channel_, outBuffer,
178 MAX_AUDIO_BUFFER_IN_SAMPLES, outLen);
179
kwiberg4ec01d92016-08-22 08:43:54 -0700180 *lengthInSamples = outLen;
kwiberga06ce492016-08-16 05:35:24 -0700181
182 if (_scaling != 1.0) {
183 for (size_t i = 0; i < outLen; i++) {
184 outBuffer[i] = (int16_t)(outBuffer[i] * _scaling);
185 }
186 }
187 _decodedLengthInMS += 10;
188 return 0;
189}
190
191int32_t FilePlayerImpl::RegisterModuleFileCallback(FileCallback* callback) {
192 return _fileModule.SetModuleFileCallback(callback);
193}
194
195int32_t FilePlayerImpl::SetAudioScaling(float scaleFactor) {
196 if ((scaleFactor >= 0) && (scaleFactor <= 2.0)) {
197 _scaling = scaleFactor;
198 return 0;
199 }
200 LOG(LS_WARNING) << "SetAudioScaling() non-allowed scale factor.";
201 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000202}
203
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000204int32_t FilePlayerImpl::StartPlayingFile(const char* fileName,
205 bool loop,
206 uint32_t startPosition,
207 float volumeScaling,
208 uint32_t notification,
209 uint32_t stopPosition,
kwiberga06ce492016-08-16 05:35:24 -0700210 const CodecInst* codecInst) {
211 if (_fileFormat == kFileFormatPcm16kHzFile ||
212 _fileFormat == kFileFormatPcm8kHzFile ||
213 _fileFormat == kFileFormatPcm32kHzFile) {
214 CodecInst codecInstL16;
215 strncpy(codecInstL16.plname, "L16", 32);
216 codecInstL16.pltype = 93;
217 codecInstL16.channels = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000218
kwiberga06ce492016-08-16 05:35:24 -0700219 if (_fileFormat == kFileFormatPcm8kHzFile) {
220 codecInstL16.rate = 128000;
221 codecInstL16.plfreq = 8000;
222 codecInstL16.pacsize = 80;
lliuubc436ed2017-03-31 16:32:28 -0700223
kwiberga06ce492016-08-16 05:35:24 -0700224 } else if (_fileFormat == kFileFormatPcm16kHzFile) {
225 codecInstL16.rate = 256000;
226 codecInstL16.plfreq = 16000;
227 codecInstL16.pacsize = 160;
lliuubc436ed2017-03-31 16:32:28 -0700228
kwiberga06ce492016-08-16 05:35:24 -0700229 } else if (_fileFormat == kFileFormatPcm32kHzFile) {
230 codecInstL16.rate = 512000;
231 codecInstL16.plfreq = 32000;
lliuubc436ed2017-03-31 16:32:28 -0700232 codecInstL16.pacsize = 160;
kwiberga06ce492016-08-16 05:35:24 -0700233 } else {
234 LOG(LS_ERROR) << "StartPlayingFile() sample frequency not "
235 << "supported for PCM format.";
236 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000237 }
kwiberga06ce492016-08-16 05:35:24 -0700238
239 if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
240 _fileFormat, &codecInstL16,
241 startPosition, stopPosition) == -1) {
242 LOG(LS_WARNING) << "StartPlayingFile() failed to initialize "
243 << "pcm file " << fileName;
244 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000245 }
kwiberga06ce492016-08-16 05:35:24 -0700246 SetAudioScaling(volumeScaling);
247 } else if (_fileFormat == kFileFormatPreencodedFile) {
248 if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
249 _fileFormat, codecInst) == -1) {
250 LOG(LS_WARNING) << "StartPlayingFile() failed to initialize "
251 << "pre-encoded file " << fileName;
252 return -1;
253 }
254 } else {
255 CodecInst* no_inst = NULL;
256 if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
257 _fileFormat, no_inst, startPosition,
258 stopPosition) == -1) {
259 LOG(LS_WARNING) << "StartPlayingFile() failed to initialize file "
260 << fileName;
261 return -1;
262 }
263 SetAudioScaling(volumeScaling);
264 }
265 if (SetUpAudioDecoder() == -1) {
266 StopPlayingFile();
267 return -1;
268 }
269 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000270}
271
kwiberg4ec01d92016-08-22 08:43:54 -0700272int32_t FilePlayerImpl::StartPlayingFile(InStream* sourceStream,
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000273 uint32_t startPosition,
274 float volumeScaling,
275 uint32_t notification,
276 uint32_t stopPosition,
kwiberga06ce492016-08-16 05:35:24 -0700277 const CodecInst* codecInst) {
278 if (_fileFormat == kFileFormatPcm16kHzFile ||
279 _fileFormat == kFileFormatPcm32kHzFile ||
lliuubc436ed2017-03-31 16:32:28 -0700280 _fileFormat == kFileFormatPcm8kHzFile) {
kwiberga06ce492016-08-16 05:35:24 -0700281 CodecInst codecInstL16;
282 strncpy(codecInstL16.plname, "L16", 32);
283 codecInstL16.pltype = 93;
284 codecInstL16.channels = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000285
kwiberga06ce492016-08-16 05:35:24 -0700286 if (_fileFormat == kFileFormatPcm8kHzFile) {
287 codecInstL16.rate = 128000;
288 codecInstL16.plfreq = 8000;
289 codecInstL16.pacsize = 80;
lliuubc436ed2017-03-31 16:32:28 -0700290
kwiberga06ce492016-08-16 05:35:24 -0700291 } else if (_fileFormat == kFileFormatPcm16kHzFile) {
292 codecInstL16.rate = 256000;
293 codecInstL16.plfreq = 16000;
294 codecInstL16.pacsize = 160;
lliuubc436ed2017-03-31 16:32:28 -0700295
kwiberga06ce492016-08-16 05:35:24 -0700296 } else if (_fileFormat == kFileFormatPcm32kHzFile) {
297 codecInstL16.rate = 512000;
298 codecInstL16.plfreq = 32000;
lliuubc436ed2017-03-31 16:32:28 -0700299 codecInstL16.pacsize = 160;
niklase@google.com470e71d2011-07-07 08:21:25 +0000300 } else {
kwiberga06ce492016-08-16 05:35:24 -0700301 LOG(LS_ERROR) << "StartPlayingFile() sample frequency not "
302 << "supported for PCM format.";
303 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000304 }
kwiberga06ce492016-08-16 05:35:24 -0700305 if (_fileModule.StartPlayingAudioStream(
kwiberg4ec01d92016-08-22 08:43:54 -0700306 *sourceStream, notification, _fileFormat, &codecInstL16,
kwiberga06ce492016-08-16 05:35:24 -0700307 startPosition, stopPosition) == -1) {
308 LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream "
309 << "playout.";
310 return -1;
311 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000312
kwiberga06ce492016-08-16 05:35:24 -0700313 } else if (_fileFormat == kFileFormatPreencodedFile) {
kwiberg4ec01d92016-08-22 08:43:54 -0700314 if (_fileModule.StartPlayingAudioStream(*sourceStream, notification,
kwiberga06ce492016-08-16 05:35:24 -0700315 _fileFormat, codecInst) == -1) {
316 LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream "
317 << "playout.";
318 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000319 }
kwiberga06ce492016-08-16 05:35:24 -0700320 } else {
321 CodecInst* no_inst = NULL;
kwiberg4ec01d92016-08-22 08:43:54 -0700322 if (_fileModule.StartPlayingAudioStream(*sourceStream, notification,
kwiberga06ce492016-08-16 05:35:24 -0700323 _fileFormat, no_inst, startPosition,
324 stopPosition) == -1) {
325 LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream "
326 << "playout.";
327 return -1;
328 }
329 }
330 SetAudioScaling(volumeScaling);
331
332 if (SetUpAudioDecoder() == -1) {
333 StopPlayingFile();
334 return -1;
335 }
336 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000337}
338
kwiberga06ce492016-08-16 05:35:24 -0700339int32_t FilePlayerImpl::StopPlayingFile() {
340 memset(&_codec, 0, sizeof(CodecInst));
341 _numberOf10MsPerFrame = 0;
342 _numberOf10MsInDecoder = 0;
343 return _fileModule.StopPlaying();
niklase@google.com470e71d2011-07-07 08:21:25 +0000344}
345
kwiberga06ce492016-08-16 05:35:24 -0700346bool FilePlayerImpl::IsPlayingFile() const {
347 return _fileModule.IsPlaying();
niklase@google.com470e71d2011-07-07 08:21:25 +0000348}
349
kwiberg4ec01d92016-08-22 08:43:54 -0700350int32_t FilePlayerImpl::GetPlayoutPosition(uint32_t* durationMs) {
351 return _fileModule.PlayoutPositionMs(*durationMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000352}
353
kwiberga06ce492016-08-16 05:35:24 -0700354int32_t FilePlayerImpl::SetUpAudioDecoder() {
355 if ((_fileModule.codec_info(_codec) == -1)) {
356 LOG(LS_WARNING) << "Failed to retrieve codec info of file data.";
357 return -1;
358 }
359 if (STR_CASE_CMP(_codec.plname, "L16") != 0 &&
360 _audioDecoder.SetDecodeCodec(_codec) == -1) {
361 LOG(LS_WARNING) << "SetUpAudioDecoder() codec " << _codec.plname
362 << " not supported.";
363 return -1;
364 }
365 _numberOf10MsPerFrame = _codec.pacsize / (_codec.plfreq / 100);
366 _numberOf10MsInDecoder = 0;
367 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000368}
kwiberg144dd272016-08-17 02:46:53 -0700369
370} // namespace
371
kwiberg5b356f42016-09-08 04:32:33 -0700372std::unique_ptr<FilePlayer> FilePlayer::CreateFilePlayer(
kwiberg5a25d952016-08-17 07:31:12 -0700373 uint32_t instanceID,
374 FileFormats fileFormat) {
kwiberg144dd272016-08-17 02:46:53 -0700375 switch (fileFormat) {
376 case kFileFormatWavFile:
377 case kFileFormatCompressedFile:
378 case kFileFormatPreencodedFile:
379 case kFileFormatPcm16kHzFile:
380 case kFileFormatPcm8kHzFile:
381 case kFileFormatPcm32kHzFile:
382 // audio formats
kwiberg5a25d952016-08-17 07:31:12 -0700383 return std::unique_ptr<FilePlayer>(
384 new FilePlayerImpl(instanceID, fileFormat));
kwiberg144dd272016-08-17 02:46:53 -0700385 default:
386 assert(false);
kwiberg5a25d952016-08-17 07:31:12 -0700387 return nullptr;
kwiberg144dd272016-08-17 02:46:53 -0700388 }
389}
390
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000391} // namespace webrtc