Chromium Code Reviews| Index: webrtc/modules/audio_device/android/opensles_player.cc |
| diff --git a/webrtc/modules/audio_device/android/opensles_player.cc b/webrtc/modules/audio_device/android/opensles_player.cc |
| index b3ad64e424627f6f1b3580ecc0b5f6e8dbbd9df9..a63b8c1257acec6fc2eda9b66fdf124bd20b71ee 100644 |
| --- a/webrtc/modules/audio_device/android/opensles_player.cc |
| +++ b/webrtc/modules/audio_device/android/opensles_player.cc |
| @@ -44,7 +44,6 @@ OpenSLESPlayer::OpenSLESPlayer(AudioManager* audio_manager) |
| audio_device_buffer_(nullptr), |
| initialized_(false), |
| playing_(false), |
| - bytes_per_buffer_(0), |
| buffer_index_(0), |
| engine_(nullptr), |
| player_(nullptr), |
| @@ -94,11 +93,13 @@ int OpenSLESPlayer::InitPlayout() { |
| RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| RTC_DCHECK(!initialized_); |
| RTC_DCHECK(!playing_); |
| - ObtainEngineInterface(); |
| + if (!ObtainEngineInterface()) { |
| + ALOGE("Failed to obtain SL Engine interface"); |
| + return -1; |
| + } |
| CreateMix(); |
| initialized_ = true; |
| buffer_index_ = 0; |
| - last_play_time_ = rtc::Time(); |
| return 0; |
| } |
| @@ -107,6 +108,9 @@ int OpenSLESPlayer::StartPlayout() { |
| RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| RTC_DCHECK(initialized_); |
| RTC_DCHECK(!playing_); |
| + if (fine_audio_buffer_) { |
| + fine_audio_buffer_->ResetPlayout(); |
| + } |
| // The number of lower latency audio players is limited, hence we create the |
| // audio player in Start() and destroy it in Stop(). |
| CreateAudioPlayer(); |
| @@ -114,6 +118,7 @@ int OpenSLESPlayer::StartPlayout() { |
| // starts when mode is later changed to SL_PLAYSTATE_PLAYING. |
| // TODO(henrika): we can save some delay by only making one call to |
| // EnqueuePlayoutData. Most likely not worth the risk of adding a glitch. |
| + last_play_time_ = rtc::Time(); |
| for (int i = 0; i < kNumOfOpenSLESBuffers; ++i) { |
| EnqueuePlayoutData(); |
| } |
| @@ -187,77 +192,29 @@ void OpenSLESPlayer::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) { |
| AllocateDataBuffers(); |
| } |
| -SLDataFormat_PCM OpenSLESPlayer::CreatePCMConfiguration( |
| - size_t channels, |
| - int sample_rate, |
| - size_t bits_per_sample) { |
| - ALOGD("CreatePCMConfiguration"); |
| - RTC_CHECK_EQ(bits_per_sample, SL_PCMSAMPLEFORMAT_FIXED_16); |
| - SLDataFormat_PCM format; |
| - format.formatType = SL_DATAFORMAT_PCM; |
| - format.numChannels = static_cast<SLuint32>(channels); |
| - // Note that, the unit of sample rate is actually in milliHertz and not Hertz. |
| - switch (sample_rate) { |
| - case 8000: |
| - format.samplesPerSec = SL_SAMPLINGRATE_8; |
| - break; |
| - case 16000: |
| - format.samplesPerSec = SL_SAMPLINGRATE_16; |
| - break; |
| - case 22050: |
| - format.samplesPerSec = SL_SAMPLINGRATE_22_05; |
| - break; |
| - case 32000: |
| - format.samplesPerSec = SL_SAMPLINGRATE_32; |
| - break; |
| - case 44100: |
| - format.samplesPerSec = SL_SAMPLINGRATE_44_1; |
| - break; |
| - case 48000: |
| - format.samplesPerSec = SL_SAMPLINGRATE_48; |
| - break; |
| - default: |
| - RTC_CHECK(false) << "Unsupported sample rate: " << sample_rate; |
| - } |
| - format.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; |
| - format.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16; |
| - format.endianness = SL_BYTEORDER_LITTLEENDIAN; |
| - if (format.numChannels == 1) |
| - format.channelMask = SL_SPEAKER_FRONT_CENTER; |
| - else if (format.numChannels == 2) |
| - format.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; |
| - else |
| - RTC_CHECK(false) << "Unsupported number of channels: " |
| - << format.numChannels; |
| - return format; |
| -} |
| - |
| void OpenSLESPlayer::AllocateDataBuffers() { |
| ALOGD("AllocateDataBuffers"); |
| RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| RTC_DCHECK(!simple_buffer_queue_); |
| RTC_CHECK(audio_device_buffer_); |
| - // Don't use the lowest possible size as native buffer size. Instead, |
| - // use 10ms to better match the frame size that WebRTC uses. It will result |
| - // in a reduced risk for audio glitches and also in a more "clean" sequence |
| - // of callbacks from the OpenSL ES thread in to WebRTC when asking for audio |
| - // to render. |
| - ALOGD("lowest possible buffer size: %" PRIuS, |
| - audio_parameters_.GetBytesPerBuffer()); |
| - bytes_per_buffer_ = audio_parameters_.GetBytesPerFrame() * |
| - audio_parameters_.frames_per_10ms_buffer(); |
| - RTC_DCHECK_GE(bytes_per_buffer_, audio_parameters_.GetBytesPerBuffer()); |
| - ALOGD("native buffer size: %" PRIuS, bytes_per_buffer_); |
| // Create a modified audio buffer class which allows us to ask for any number |
| // of samples (and not only multiple of 10ms) to match the native OpenSL ES |
| - // buffer size. |
| - fine_buffer_.reset(new FineAudioBuffer(audio_device_buffer_, |
| - bytes_per_buffer_, |
| - audio_parameters_.sample_rate())); |
| + // buffer size. The native buffer size corresponds to the |
| + // PROPERTY_OUTPUT_FRAMES_PER_BUFFER property which is the number of audio |
| + // frames that the HAL (Hardware Abstraction Layer) buffer can hold. It is |
| + // recommended to construct audio buffers so that they contain an exact |
| + // multiple of this number. If so, callbacks will occur at regular intervals, |
| + // which reduces jitter. |
| + ALOGD("native buffer size: %" PRIuS, audio_parameters_.GetBytesPerBuffer()); |
| + ALOGD("native buffer size in ms: %.2f", |
| + audio_parameters_.GetBufferSizeInMilliseconds()); |
| + fine_audio_buffer_.reset(new FineAudioBuffer( |
| + audio_device_buffer_, audio_parameters_.GetBytesPerBuffer(), |
| + audio_parameters_.sample_rate())); |
| // Each buffer must be of this size to avoid unnecessary memcpy while caching |
| // data between successive callbacks. |
| const size_t required_buffer_size = |
| - fine_buffer_->RequiredPlayoutBufferSizeBytes(); |
| + fine_audio_buffer_->RequiredPlayoutBufferSizeBytes(); |
| ALOGD("required buffer size: %" PRIuS, required_buffer_size); |
| for (int i = 0; i < kNumOfOpenSLESBuffers; ++i) { |
| audio_buffers_[i].reset(new SLint8[required_buffer_size]); |
| @@ -267,7 +224,8 @@ void OpenSLESPlayer::AllocateDataBuffers() { |
| bool OpenSLESPlayer::ObtainEngineInterface() { |
| ALOGD("ObtainEngineInterface"); |
| RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| - RTC_DCHECK(!engine_); |
| + 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
|
| + return true; |
| // Get access to (or create if not already existing) the global OpenSL Engine |
| // object. |
| SLObjectItf engine_object = audio_manager_->GetOpenSLEngine(); |
| @@ -395,6 +353,8 @@ void OpenSLESPlayer::DestroyAudioPlayer() { |
| RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| if (!player_object_.Get()) |
| return; |
| + (*simple_buffer_queue_) |
| + ->RegisterCallback(simple_buffer_queue_, nullptr, nullptr); |
| player_object_.Reset(); |
| player_ = nullptr; |
| simple_buffer_queue_ = nullptr; |
| @@ -422,10 +382,10 @@ void OpenSLESPlayer::FillBufferQueue() { |
| void OpenSLESPlayer::EnqueuePlayoutData() { |
| // Check delta time between two successive callbacks and provide a warning |
| // if it becomes very large. |
| - // TODO(henrika): using 100ms as upper limit but this value is rather random. |
| + // TODO(henrika): using 150ms as upper limit but this value is rather random. |
| const uint32_t current_time = rtc::Time(); |
| const uint32_t diff = current_time - last_play_time_; |
| - if (diff > 100) { |
| + if (diff > 150) { |
| ALOGW("Bad OpenSL ES playout timing, dT=%u [ms]", diff); |
| } |
| last_play_time_ = current_time; |
| @@ -433,11 +393,11 @@ void OpenSLESPlayer::EnqueuePlayoutData() { |
| // to adjust for differences in buffer size between WebRTC (10ms) and native |
| // OpenSL ES. |
| SLint8* audio_ptr = audio_buffers_[buffer_index_].get(); |
| - fine_buffer_->GetPlayoutData(audio_ptr); |
| + fine_audio_buffer_->GetPlayoutData(audio_ptr); |
| // Enqueue the decoded audio buffer for playback. |
| - SLresult err = |
| - (*simple_buffer_queue_) |
| - ->Enqueue(simple_buffer_queue_, audio_ptr, bytes_per_buffer_); |
| + SLresult err = (*simple_buffer_queue_) |
| + ->Enqueue(simple_buffer_queue_, audio_ptr, |
| + audio_parameters_.GetBytesPerBuffer()); |
| if (SL_RESULT_SUCCESS != err) { |
| ALOGE("Enqueue failed: %d", err); |
| } |