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 |
11 #include "webrtc/modules/audio_device/android/opensles_player.h" | 11 #include "webrtc/modules/audio_device/android/opensles_player.h" |
12 | 12 |
13 #include <android/log.h> | 13 #include <android/log.h> |
14 | 14 |
15 #include "webrtc/base/arraysize.h" | 15 #include "webrtc/base/arraysize.h" |
16 #include "webrtc/base/checks.h" | 16 #include "webrtc/base/checks.h" |
17 #include "webrtc/base/format_macros.h" | 17 #include "webrtc/base/format_macros.h" |
| 18 #include "webrtc/base/timeutils.h" |
18 #include "webrtc/modules/audio_device/android/audio_manager.h" | 19 #include "webrtc/modules/audio_device/android/audio_manager.h" |
19 #include "webrtc/modules/audio_device/fine_audio_buffer.h" | 20 #include "webrtc/modules/audio_device/fine_audio_buffer.h" |
20 | 21 |
21 #define TAG "OpenSLESPlayer" | 22 #define TAG "OpenSLESPlayer" |
22 #define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__) | 23 #define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__) |
23 #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) | 24 #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) |
24 #define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) | 25 #define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) |
25 #define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__) | 26 #define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__) |
26 #define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) | 27 #define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) |
27 | 28 |
(...skipping 11 matching lines...) Expand all Loading... |
39 OpenSLESPlayer::OpenSLESPlayer(AudioManager* audio_manager) | 40 OpenSLESPlayer::OpenSLESPlayer(AudioManager* audio_manager) |
40 : audio_parameters_(audio_manager->GetPlayoutAudioParameters()), | 41 : audio_parameters_(audio_manager->GetPlayoutAudioParameters()), |
41 audio_device_buffer_(NULL), | 42 audio_device_buffer_(NULL), |
42 initialized_(false), | 43 initialized_(false), |
43 playing_(false), | 44 playing_(false), |
44 bytes_per_buffer_(0), | 45 bytes_per_buffer_(0), |
45 buffer_index_(0), | 46 buffer_index_(0), |
46 engine_(nullptr), | 47 engine_(nullptr), |
47 player_(nullptr), | 48 player_(nullptr), |
48 simple_buffer_queue_(nullptr), | 49 simple_buffer_queue_(nullptr), |
49 volume_(nullptr) { | 50 volume_(nullptr), |
| 51 last_play_time_(0) { |
50 ALOGD("ctor%s", GetThreadInfo().c_str()); | 52 ALOGD("ctor%s", GetThreadInfo().c_str()); |
51 // Use native audio output parameters provided by the audio manager and | 53 // Use native audio output parameters provided by the audio manager and |
52 // define the PCM format structure. | 54 // define the PCM format structure. |
53 pcm_format_ = CreatePCMConfiguration(audio_parameters_.channels(), | 55 pcm_format_ = CreatePCMConfiguration(audio_parameters_.channels(), |
54 audio_parameters_.sample_rate(), | 56 audio_parameters_.sample_rate(), |
55 audio_parameters_.bits_per_sample()); | 57 audio_parameters_.bits_per_sample()); |
56 // Detach from this thread since we want to use the checker to verify calls | 58 // Detach from this thread since we want to use the checker to verify calls |
57 // from the internal audio thread. | 59 // from the internal audio thread. |
58 thread_checker_opensles_.DetachFromThread(); | 60 thread_checker_opensles_.DetachFromThread(); |
59 } | 61 } |
(...skipping 28 matching lines...) Expand all Loading... |
88 | 90 |
89 int OpenSLESPlayer::InitPlayout() { | 91 int OpenSLESPlayer::InitPlayout() { |
90 ALOGD("InitPlayout%s", GetThreadInfo().c_str()); | 92 ALOGD("InitPlayout%s", GetThreadInfo().c_str()); |
91 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 93 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
92 RTC_DCHECK(!initialized_); | 94 RTC_DCHECK(!initialized_); |
93 RTC_DCHECK(!playing_); | 95 RTC_DCHECK(!playing_); |
94 CreateEngine(); | 96 CreateEngine(); |
95 CreateMix(); | 97 CreateMix(); |
96 initialized_ = true; | 98 initialized_ = true; |
97 buffer_index_ = 0; | 99 buffer_index_ = 0; |
| 100 last_play_time_ = rtc::Time(); |
98 return 0; | 101 return 0; |
99 } | 102 } |
100 | 103 |
101 int OpenSLESPlayer::StartPlayout() { | 104 int OpenSLESPlayer::StartPlayout() { |
102 ALOGD("StartPlayout%s", GetThreadInfo().c_str()); | 105 ALOGD("StartPlayout%s", GetThreadInfo().c_str()); |
103 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 106 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
104 RTC_DCHECK(initialized_); | 107 RTC_DCHECK(initialized_); |
105 RTC_DCHECK(!playing_); | 108 RTC_DCHECK(!playing_); |
106 // The number of lower latency audio players is limited, hence we create the | 109 // The number of lower latency audio players is limited, hence we create the |
107 // audio player in Start() and destroy it in Stop(). | 110 // audio player in Start() and destroy it in Stop(). |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 RTC_CHECK(false) << "Unsupported number of channels: " | 229 RTC_CHECK(false) << "Unsupported number of channels: " |
227 << format.numChannels; | 230 << format.numChannels; |
228 return format; | 231 return format; |
229 } | 232 } |
230 | 233 |
231 void OpenSLESPlayer::AllocateDataBuffers() { | 234 void OpenSLESPlayer::AllocateDataBuffers() { |
232 ALOGD("AllocateDataBuffers"); | 235 ALOGD("AllocateDataBuffers"); |
233 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 236 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
234 RTC_DCHECK(!simple_buffer_queue_); | 237 RTC_DCHECK(!simple_buffer_queue_); |
235 RTC_CHECK(audio_device_buffer_); | 238 RTC_CHECK(audio_device_buffer_); |
236 bytes_per_buffer_ = audio_parameters_.GetBytesPerBuffer(); | 239 // Don't use the lowest possible size as native buffer size. Instead, |
| 240 // use 10ms to better match the frame size that WebRTC uses. It will result |
| 241 // in a reduced risk for audio glitches and also in a more "clean" sequence |
| 242 // of callbacks from the OpenSL ES thread in to WebRTC when asking for audio |
| 243 // to render. |
| 244 ALOGD("lowest possible buffer size: %" PRIuS, |
| 245 audio_parameters_.GetBytesPerBuffer()); |
| 246 bytes_per_buffer_ = audio_parameters_.GetBytesPerFrame() * |
| 247 audio_parameters_.frames_per_10ms_buffer(); |
| 248 RTC_DCHECK_GT(bytes_per_buffer_, audio_parameters_.GetBytesPerBuffer()); |
237 ALOGD("native buffer size: %" PRIuS, bytes_per_buffer_); | 249 ALOGD("native buffer size: %" PRIuS, bytes_per_buffer_); |
238 // Create a modified audio buffer class which allows us to ask for any number | 250 // Create a modified audio buffer class which allows us to ask for any number |
239 // of samples (and not only multiple of 10ms) to match the native OpenSL ES | 251 // of samples (and not only multiple of 10ms) to match the native OpenSL ES |
240 // buffer size. | 252 // buffer size. |
241 fine_buffer_.reset(new FineAudioBuffer(audio_device_buffer_, | 253 fine_buffer_.reset(new FineAudioBuffer(audio_device_buffer_, |
242 bytes_per_buffer_, | 254 bytes_per_buffer_, |
243 audio_parameters_.sample_rate())); | 255 audio_parameters_.sample_rate())); |
244 // Each buffer must be of this size to avoid unnecessary memcpy while caching | 256 // Each buffer must be of this size to avoid unnecessary memcpy while caching |
245 // data between successive callbacks. | 257 // data between successive callbacks. |
246 const size_t required_buffer_size = | 258 const size_t required_buffer_size = |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
411 RTC_DCHECK(thread_checker_opensles_.CalledOnValidThread()); | 423 RTC_DCHECK(thread_checker_opensles_.CalledOnValidThread()); |
412 SLuint32 state = GetPlayState(); | 424 SLuint32 state = GetPlayState(); |
413 if (state != SL_PLAYSTATE_PLAYING) { | 425 if (state != SL_PLAYSTATE_PLAYING) { |
414 ALOGW("Buffer callback in non-playing state!"); | 426 ALOGW("Buffer callback in non-playing state!"); |
415 return; | 427 return; |
416 } | 428 } |
417 EnqueuePlayoutData(); | 429 EnqueuePlayoutData(); |
418 } | 430 } |
419 | 431 |
420 void OpenSLESPlayer::EnqueuePlayoutData() { | 432 void OpenSLESPlayer::EnqueuePlayoutData() { |
| 433 // Check delta time between two successive callbacks and provide a warning |
| 434 // if it becomes very large. |
| 435 // TODO(henrika): using 100ms as upper limit but this value is rather random. |
| 436 const uint32_t current_time = rtc::Time(); |
| 437 const uint32_t diff = current_time - last_play_time_; |
| 438 if (diff > 100) { |
| 439 ALOGW("Bad OpenSL ES playout timing, dT=%u [ms]", diff); |
| 440 } |
| 441 last_play_time_ = current_time; |
421 // Read audio data from the WebRTC source using the FineAudioBuffer object | 442 // Read audio data from the WebRTC source using the FineAudioBuffer object |
422 // to adjust for differences in buffer size between WebRTC (10ms) and native | 443 // to adjust for differences in buffer size between WebRTC (10ms) and native |
423 // OpenSL ES. | 444 // OpenSL ES. |
424 SLint8* audio_ptr = audio_buffers_[buffer_index_].get(); | 445 SLint8* audio_ptr = audio_buffers_[buffer_index_].get(); |
425 fine_buffer_->GetPlayoutData(audio_ptr); | 446 fine_buffer_->GetPlayoutData(audio_ptr); |
426 // Enqueue the decoded audio buffer for playback. | 447 // Enqueue the decoded audio buffer for playback. |
427 SLresult err = | 448 SLresult err = |
428 (*simple_buffer_queue_) | 449 (*simple_buffer_queue_) |
429 ->Enqueue(simple_buffer_queue_, audio_ptr, bytes_per_buffer_); | 450 ->Enqueue(simple_buffer_queue_, audio_ptr, bytes_per_buffer_); |
430 if (SL_RESULT_SUCCESS != err) { | 451 if (SL_RESULT_SUCCESS != err) { |
431 ALOGE("Enqueue failed: %d", err); | 452 ALOGE("Enqueue failed: %d", err); |
432 } | 453 } |
433 buffer_index_ = (buffer_index_ + 1) % kNumOfOpenSLESBuffers; | 454 buffer_index_ = (buffer_index_ + 1) % kNumOfOpenSLESBuffers; |
434 } | 455 } |
435 | 456 |
436 SLuint32 OpenSLESPlayer::GetPlayState() const { | 457 SLuint32 OpenSLESPlayer::GetPlayState() const { |
437 RTC_DCHECK(player_); | 458 RTC_DCHECK(player_); |
438 SLuint32 state; | 459 SLuint32 state; |
439 SLresult err = (*player_)->GetPlayState(player_, &state); | 460 SLresult err = (*player_)->GetPlayState(player_, &state); |
440 if (SL_RESULT_SUCCESS != err) { | 461 if (SL_RESULT_SUCCESS != err) { |
441 ALOGE("GetPlayState failed: %d", err); | 462 ALOGE("GetPlayState failed: %d", err); |
442 } | 463 } |
443 return state; | 464 return state; |
444 } | 465 } |
445 | 466 |
446 } // namespace webrtc | 467 } // namespace webrtc |
OLD | NEW |