OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 26 matching lines...) Expand all Loading... | |
37 } while (0) | 37 } while (0) |
38 | 38 |
39 namespace webrtc { | 39 namespace webrtc { |
40 | 40 |
41 OpenSLESPlayer::OpenSLESPlayer(AudioManager* audio_manager) | 41 OpenSLESPlayer::OpenSLESPlayer(AudioManager* audio_manager) |
42 : audio_manager_(audio_manager), | 42 : audio_manager_(audio_manager), |
43 audio_parameters_(audio_manager->GetPlayoutAudioParameters()), | 43 audio_parameters_(audio_manager->GetPlayoutAudioParameters()), |
44 audio_device_buffer_(nullptr), | 44 audio_device_buffer_(nullptr), |
45 initialized_(false), | 45 initialized_(false), |
46 playing_(false), | 46 playing_(false), |
47 bytes_per_buffer_(0), | |
48 buffer_index_(0), | 47 buffer_index_(0), |
49 engine_(nullptr), | 48 engine_(nullptr), |
50 player_(nullptr), | 49 player_(nullptr), |
51 simple_buffer_queue_(nullptr), | 50 simple_buffer_queue_(nullptr), |
52 volume_(nullptr), | 51 volume_(nullptr), |
53 last_play_time_(0) { | 52 last_play_time_(0) { |
54 ALOGD("ctor%s", GetThreadInfo().c_str()); | 53 ALOGD("ctor%s", GetThreadInfo().c_str()); |
55 // Use native audio output parameters provided by the audio manager and | 54 // Use native audio output parameters provided by the audio manager and |
56 // define the PCM format structure. | 55 // define the PCM format structure. |
57 pcm_format_ = CreatePCMConfiguration(audio_parameters_.channels(), | 56 pcm_format_ = CreatePCMConfiguration(audio_parameters_.channels(), |
(...skipping 29 matching lines...) Expand all Loading... | |
87 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 86 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
88 StopPlayout(); | 87 StopPlayout(); |
89 return 0; | 88 return 0; |
90 } | 89 } |
91 | 90 |
92 int OpenSLESPlayer::InitPlayout() { | 91 int OpenSLESPlayer::InitPlayout() { |
93 ALOGD("InitPlayout%s", GetThreadInfo().c_str()); | 92 ALOGD("InitPlayout%s", GetThreadInfo().c_str()); |
94 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 93 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
95 RTC_DCHECK(!initialized_); | 94 RTC_DCHECK(!initialized_); |
96 RTC_DCHECK(!playing_); | 95 RTC_DCHECK(!playing_); |
97 ObtainEngineInterface(); | 96 if (!ObtainEngineInterface()) { |
97 ALOGE("Failed to obtain SL Engine interface"); | |
98 return -1; | |
99 } | |
98 CreateMix(); | 100 CreateMix(); |
99 initialized_ = true; | 101 initialized_ = true; |
100 buffer_index_ = 0; | 102 buffer_index_ = 0; |
101 last_play_time_ = rtc::Time(); | |
102 return 0; | 103 return 0; |
103 } | 104 } |
104 | 105 |
105 int OpenSLESPlayer::StartPlayout() { | 106 int OpenSLESPlayer::StartPlayout() { |
106 ALOGD("StartPlayout%s", GetThreadInfo().c_str()); | 107 ALOGD("StartPlayout%s", GetThreadInfo().c_str()); |
107 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 108 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
108 RTC_DCHECK(initialized_); | 109 RTC_DCHECK(initialized_); |
109 RTC_DCHECK(!playing_); | 110 RTC_DCHECK(!playing_); |
111 if (fine_audio_buffer_) { | |
112 fine_audio_buffer_->ResetPlayout(); | |
113 } | |
110 // The number of lower latency audio players is limited, hence we create the | 114 // The number of lower latency audio players is limited, hence we create the |
111 // audio player in Start() and destroy it in Stop(). | 115 // audio player in Start() and destroy it in Stop(). |
112 CreateAudioPlayer(); | 116 CreateAudioPlayer(); |
113 // Fill up audio buffers to avoid initial glitch and to ensure that playback | 117 // Fill up audio buffers to avoid initial glitch and to ensure that playback |
114 // starts when mode is later changed to SL_PLAYSTATE_PLAYING. | 118 // starts when mode is later changed to SL_PLAYSTATE_PLAYING. |
115 // TODO(henrika): we can save some delay by only making one call to | 119 // TODO(henrika): we can save some delay by only making one call to |
116 // EnqueuePlayoutData. Most likely not worth the risk of adding a glitch. | 120 // EnqueuePlayoutData. Most likely not worth the risk of adding a glitch. |
121 last_play_time_ = rtc::Time(); | |
117 for (int i = 0; i < kNumOfOpenSLESBuffers; ++i) { | 122 for (int i = 0; i < kNumOfOpenSLESBuffers; ++i) { |
118 EnqueuePlayoutData(); | 123 EnqueuePlayoutData(); |
119 } | 124 } |
120 // Start streaming data by setting the play state to SL_PLAYSTATE_PLAYING. | 125 // Start streaming data by setting the play state to SL_PLAYSTATE_PLAYING. |
121 // For a player object, when the object is in the SL_PLAYSTATE_PLAYING | 126 // For a player object, when the object is in the SL_PLAYSTATE_PLAYING |
122 // state, adding buffers will implicitly start playback. | 127 // state, adding buffers will implicitly start playback. |
123 RETURN_ON_ERROR((*player_)->SetPlayState(player_, SL_PLAYSTATE_PLAYING), -1); | 128 RETURN_ON_ERROR((*player_)->SetPlayState(player_, SL_PLAYSTATE_PLAYING), -1); |
124 playing_ = (GetPlayState() == SL_PLAYSTATE_PLAYING); | 129 playing_ = (GetPlayState() == SL_PLAYSTATE_PLAYING); |
125 RTC_DCHECK(playing_); | 130 RTC_DCHECK(playing_); |
126 return 0; | 131 return 0; |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
180 const int sample_rate_hz = audio_parameters_.sample_rate(); | 185 const int sample_rate_hz = audio_parameters_.sample_rate(); |
181 ALOGD("SetPlayoutSampleRate(%d)", sample_rate_hz); | 186 ALOGD("SetPlayoutSampleRate(%d)", sample_rate_hz); |
182 audio_device_buffer_->SetPlayoutSampleRate(sample_rate_hz); | 187 audio_device_buffer_->SetPlayoutSampleRate(sample_rate_hz); |
183 const size_t channels = audio_parameters_.channels(); | 188 const size_t channels = audio_parameters_.channels(); |
184 ALOGD("SetPlayoutChannels(%" PRIuS ")", channels); | 189 ALOGD("SetPlayoutChannels(%" PRIuS ")", channels); |
185 audio_device_buffer_->SetPlayoutChannels(channels); | 190 audio_device_buffer_->SetPlayoutChannels(channels); |
186 RTC_CHECK(audio_device_buffer_); | 191 RTC_CHECK(audio_device_buffer_); |
187 AllocateDataBuffers(); | 192 AllocateDataBuffers(); |
188 } | 193 } |
189 | 194 |
190 SLDataFormat_PCM OpenSLESPlayer::CreatePCMConfiguration( | |
191 size_t channels, | |
192 int sample_rate, | |
193 size_t bits_per_sample) { | |
194 ALOGD("CreatePCMConfiguration"); | |
195 RTC_CHECK_EQ(bits_per_sample, SL_PCMSAMPLEFORMAT_FIXED_16); | |
196 SLDataFormat_PCM format; | |
197 format.formatType = SL_DATAFORMAT_PCM; | |
198 format.numChannels = static_cast<SLuint32>(channels); | |
199 // Note that, the unit of sample rate is actually in milliHertz and not Hertz. | |
200 switch (sample_rate) { | |
201 case 8000: | |
202 format.samplesPerSec = SL_SAMPLINGRATE_8; | |
203 break; | |
204 case 16000: | |
205 format.samplesPerSec = SL_SAMPLINGRATE_16; | |
206 break; | |
207 case 22050: | |
208 format.samplesPerSec = SL_SAMPLINGRATE_22_05; | |
209 break; | |
210 case 32000: | |
211 format.samplesPerSec = SL_SAMPLINGRATE_32; | |
212 break; | |
213 case 44100: | |
214 format.samplesPerSec = SL_SAMPLINGRATE_44_1; | |
215 break; | |
216 case 48000: | |
217 format.samplesPerSec = SL_SAMPLINGRATE_48; | |
218 break; | |
219 default: | |
220 RTC_CHECK(false) << "Unsupported sample rate: " << sample_rate; | |
221 } | |
222 format.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; | |
223 format.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16; | |
224 format.endianness = SL_BYTEORDER_LITTLEENDIAN; | |
225 if (format.numChannels == 1) | |
226 format.channelMask = SL_SPEAKER_FRONT_CENTER; | |
227 else if (format.numChannels == 2) | |
228 format.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; | |
229 else | |
230 RTC_CHECK(false) << "Unsupported number of channels: " | |
231 << format.numChannels; | |
232 return format; | |
233 } | |
234 | |
235 void OpenSLESPlayer::AllocateDataBuffers() { | 195 void OpenSLESPlayer::AllocateDataBuffers() { |
236 ALOGD("AllocateDataBuffers"); | 196 ALOGD("AllocateDataBuffers"); |
237 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 197 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
238 RTC_DCHECK(!simple_buffer_queue_); | 198 RTC_DCHECK(!simple_buffer_queue_); |
239 RTC_CHECK(audio_device_buffer_); | 199 RTC_CHECK(audio_device_buffer_); |
240 // Don't use the lowest possible size as native buffer size. Instead, | |
241 // use 10ms to better match the frame size that WebRTC uses. It will result | |
242 // in a reduced risk for audio glitches and also in a more "clean" sequence | |
243 // of callbacks from the OpenSL ES thread in to WebRTC when asking for audio | |
244 // to render. | |
245 ALOGD("lowest possible buffer size: %" PRIuS, | |
246 audio_parameters_.GetBytesPerBuffer()); | |
247 bytes_per_buffer_ = audio_parameters_.GetBytesPerFrame() * | |
248 audio_parameters_.frames_per_10ms_buffer(); | |
249 RTC_DCHECK_GE(bytes_per_buffer_, audio_parameters_.GetBytesPerBuffer()); | |
250 ALOGD("native buffer size: %" PRIuS, bytes_per_buffer_); | |
251 // Create a modified audio buffer class which allows us to ask for any number | 200 // Create a modified audio buffer class which allows us to ask for any number |
252 // of samples (and not only multiple of 10ms) to match the native OpenSL ES | 201 // of samples (and not only multiple of 10ms) to match the native OpenSL ES |
253 // buffer size. | 202 // buffer size. The native buffer size corresponds to the |
254 fine_buffer_.reset(new FineAudioBuffer(audio_device_buffer_, | 203 // PROPERTY_OUTPUT_FRAMES_PER_BUFFER property which is the number of audio |
255 bytes_per_buffer_, | 204 // frames that the HAL (Hardware Abstraction Layer) buffer can hold. It is |
256 audio_parameters_.sample_rate())); | 205 // recommended to construct audio buffers so that they contain an exact |
206 // multiple of this number. If so, callbacks will occur at regular intervals, | |
207 // which reduces jitter. | |
208 ALOGD("native buffer size: %" PRIuS, audio_parameters_.GetBytesPerBuffer()); | |
209 ALOGD("native buffer size in ms: %.2f", | |
210 audio_parameters_.GetBufferSizeInMilliseconds()); | |
211 fine_audio_buffer_.reset(new FineAudioBuffer( | |
212 audio_device_buffer_, audio_parameters_.GetBytesPerBuffer(), | |
213 audio_parameters_.sample_rate())); | |
257 // Each buffer must be of this size to avoid unnecessary memcpy while caching | 214 // Each buffer must be of this size to avoid unnecessary memcpy while caching |
258 // data between successive callbacks. | 215 // data between successive callbacks. |
259 const size_t required_buffer_size = | 216 const size_t required_buffer_size = |
260 fine_buffer_->RequiredPlayoutBufferSizeBytes(); | 217 fine_audio_buffer_->RequiredPlayoutBufferSizeBytes(); |
261 ALOGD("required buffer size: %" PRIuS, required_buffer_size); | 218 ALOGD("required buffer size: %" PRIuS, required_buffer_size); |
262 for (int i = 0; i < kNumOfOpenSLESBuffers; ++i) { | 219 for (int i = 0; i < kNumOfOpenSLESBuffers; ++i) { |
263 audio_buffers_[i].reset(new SLint8[required_buffer_size]); | 220 audio_buffers_[i].reset(new SLint8[required_buffer_size]); |
264 } | 221 } |
265 } | 222 } |
266 | 223 |
267 bool OpenSLESPlayer::ObtainEngineInterface() { | 224 bool OpenSLESPlayer::ObtainEngineInterface() { |
268 ALOGD("ObtainEngineInterface"); | 225 ALOGD("ObtainEngineInterface"); |
269 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 226 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
270 RTC_DCHECK(!engine_); | 227 if (engine_) |
tommi
2016/09/15 09:34:13
is ObtainEngineInterface always called on the same
henrika_webrtc
2016/09/16 13:30:47
Yes Sir, it is...and I do have a thread checker to
| |
228 return true; | |
271 // Get access to (or create if not already existing) the global OpenSL Engine | 229 // Get access to (or create if not already existing) the global OpenSL Engine |
272 // object. | 230 // object. |
273 SLObjectItf engine_object = audio_manager_->GetOpenSLEngine(); | 231 SLObjectItf engine_object = audio_manager_->GetOpenSLEngine(); |
274 if (engine_object == nullptr) { | 232 if (engine_object == nullptr) { |
275 ALOGE("Failed to access the global OpenSL engine"); | 233 ALOGE("Failed to access the global OpenSL engine"); |
276 return false; | 234 return false; |
277 } | 235 } |
278 // Get the SL Engine Interface which is implicit. | 236 // Get the SL Engine Interface which is implicit. |
279 RETURN_ON_ERROR( | 237 RETURN_ON_ERROR( |
280 (*engine_object)->GetInterface(engine_object, SL_IID_ENGINE, &engine_), | 238 (*engine_object)->GetInterface(engine_object, SL_IID_ENGINE, &engine_), |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
388 // RETURN_ON_ERROR((*volume_)->SetVolumeLevel(volume_, 0), false); | 346 // RETURN_ON_ERROR((*volume_)->SetVolumeLevel(volume_, 0), false); |
389 | 347 |
390 return true; | 348 return true; |
391 } | 349 } |
392 | 350 |
393 void OpenSLESPlayer::DestroyAudioPlayer() { | 351 void OpenSLESPlayer::DestroyAudioPlayer() { |
394 ALOGD("DestroyAudioPlayer"); | 352 ALOGD("DestroyAudioPlayer"); |
395 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 353 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
396 if (!player_object_.Get()) | 354 if (!player_object_.Get()) |
397 return; | 355 return; |
356 (*simple_buffer_queue_) | |
357 ->RegisterCallback(simple_buffer_queue_, nullptr, nullptr); | |
398 player_object_.Reset(); | 358 player_object_.Reset(); |
399 player_ = nullptr; | 359 player_ = nullptr; |
400 simple_buffer_queue_ = nullptr; | 360 simple_buffer_queue_ = nullptr; |
401 volume_ = nullptr; | 361 volume_ = nullptr; |
402 } | 362 } |
403 | 363 |
404 // static | 364 // static |
405 void OpenSLESPlayer::SimpleBufferQueueCallback( | 365 void OpenSLESPlayer::SimpleBufferQueueCallback( |
406 SLAndroidSimpleBufferQueueItf caller, | 366 SLAndroidSimpleBufferQueueItf caller, |
407 void* context) { | 367 void* context) { |
408 OpenSLESPlayer* stream = reinterpret_cast<OpenSLESPlayer*>(context); | 368 OpenSLESPlayer* stream = reinterpret_cast<OpenSLESPlayer*>(context); |
409 stream->FillBufferQueue(); | 369 stream->FillBufferQueue(); |
410 } | 370 } |
411 | 371 |
412 void OpenSLESPlayer::FillBufferQueue() { | 372 void OpenSLESPlayer::FillBufferQueue() { |
413 RTC_DCHECK(thread_checker_opensles_.CalledOnValidThread()); | 373 RTC_DCHECK(thread_checker_opensles_.CalledOnValidThread()); |
414 SLuint32 state = GetPlayState(); | 374 SLuint32 state = GetPlayState(); |
415 if (state != SL_PLAYSTATE_PLAYING) { | 375 if (state != SL_PLAYSTATE_PLAYING) { |
416 ALOGW("Buffer callback in non-playing state!"); | 376 ALOGW("Buffer callback in non-playing state!"); |
417 return; | 377 return; |
418 } | 378 } |
419 EnqueuePlayoutData(); | 379 EnqueuePlayoutData(); |
420 } | 380 } |
421 | 381 |
422 void OpenSLESPlayer::EnqueuePlayoutData() { | 382 void OpenSLESPlayer::EnqueuePlayoutData() { |
423 // Check delta time between two successive callbacks and provide a warning | 383 // Check delta time between two successive callbacks and provide a warning |
424 // if it becomes very large. | 384 // if it becomes very large. |
425 // TODO(henrika): using 100ms as upper limit but this value is rather random. | 385 // TODO(henrika): using 150ms as upper limit but this value is rather random. |
426 const uint32_t current_time = rtc::Time(); | 386 const uint32_t current_time = rtc::Time(); |
427 const uint32_t diff = current_time - last_play_time_; | 387 const uint32_t diff = current_time - last_play_time_; |
428 if (diff > 100) { | 388 if (diff > 150) { |
429 ALOGW("Bad OpenSL ES playout timing, dT=%u [ms]", diff); | 389 ALOGW("Bad OpenSL ES playout timing, dT=%u [ms]", diff); |
430 } | 390 } |
431 last_play_time_ = current_time; | 391 last_play_time_ = current_time; |
432 // Read audio data from the WebRTC source using the FineAudioBuffer object | 392 // Read audio data from the WebRTC source using the FineAudioBuffer object |
433 // to adjust for differences in buffer size between WebRTC (10ms) and native | 393 // to adjust for differences in buffer size between WebRTC (10ms) and native |
434 // OpenSL ES. | 394 // OpenSL ES. |
435 SLint8* audio_ptr = audio_buffers_[buffer_index_].get(); | 395 SLint8* audio_ptr = audio_buffers_[buffer_index_].get(); |
436 fine_buffer_->GetPlayoutData(audio_ptr); | 396 fine_audio_buffer_->GetPlayoutData(audio_ptr); |
437 // Enqueue the decoded audio buffer for playback. | 397 // Enqueue the decoded audio buffer for playback. |
438 SLresult err = | 398 SLresult err = (*simple_buffer_queue_) |
439 (*simple_buffer_queue_) | 399 ->Enqueue(simple_buffer_queue_, audio_ptr, |
440 ->Enqueue(simple_buffer_queue_, audio_ptr, bytes_per_buffer_); | 400 audio_parameters_.GetBytesPerBuffer()); |
441 if (SL_RESULT_SUCCESS != err) { | 401 if (SL_RESULT_SUCCESS != err) { |
442 ALOGE("Enqueue failed: %d", err); | 402 ALOGE("Enqueue failed: %d", err); |
443 } | 403 } |
444 buffer_index_ = (buffer_index_ + 1) % kNumOfOpenSLESBuffers; | 404 buffer_index_ = (buffer_index_ + 1) % kNumOfOpenSLESBuffers; |
445 } | 405 } |
446 | 406 |
447 SLuint32 OpenSLESPlayer::GetPlayState() const { | 407 SLuint32 OpenSLESPlayer::GetPlayState() const { |
448 RTC_DCHECK(player_); | 408 RTC_DCHECK(player_); |
449 SLuint32 state; | 409 SLuint32 state; |
450 SLresult err = (*player_)->GetPlayState(player_, &state); | 410 SLresult err = (*player_)->GetPlayState(player_, &state); |
451 if (SL_RESULT_SUCCESS != err) { | 411 if (SL_RESULT_SUCCESS != err) { |
452 ALOGE("GetPlayState failed: %d", err); | 412 ALOGE("GetPlayState failed: %d", err); |
453 } | 413 } |
454 return state; | 414 return state; |
455 } | 415 } |
456 | 416 |
457 } // namespace webrtc | 417 } // namespace webrtc |
OLD | NEW |