OLD | NEW |
| (Empty) |
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 | |
14 namespace webrtc { | |
15 FilePlayer* 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 | |
34 void FilePlayer::DestroyFilePlayer(FilePlayer* player) | |
35 { | |
36 delete player; | |
37 } | |
38 | |
39 FilePlayerImpl::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 | |
55 FilePlayerImpl::~FilePlayerImpl() | |
56 { | |
57 MediaFile::DestroyMediaFile(&_fileModule); | |
58 } | |
59 | |
60 int32_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 | |
90 int32_t FilePlayerImpl::AudioCodec(CodecInst& audioCodec) const | |
91 { | |
92 audioCodec = _codec; | |
93 return 0; | |
94 } | |
95 | |
96 int32_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 | |
188 int32_t FilePlayerImpl::RegisterModuleFileCallback(FileCallback* callback) | |
189 { | |
190 return _fileModule.SetModuleFileCallback(callback); | |
191 } | |
192 | |
193 int32_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 | |
204 int32_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 | |
286 int32_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 | |
366 int32_t FilePlayerImpl::StopPlayingFile() | |
367 { | |
368 memset(&_codec, 0, sizeof(CodecInst)); | |
369 _numberOf10MsPerFrame = 0; | |
370 _numberOf10MsInDecoder = 0; | |
371 return _fileModule.StopPlaying(); | |
372 } | |
373 | |
374 bool FilePlayerImpl::IsPlayingFile() const | |
375 { | |
376 return _fileModule.IsPlaying(); | |
377 } | |
378 | |
379 int32_t FilePlayerImpl::GetPlayoutPosition(uint32_t& durationMs) | |
380 { | |
381 return _fileModule.PlayoutPositionMs(durationMs); | |
382 } | |
383 | |
384 int32_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 | |
OLD | NEW |