Chromium Code Reviews| 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 |