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