Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Side by Side Diff: webrtc/modules/audio_device/android/opensles_player.cc

Issue 2119633004: Adds support for OpenSL ES based audio capture on Android (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Rebased Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698