blob: 8c5824d1bb7a25e84c71d843a106091c20fe5ca6 [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) {
Minyue Li85a3b6b2017-09-01 14:36:33 +0200103 return 48000;
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;
kwiberga06ce492016-08-16 05:35:24 -0700223 } else if (_fileFormat == kFileFormatPcm16kHzFile) {
224 codecInstL16.rate = 256000;
225 codecInstL16.plfreq = 16000;
226 codecInstL16.pacsize = 160;
kwiberga06ce492016-08-16 05:35:24 -0700227 } else if (_fileFormat == kFileFormatPcm32kHzFile) {
228 codecInstL16.rate = 512000;
229 codecInstL16.plfreq = 32000;
Minyue Li85a3b6b2017-09-01 14:36:33 +0200230 codecInstL16.pacsize = 320;
231 } else if (_fileFormat == kFileFormatPcm48kHzFile) {
232 codecInstL16.rate = 768000;
233 codecInstL16.plfreq = 48000;
234 codecInstL16.pacsize = 480;
kwiberga06ce492016-08-16 05:35:24 -0700235 } else {
236 LOG(LS_ERROR) << "StartPlayingFile() sample frequency not "
237 << "supported for PCM format.";
238 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000239 }
kwiberga06ce492016-08-16 05:35:24 -0700240
241 if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
242 _fileFormat, &codecInstL16,
243 startPosition, stopPosition) == -1) {
244 LOG(LS_WARNING) << "StartPlayingFile() failed to initialize "
245 << "pcm file " << fileName;
246 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000247 }
kwiberga06ce492016-08-16 05:35:24 -0700248 SetAudioScaling(volumeScaling);
249 } else if (_fileFormat == kFileFormatPreencodedFile) {
250 if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
251 _fileFormat, codecInst) == -1) {
252 LOG(LS_WARNING) << "StartPlayingFile() failed to initialize "
253 << "pre-encoded file " << fileName;
254 return -1;
255 }
256 } else {
257 CodecInst* no_inst = NULL;
258 if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
259 _fileFormat, no_inst, startPosition,
260 stopPosition) == -1) {
261 LOG(LS_WARNING) << "StartPlayingFile() failed to initialize file "
262 << fileName;
263 return -1;
264 }
265 SetAudioScaling(volumeScaling);
266 }
267 if (SetUpAudioDecoder() == -1) {
268 StopPlayingFile();
269 return -1;
270 }
271 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000272}
273
kwiberg4ec01d92016-08-22 08:43:54 -0700274int32_t FilePlayerImpl::StartPlayingFile(InStream* sourceStream,
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000275 uint32_t startPosition,
276 float volumeScaling,
277 uint32_t notification,
278 uint32_t stopPosition,
kwiberga06ce492016-08-16 05:35:24 -0700279 const CodecInst* codecInst) {
280 if (_fileFormat == kFileFormatPcm16kHzFile ||
281 _fileFormat == kFileFormatPcm32kHzFile ||
Minyue Li85a3b6b2017-09-01 14:36:33 +0200282 _fileFormat == kFileFormatPcm8kHzFile ||
283 _fileFormat == kFileFormatPcm48kHzFile) {
kwiberga06ce492016-08-16 05:35:24 -0700284 CodecInst codecInstL16;
285 strncpy(codecInstL16.plname, "L16", 32);
286 codecInstL16.pltype = 93;
287 codecInstL16.channels = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000288
kwiberga06ce492016-08-16 05:35:24 -0700289 if (_fileFormat == kFileFormatPcm8kHzFile) {
290 codecInstL16.rate = 128000;
291 codecInstL16.plfreq = 8000;
292 codecInstL16.pacsize = 80;
kwiberga06ce492016-08-16 05:35:24 -0700293 } else if (_fileFormat == kFileFormatPcm16kHzFile) {
294 codecInstL16.rate = 256000;
295 codecInstL16.plfreq = 16000;
296 codecInstL16.pacsize = 160;
kwiberga06ce492016-08-16 05:35:24 -0700297 } else if (_fileFormat == kFileFormatPcm32kHzFile) {
298 codecInstL16.rate = 512000;
299 codecInstL16.plfreq = 32000;
Minyue Li85a3b6b2017-09-01 14:36:33 +0200300 codecInstL16.pacsize = 320;
301 } else if (_fileFormat == kFileFormatPcm48kHzFile) {
302 codecInstL16.rate = 768000;
303 codecInstL16.plfreq = 48000;
304 codecInstL16.pacsize = 480;
niklase@google.com470e71d2011-07-07 08:21:25 +0000305 } else {
kwiberga06ce492016-08-16 05:35:24 -0700306 LOG(LS_ERROR) << "StartPlayingFile() sample frequency not "
307 << "supported for PCM format.";
308 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000309 }
kwiberga06ce492016-08-16 05:35:24 -0700310 if (_fileModule.StartPlayingAudioStream(
kwiberg4ec01d92016-08-22 08:43:54 -0700311 *sourceStream, notification, _fileFormat, &codecInstL16,
kwiberga06ce492016-08-16 05:35:24 -0700312 startPosition, stopPosition) == -1) {
313 LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream "
314 << "playout.";
315 return -1;
316 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000317
kwiberga06ce492016-08-16 05:35:24 -0700318 } else if (_fileFormat == kFileFormatPreencodedFile) {
kwiberg4ec01d92016-08-22 08:43:54 -0700319 if (_fileModule.StartPlayingAudioStream(*sourceStream, notification,
kwiberga06ce492016-08-16 05:35:24 -0700320 _fileFormat, codecInst) == -1) {
321 LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream "
322 << "playout.";
323 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000324 }
kwiberga06ce492016-08-16 05:35:24 -0700325 } else {
326 CodecInst* no_inst = NULL;
kwiberg4ec01d92016-08-22 08:43:54 -0700327 if (_fileModule.StartPlayingAudioStream(*sourceStream, notification,
kwiberga06ce492016-08-16 05:35:24 -0700328 _fileFormat, no_inst, startPosition,
329 stopPosition) == -1) {
330 LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream "
331 << "playout.";
332 return -1;
333 }
334 }
335 SetAudioScaling(volumeScaling);
336
337 if (SetUpAudioDecoder() == -1) {
338 StopPlayingFile();
339 return -1;
340 }
341 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000342}
343
kwiberga06ce492016-08-16 05:35:24 -0700344int32_t FilePlayerImpl::StopPlayingFile() {
345 memset(&_codec, 0, sizeof(CodecInst));
346 _numberOf10MsPerFrame = 0;
347 _numberOf10MsInDecoder = 0;
348 return _fileModule.StopPlaying();
niklase@google.com470e71d2011-07-07 08:21:25 +0000349}
350
kwiberga06ce492016-08-16 05:35:24 -0700351bool FilePlayerImpl::IsPlayingFile() const {
352 return _fileModule.IsPlaying();
niklase@google.com470e71d2011-07-07 08:21:25 +0000353}
354
kwiberg4ec01d92016-08-22 08:43:54 -0700355int32_t FilePlayerImpl::GetPlayoutPosition(uint32_t* durationMs) {
356 return _fileModule.PlayoutPositionMs(*durationMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000357}
358
kwiberga06ce492016-08-16 05:35:24 -0700359int32_t FilePlayerImpl::SetUpAudioDecoder() {
360 if ((_fileModule.codec_info(_codec) == -1)) {
361 LOG(LS_WARNING) << "Failed to retrieve codec info of file data.";
362 return -1;
363 }
364 if (STR_CASE_CMP(_codec.plname, "L16") != 0 &&
365 _audioDecoder.SetDecodeCodec(_codec) == -1) {
366 LOG(LS_WARNING) << "SetUpAudioDecoder() codec " << _codec.plname
367 << " not supported.";
368 return -1;
369 }
370 _numberOf10MsPerFrame = _codec.pacsize / (_codec.plfreq / 100);
371 _numberOf10MsInDecoder = 0;
372 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000373}
kwiberg144dd272016-08-17 02:46:53 -0700374
375} // namespace
376
kwiberg5b356f42016-09-08 04:32:33 -0700377std::unique_ptr<FilePlayer> FilePlayer::CreateFilePlayer(
kwiberg5a25d952016-08-17 07:31:12 -0700378 uint32_t instanceID,
379 FileFormats fileFormat) {
kwiberg144dd272016-08-17 02:46:53 -0700380 switch (fileFormat) {
381 case kFileFormatWavFile:
382 case kFileFormatCompressedFile:
383 case kFileFormatPreencodedFile:
384 case kFileFormatPcm16kHzFile:
385 case kFileFormatPcm8kHzFile:
386 case kFileFormatPcm32kHzFile:
Minyue Li85a3b6b2017-09-01 14:36:33 +0200387 case kFileFormatPcm48kHzFile:
kwiberg144dd272016-08-17 02:46:53 -0700388 // audio formats
kwiberg5a25d952016-08-17 07:31:12 -0700389 return std::unique_ptr<FilePlayer>(
390 new FilePlayerImpl(instanceID, fileFormat));
kwiberg144dd272016-08-17 02:46:53 -0700391 default:
392 assert(false);
kwiberg5a25d952016-08-17 07:31:12 -0700393 return nullptr;
kwiberg144dd272016-08-17 02:46:53 -0700394 }
395}
396
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000397} // namespace webrtc