| 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/base/timeutils.h" |
| 19 #include "webrtc/modules/audio_device/android/audio_common.h" |
| 19 #include "webrtc/modules/audio_device/android/audio_manager.h" | 20 #include "webrtc/modules/audio_device/android/audio_manager.h" |
| 20 #include "webrtc/modules/audio_device/fine_audio_buffer.h" | 21 #include "webrtc/modules/audio_device/fine_audio_buffer.h" |
| 21 | 22 |
| 22 #define TAG "OpenSLESPlayer" | 23 #define TAG "OpenSLESPlayer" |
| 23 #define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__) | 24 #define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__) |
| 24 #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) | 25 #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) |
| 25 #define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) | 26 #define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) |
| 26 #define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__) | 27 #define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__) |
| 27 #define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) | 28 #define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) |
| 28 | 29 |
| 29 #define RETURN_ON_ERROR(op, ...) \ | 30 #define RETURN_ON_ERROR(op, ...) \ |
| 30 do { \ | 31 do { \ |
| 31 SLresult err = (op); \ | 32 SLresult err = (op); \ |
| 32 if (err != SL_RESULT_SUCCESS) { \ | 33 if (err != SL_RESULT_SUCCESS) { \ |
| 33 ALOGE("%s failed: %d", #op, err); \ | 34 ALOGE("%s failed: %s", #op, GetSLErrorString(err)); \ |
| 34 return __VA_ARGS__; \ | 35 return __VA_ARGS__; \ |
| 35 } \ | 36 } \ |
| 36 } while (0) | 37 } while (0) |
| 37 | 38 |
| 38 namespace webrtc { | 39 namespace webrtc { |
| 39 | 40 |
| 40 OpenSLESPlayer::OpenSLESPlayer(AudioManager* audio_manager) | 41 OpenSLESPlayer::OpenSLESPlayer(AudioManager* audio_manager) |
| 41 : audio_parameters_(audio_manager->GetPlayoutAudioParameters()), | 42 : audio_manager_(audio_manager), |
| 42 audio_device_buffer_(NULL), | 43 audio_parameters_(audio_manager->GetPlayoutAudioParameters()), |
| 44 audio_device_buffer_(nullptr), |
| 43 initialized_(false), | 45 initialized_(false), |
| 44 playing_(false), | 46 playing_(false), |
| 45 bytes_per_buffer_(0), | 47 bytes_per_buffer_(0), |
| 46 buffer_index_(0), | 48 buffer_index_(0), |
| 47 engine_(nullptr), | 49 engine_(nullptr), |
| 48 player_(nullptr), | 50 player_(nullptr), |
| 49 simple_buffer_queue_(nullptr), | 51 simple_buffer_queue_(nullptr), |
| 50 volume_(nullptr), | 52 volume_(nullptr), |
| 51 last_play_time_(0) { | 53 last_play_time_(0) { |
| 52 ALOGD("ctor%s", GetThreadInfo().c_str()); | 54 ALOGD("ctor%s", GetThreadInfo().c_str()); |
| 53 // Use native audio output parameters provided by the audio manager and | 55 // Use native audio output parameters provided by the audio manager and |
| 54 // define the PCM format structure. | 56 // define the PCM format structure. |
| 55 pcm_format_ = CreatePCMConfiguration(audio_parameters_.channels(), | 57 pcm_format_ = CreatePCMConfiguration(audio_parameters_.channels(), |
| 56 audio_parameters_.sample_rate(), | 58 audio_parameters_.sample_rate(), |
| 57 audio_parameters_.bits_per_sample()); | 59 audio_parameters_.bits_per_sample()); |
| 58 // Detach from this thread since we want to use the checker to verify calls | 60 // Detach from this thread since we want to use the checker to verify calls |
| 59 // from the internal audio thread. | 61 // from the internal audio thread. |
| 60 thread_checker_opensles_.DetachFromThread(); | 62 thread_checker_opensles_.DetachFromThread(); |
| 61 } | 63 } |
| 62 | 64 |
| 63 OpenSLESPlayer::~OpenSLESPlayer() { | 65 OpenSLESPlayer::~OpenSLESPlayer() { |
| 64 ALOGD("dtor%s", GetThreadInfo().c_str()); | 66 ALOGD("dtor%s", GetThreadInfo().c_str()); |
| 65 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 67 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| 66 Terminate(); | 68 Terminate(); |
| 67 DestroyAudioPlayer(); | 69 DestroyAudioPlayer(); |
| 68 DestroyMix(); | 70 DestroyMix(); |
| 69 DestroyEngine(); | 71 engine_ = nullptr; |
| 70 RTC_DCHECK(!engine_object_.Get()); | |
| 71 RTC_DCHECK(!engine_); | 72 RTC_DCHECK(!engine_); |
| 72 RTC_DCHECK(!output_mix_.Get()); | 73 RTC_DCHECK(!output_mix_.Get()); |
| 73 RTC_DCHECK(!player_); | 74 RTC_DCHECK(!player_); |
| 74 RTC_DCHECK(!simple_buffer_queue_); | 75 RTC_DCHECK(!simple_buffer_queue_); |
| 75 RTC_DCHECK(!volume_); | 76 RTC_DCHECK(!volume_); |
| 76 } | 77 } |
| 77 | 78 |
| 78 int OpenSLESPlayer::Init() { | 79 int OpenSLESPlayer::Init() { |
| 79 ALOGD("Init%s", GetThreadInfo().c_str()); | 80 ALOGD("Init%s", GetThreadInfo().c_str()); |
| 80 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 81 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| 81 return 0; | 82 return 0; |
| 82 } | 83 } |
| 83 | 84 |
| 84 int OpenSLESPlayer::Terminate() { | 85 int OpenSLESPlayer::Terminate() { |
| 85 ALOGD("Terminate%s", GetThreadInfo().c_str()); | 86 ALOGD("Terminate%s", GetThreadInfo().c_str()); |
| 86 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 87 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| 87 StopPlayout(); | 88 StopPlayout(); |
| 88 return 0; | 89 return 0; |
| 89 } | 90 } |
| 90 | 91 |
| 91 int OpenSLESPlayer::InitPlayout() { | 92 int OpenSLESPlayer::InitPlayout() { |
| 92 ALOGD("InitPlayout%s", GetThreadInfo().c_str()); | 93 ALOGD("InitPlayout%s", GetThreadInfo().c_str()); |
| 93 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 94 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| 94 RTC_DCHECK(!initialized_); | 95 RTC_DCHECK(!initialized_); |
| 95 RTC_DCHECK(!playing_); | 96 RTC_DCHECK(!playing_); |
| 96 CreateEngine(); | 97 GetEngineInterface(); |
| 97 CreateMix(); | 98 CreateMix(); |
| 98 initialized_ = true; | 99 initialized_ = true; |
| 99 buffer_index_ = 0; | 100 buffer_index_ = 0; |
| 100 last_play_time_ = rtc::Time(); | 101 last_play_time_ = rtc::Time(); |
| 101 return 0; | 102 return 0; |
| 102 } | 103 } |
| 103 | 104 |
| 104 int OpenSLESPlayer::StartPlayout() { | 105 int OpenSLESPlayer::StartPlayout() { |
| 105 ALOGD("StartPlayout%s", GetThreadInfo().c_str()); | 106 ALOGD("StartPlayout%s", GetThreadInfo().c_str()); |
| 106 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 107 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 256 // Each buffer must be of this size to avoid unnecessary memcpy while caching | 257 // Each buffer must be of this size to avoid unnecessary memcpy while caching |
| 257 // data between successive callbacks. | 258 // data between successive callbacks. |
| 258 const size_t required_buffer_size = | 259 const size_t required_buffer_size = |
| 259 fine_buffer_->RequiredPlayoutBufferSizeBytes(); | 260 fine_buffer_->RequiredPlayoutBufferSizeBytes(); |
| 260 ALOGD("required buffer size: %" PRIuS, required_buffer_size); | 261 ALOGD("required buffer size: %" PRIuS, required_buffer_size); |
| 261 for (int i = 0; i < kNumOfOpenSLESBuffers; ++i) { | 262 for (int i = 0; i < kNumOfOpenSLESBuffers; ++i) { |
| 262 audio_buffers_[i].reset(new SLint8[required_buffer_size]); | 263 audio_buffers_[i].reset(new SLint8[required_buffer_size]); |
| 263 } | 264 } |
| 264 } | 265 } |
| 265 | 266 |
| 266 bool OpenSLESPlayer::CreateEngine() { | 267 bool OpenSLESPlayer::GetEngineInterface() { |
| 267 ALOGD("CreateEngine"); | 268 ALOGD("GetEngineInterface"); |
| 268 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 269 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| 269 if (engine_object_.Get()) | |
| 270 return true; | |
| 271 RTC_DCHECK(!engine_); | 270 RTC_DCHECK(!engine_); |
| 272 const SLEngineOption option[] = { | 271 // Get access to (or create if not already existing) the global OpenSL Engine |
| 273 {SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE)}}; | 272 // object. |
| 273 SLObjectItf engine_object = audio_manager_->GetOpenSLEngine(); |
| 274 if (engine_object == nullptr) { |
| 275 ALOGE("Failed to access the global OpenSL engine"); |
| 276 return false; |
| 277 } |
| 278 // Get the SL Engine Interface which is implicit. |
| 274 RETURN_ON_ERROR( | 279 RETURN_ON_ERROR( |
| 275 slCreateEngine(engine_object_.Receive(), 1, option, 0, NULL, NULL), | 280 (*engine_object)->GetInterface(engine_object, SL_IID_ENGINE, &engine_), |
| 276 false); | 281 false); |
| 277 RETURN_ON_ERROR( | |
| 278 engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE), false); | |
| 279 RETURN_ON_ERROR(engine_object_->GetInterface(engine_object_.Get(), | |
| 280 SL_IID_ENGINE, &engine_), | |
| 281 false); | |
| 282 return true; | 282 return true; |
| 283 } | 283 } |
| 284 | 284 |
| 285 void OpenSLESPlayer::DestroyEngine() { | |
| 286 ALOGD("DestroyEngine"); | |
| 287 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | |
| 288 if (!engine_object_.Get()) | |
| 289 return; | |
| 290 engine_ = nullptr; | |
| 291 engine_object_.Reset(); | |
| 292 } | |
| 293 | |
| 294 bool OpenSLESPlayer::CreateMix() { | 285 bool OpenSLESPlayer::CreateMix() { |
| 295 ALOGD("CreateMix"); | 286 ALOGD("CreateMix"); |
| 296 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 287 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| 297 RTC_DCHECK(engine_); | 288 RTC_DCHECK(engine_); |
| 298 if (output_mix_.Get()) | 289 if (output_mix_.Get()) |
| 299 return true; | 290 return true; |
| 300 | 291 |
| 301 // Create the ouput mix on the engine object. No interfaces will be used. | 292 // Create the ouput mix on the engine object. No interfaces will be used. |
| 302 RETURN_ON_ERROR((*engine_)->CreateOutputMix(engine_, output_mix_.Receive(), 0, | 293 RETURN_ON_ERROR((*engine_)->CreateOutputMix(engine_, output_mix_.Receive(), 0, |
| 303 NULL, NULL), | 294 nullptr, nullptr), |
| 304 false); | 295 false); |
| 305 RETURN_ON_ERROR(output_mix_->Realize(output_mix_.Get(), SL_BOOLEAN_FALSE), | 296 RETURN_ON_ERROR(output_mix_->Realize(output_mix_.Get(), SL_BOOLEAN_FALSE), |
| 306 false); | 297 false); |
| 307 return true; | 298 return true; |
| 308 } | 299 } |
| 309 | 300 |
| 310 void OpenSLESPlayer::DestroyMix() { | 301 void OpenSLESPlayer::DestroyMix() { |
| 311 ALOGD("DestroyMix"); | 302 ALOGD("DestroyMix"); |
| 312 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 303 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| 313 if (!output_mix_.Get()) | 304 if (!output_mix_.Get()) |
| 314 return; | 305 return; |
| 315 output_mix_.Reset(); | 306 output_mix_.Reset(); |
| 316 } | 307 } |
| 317 | 308 |
| 318 bool OpenSLESPlayer::CreateAudioPlayer() { | 309 bool OpenSLESPlayer::CreateAudioPlayer() { |
| 319 ALOGD("CreateAudioPlayer"); | 310 ALOGD("CreateAudioPlayer"); |
| 320 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 311 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| 321 RTC_DCHECK(engine_object_.Get()); | |
| 322 RTC_DCHECK(output_mix_.Get()); | 312 RTC_DCHECK(output_mix_.Get()); |
| 323 if (player_object_.Get()) | 313 if (player_object_.Get()) |
| 324 return true; | 314 return true; |
| 325 RTC_DCHECK(!player_); | 315 RTC_DCHECK(!player_); |
| 326 RTC_DCHECK(!simple_buffer_queue_); | 316 RTC_DCHECK(!simple_buffer_queue_); |
| 327 RTC_DCHECK(!volume_); | 317 RTC_DCHECK(!volume_); |
| 328 | 318 |
| 329 // source: Android Simple Buffer Queue Data Locator is source. | 319 // source: Android Simple Buffer Queue Data Locator is source. |
| 330 SLDataLocator_AndroidSimpleBufferQueue simple_buffer_queue = { | 320 SLDataLocator_AndroidSimpleBufferQueue simple_buffer_queue = { |
| 331 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, | 321 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, |
| 332 static_cast<SLuint32>(kNumOfOpenSLESBuffers)}; | 322 static_cast<SLuint32>(kNumOfOpenSLESBuffers)}; |
| 333 SLDataSource audio_source = {&simple_buffer_queue, &pcm_format_}; | 323 SLDataSource audio_source = {&simple_buffer_queue, &pcm_format_}; |
| 334 | 324 |
| 335 // sink: OutputMix-based data is sink. | 325 // sink: OutputMix-based data is sink. |
| 336 SLDataLocator_OutputMix locator_output_mix = {SL_DATALOCATOR_OUTPUTMIX, | 326 SLDataLocator_OutputMix locator_output_mix = {SL_DATALOCATOR_OUTPUTMIX, |
| 337 output_mix_.Get()}; | 327 output_mix_.Get()}; |
| 338 SLDataSink audio_sink = {&locator_output_mix, NULL}; | 328 SLDataSink audio_sink = {&locator_output_mix, nullptr}; |
| 339 | 329 |
| 340 // Define interfaces that we indend to use and realize. | 330 // Define interfaces that we indend to use and realize. |
| 341 const SLInterfaceID interface_ids[] = { | 331 const SLInterfaceID interface_ids[] = { |
| 342 SL_IID_ANDROIDCONFIGURATION, SL_IID_BUFFERQUEUE, SL_IID_VOLUME}; | 332 SL_IID_ANDROIDCONFIGURATION, SL_IID_BUFFERQUEUE, SL_IID_VOLUME}; |
| 343 const SLboolean interface_required[] = { | 333 const SLboolean interface_required[] = { |
| 344 SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; | 334 SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; |
| 345 | 335 |
| 346 // Create the audio player on the engine interface. | 336 // Create the audio player on the engine interface. |
| 347 RETURN_ON_ERROR( | 337 RETURN_ON_ERROR( |
| 348 (*engine_)->CreateAudioPlayer( | 338 (*engine_)->CreateAudioPlayer( |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 458 RTC_DCHECK(player_); | 448 RTC_DCHECK(player_); |
| 459 SLuint32 state; | 449 SLuint32 state; |
| 460 SLresult err = (*player_)->GetPlayState(player_, &state); | 450 SLresult err = (*player_)->GetPlayState(player_, &state); |
| 461 if (SL_RESULT_SUCCESS != err) { | 451 if (SL_RESULT_SUCCESS != err) { |
| 462 ALOGE("GetPlayState failed: %d", err); | 452 ALOGE("GetPlayState failed: %d", err); |
| 463 } | 453 } |
| 464 return state; | 454 return state; |
| 465 } | 455 } |
| 466 | 456 |
| 467 } // namespace webrtc | 457 } // namespace webrtc |
| OLD | NEW |