1 /*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
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
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #ifdef WEBRTC_ANDROID_OPENSLES_OUTPUT
12
13 #include "webrtc/modules/audio_device/android/opensles_output.h"
14
15 #include <assert.h>
16 #include <dlfcn.h>
17
18 #include "OpenSLESProvider.h"
19 #include "webrtc/modules/audio_device/android/opensles_common.h"
20 #include "webrtc/modules/audio_device/android/fine_audio_buffer.h"
21 #include "webrtc/modules/audio_device/android/single_rw_fifo.h"
22 #include "webrtc/modules/audio_device/audio_device_buffer.h"
23 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
24 #include "webrtc/system_wrappers/interface/thread_wrapper.h"
25 #include "webrtc/system_wrappers/interface/trace.h"
26
27 #define VOID_RETURN
28 #define OPENSL_RETURN_ON_FAILURE(op, ret_val) \
29 do { \
30 SLresult err = (op); \
31 if (err != SL_RESULT_SUCCESS) { \
32 assert(false); \
33 return ret_val; \
34 } \
35 } while (0)
36
37 static const SLEngineOption kOption[] = {
38 { SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE) },
39 };
40
41 enum {
42 kNoUnderrun,
43 kUnderrun,
44 };
45
46 namespace webrtc {
47
OpenSlesOutput(AudioManager * audio_manager)48 OpenSlesOutput::OpenSlesOutput(AudioManager* audio_manager)
49 : initialized_(false),
50 speaker_initialized_(false),
51 play_initialized_(false),
52 crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
53 playing_(false),
54 num_fifo_buffers_needed_(0),
55 number_underruns_(0),
56 sles_engine_(NULL),
57 sles_engine_itf_(NULL),
58 sles_player_(NULL),
59 sles_player_itf_(NULL),
60 sles_player_sbq_itf_(NULL),
61 sles_output_mixer_(NULL),
62 audio_buffer_(NULL),
63 active_queue_(0),
64 speaker_sampling_rate_(kDefaultSampleRate),
65 buffer_size_samples_(0),
66 buffer_size_bytes_(0),
67 playout_delay_(0),
68 opensles_lib_(NULL) {
69 }
70
~OpenSlesOutput()71 OpenSlesOutput::~OpenSlesOutput() {
72 }
73
SetAndroidAudioDeviceObjects(void * javaVM,void * context)74 int32_t OpenSlesOutput::SetAndroidAudioDeviceObjects(void* javaVM,
75 void* context) {
76 AudioManagerJni::SetAndroidAudioDeviceObjects(javaVM, context);
77 return 0;
78 }
79
ClearAndroidAudioDeviceObjects()80 void OpenSlesOutput::ClearAndroidAudioDeviceObjects() {
81 AudioManagerJni::ClearAndroidAudioDeviceObjects();
82 }
83
Init()84 int32_t OpenSlesOutput::Init() {
85 assert(!initialized_);
86
87 /* Try to dynamically open the OpenSLES library */
88 opensles_lib_ = dlopen("libOpenSLES.so", RTLD_LAZY);
89 if (!opensles_lib_) {
90 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, -1,
91 " failed to dlopen OpenSLES library");
92 return -1;
93 }
94
95 f_slCreateEngine = (slCreateEngine_t)dlsym(opensles_lib_, "slCreateEngine");
96 SL_IID_ENGINE_ = *(SLInterfaceID *)dlsym(opensles_lib_, "SL_IID_ENGINE");
97 SL_IID_BUFFERQUEUE_ = *(SLInterfaceID *)dlsym(opensles_lib_, "SL_IID_BUFFERQUEUE");
98 SL_IID_ANDROIDCONFIGURATION_ = *(SLInterfaceID *)dlsym(opensles_lib_, "SL_IID_ANDROIDCONFIGURATION");
99 SL_IID_PLAY_ = *(SLInterfaceID *)dlsym(opensles_lib_, "SL_IID_PLAY");
100 SL_IID_ANDROIDSIMPLEBUFFERQUEUE_ = *(SLInterfaceID *)dlsym(opensles_lib_, "SL_IID_ANDROIDSIMPLEBUFFERQUEUE");
101 SL_IID_VOLUME_ = *(SLInterfaceID *)dlsym(opensles_lib_, "SL_IID_VOLUME");
102
103 if (!f_slCreateEngine ||
104 !SL_IID_ENGINE_ ||
105 !SL_IID_BUFFERQUEUE_ ||
106 !SL_IID_ANDROIDCONFIGURATION_ ||
107 !SL_IID_PLAY_ ||
108 !SL_IID_ANDROIDSIMPLEBUFFERQUEUE_ ||
109 !SL_IID_VOLUME_) {
110 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, -1,
111 " failed to find OpenSLES function");
112 return -1;
113 }
114
115 // Set up OpenSl engine.
116 #ifndef MOZILLA_INTERNAL_API
117 OPENSL_RETURN_ON_FAILURE(f_slCreateEngine(&sles_engine_, 1, kOption, 0,
118 NULL, NULL),
119 -1);
120 #else
121 OPENSL_RETURN_ON_FAILURE(mozilla_get_sles_engine(&sles_engine_, 1, kOption), -1);
122 #endif
123 #ifndef MOZILLA_INTERNAL_API
124 OPENSL_RETURN_ON_FAILURE((*sles_engine_)->Realize(sles_engine_,
125 SL_BOOLEAN_FALSE),
126 -1);
127 #else
128 OPENSL_RETURN_ON_FAILURE(mozilla_realize_sles_engine(sles_engine_), -1);
129 #endif
130 OPENSL_RETURN_ON_FAILURE((*sles_engine_)->GetInterface(sles_engine_,
131 SL_IID_ENGINE_,
132 &sles_engine_itf_),
133 -1);
134 // Set up OpenSl output mix.
135 OPENSL_RETURN_ON_FAILURE(
136 (*sles_engine_itf_)->CreateOutputMix(sles_engine_itf_,
137 &sles_output_mixer_,
138 0,
139 NULL,
140 NULL),
141 -1);
142 OPENSL_RETURN_ON_FAILURE(
143 (*sles_output_mixer_)->Realize(sles_output_mixer_,
144 SL_BOOLEAN_FALSE),
145 -1);
146
147 if (!InitSampleRate()) {
148 return -1;
149 }
150 AllocateBuffers();
151 initialized_ = true;
152 return 0;
153 }
154
Terminate()155 int32_t OpenSlesOutput::Terminate() {
156 // It is assumed that the caller has stopped recording before terminating.
157 assert(!playing_);
158 (*sles_output_mixer_)->Destroy(sles_output_mixer_);
159 #ifndef MOZILLA_INTERNAL_API
160 (*sles_engine_)->Destroy(sles_engine_);
161 #else
162 mozilla_destroy_sles_engine(&sles_engine_);
163 #endif
164 initialized_ = false;
165 speaker_initialized_ = false;
166 play_initialized_ = false;
167 dlclose(opensles_lib_);
168 return 0;
169 }
170
PlayoutDeviceName(uint16_t index,char name[kAdmMaxDeviceNameSize],char guid[kAdmMaxGuidSize])171 int32_t OpenSlesOutput::PlayoutDeviceName(uint16_t index,
172 char name[kAdmMaxDeviceNameSize],
173 char guid[kAdmMaxGuidSize]) {
174 assert(index == 0);
175 // Empty strings.
176 name[0] = '\0';
177 guid[0] = '\0';
178 return 0;
179 }
180
SetPlayoutDevice(uint16_t index)181 int32_t OpenSlesOutput::SetPlayoutDevice(uint16_t index) {
182 assert(index == 0);
183 return 0;
184 }
185
PlayoutIsAvailable(bool & available)186 int32_t OpenSlesOutput::PlayoutIsAvailable(bool& available) { // NOLINT
187 available = true;
188 return 0;
189 }
190
InitPlayout()191 int32_t OpenSlesOutput::InitPlayout() {
192 assert(initialized_);
193 play_initialized_ = true;
194 return 0;
195 }
196
StartPlayout()197 int32_t OpenSlesOutput::StartPlayout() {
198 assert(play_initialized_);
199 assert(!playing_);
200 if (!CreateAudioPlayer()) {
201 return -1;
202 }
203
204 // Register callback to receive enqueued buffers.
205 OPENSL_RETURN_ON_FAILURE(
206 (*sles_player_sbq_itf_)->RegisterCallback(sles_player_sbq_itf_,
207 PlayerSimpleBufferQueueCallback,
208 this),
209 -1);
210 if (!EnqueueAllBuffers()) {
211 return -1;
212 }
213
214 {
215 // To prevent the compiler from e.g. optimizing the code to
216 // playing_ = StartCbThreads() which wouldn't have been thread safe.
217 CriticalSectionScoped lock(crit_sect_.get());
218 playing_ = true;
219 }
220 if (!StartCbThreads()) {
221 playing_ = false;
222 }
223 return 0;
224 }
225
StopPlayout()226 int32_t OpenSlesOutput::StopPlayout() {
227 StopCbThreads();
228 DestroyAudioPlayer();
229 playing_ = false;
230 return 0;
231 }
232
InitSpeaker()233 int32_t OpenSlesOutput::InitSpeaker() {
234 assert(!playing_);
235 speaker_initialized_ = true;
236 return 0;
237 }
238
SpeakerVolumeIsAvailable(bool & available)239 int32_t OpenSlesOutput::SpeakerVolumeIsAvailable(bool& available) { // NOLINT
240 available = true;
241 return 0;
242 }
243
SetSpeakerVolume(uint32_t volume)244 int32_t OpenSlesOutput::SetSpeakerVolume(uint32_t volume) {
245 assert(speaker_initialized_);
246 assert(initialized_);
247 // TODO(hellner): implement.
248 return 0;
249 }
250
MaxSpeakerVolume(uint32_t & maxVolume) const251 int32_t OpenSlesOutput::MaxSpeakerVolume(uint32_t& maxVolume) const { // NOLINT
252 assert(speaker_initialized_);
253 assert(initialized_);
254 // TODO(hellner): implement.
255 maxVolume = 0;
256 return 0;
257 }
258
MinSpeakerVolume(uint32_t & minVolume) const259 int32_t OpenSlesOutput::MinSpeakerVolume(uint32_t& minVolume) const { // NOLINT
260 assert(speaker_initialized_);
261 assert(initialized_);
262 // TODO(hellner): implement.
263 minVolume = 0;
264 return 0;
265 }
266
SpeakerVolumeStepSize(uint16_t & stepSize) const267 int32_t OpenSlesOutput::SpeakerVolumeStepSize(
268 uint16_t& stepSize) const { // NOLINT
269 assert(speaker_initialized_);
270 stepSize = 1;
271 return 0;
272 }
273
SpeakerMuteIsAvailable(bool & available)274 int32_t OpenSlesOutput::SpeakerMuteIsAvailable(bool& available) { // NOLINT
275 available = false;
276 return 0;
277 }
278
StereoPlayoutIsAvailable(bool & available)279 int32_t OpenSlesOutput::StereoPlayoutIsAvailable(bool& available) { // NOLINT
280 available = false;
281 return 0;
282 }
283
SetStereoPlayout(bool enable)284 int32_t OpenSlesOutput::SetStereoPlayout(bool enable) {
285 if (enable) {
286 assert(false);
287 return -1;
288 }
289 return 0;
290 }
291
StereoPlayout(bool & enabled) const292 int32_t OpenSlesOutput::StereoPlayout(bool& enabled) const { // NOLINT
293 enabled = kNumChannels == 2;
294 return 0;
295 }
296
PlayoutBuffer(AudioDeviceModule::BufferType & type,uint16_t & sizeMS) const297 int32_t OpenSlesOutput::PlayoutBuffer(
298 AudioDeviceModule::BufferType& type, // NOLINT
299 uint16_t& sizeMS) const { // NOLINT
300 type = AudioDeviceModule::kAdaptiveBufferSize;
301 sizeMS = playout_delay_;
302 return 0;
303 }
304
PlayoutDelay(uint16_t & delayMS) const305 int32_t OpenSlesOutput::PlayoutDelay(uint16_t& delayMS) const { // NOLINT
306 delayMS = playout_delay_;
307 return 0;
308 }
309
AttachAudioBuffer(AudioDeviceBuffer * audioBuffer)310 void OpenSlesOutput::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
311 audio_buffer_ = audioBuffer;
312 }
313
SetLoudspeakerStatus(bool enable)314 int32_t OpenSlesOutput::SetLoudspeakerStatus(bool enable) {
315 return 0;
316 }
317
GetLoudspeakerStatus(bool & enabled) const318 int32_t OpenSlesOutput::GetLoudspeakerStatus(bool& enabled) const { // NOLINT
319 enabled = true;
320 return 0;
321 }
322
PlayoutDelayMs()323 int OpenSlesOutput::PlayoutDelayMs() {
324 return playout_delay_;
325 }
326
InitSampleRate()327 bool OpenSlesOutput::InitSampleRate() {
328 if (!SetLowLatency()) {
329 speaker_sampling_rate_ = kDefaultSampleRate;
330 // Default is to use 10ms buffers.
331 buffer_size_samples_ = speaker_sampling_rate_ * 10 / 1000;
332 }
333 if (audio_buffer_->SetPlayoutSampleRate(speaker_sampling_rate_) < 0) {
334 return false;
335 }
336 if (audio_buffer_->SetPlayoutChannels(kNumChannels) < 0) {
337 return false;
338 }
339 UpdatePlayoutDelay();
340 return true;
341 }
342
UpdatePlayoutDelay()343 void OpenSlesOutput::UpdatePlayoutDelay() {
344 // TODO(hellner): Add accurate delay estimate.
345 // On average half the current buffer will have been played out.
346 int outstanding_samples = (TotalBuffersUsed() - 0.5) * buffer_size_samples_;
347 playout_delay_ = outstanding_samples / (speaker_sampling_rate_ / 1000);
348 }
349
SetLowLatency()350 bool OpenSlesOutput::SetLowLatency() {
351 #if !defined(WEBRTC_GONK)
352 if (!audio_manager_.low_latency_supported()) {
353 return false;
354 }
355 buffer_size_samples_ = audio_manager_.native_buffer_size();
356 assert(buffer_size_samples_ > 0);
357 speaker_sampling_rate_ = audio_manager_.native_output_sample_rate();
358 assert(speaker_sampling_rate_ > 0);
359 return true;
360 #else
361 return false;
362 #endif
363 }
364
CalculateNumFifoBuffersNeeded()365 void OpenSlesOutput::CalculateNumFifoBuffersNeeded() {
366 int number_of_bytes_needed =
367 (speaker_sampling_rate_ * kNumChannels * sizeof(int16_t)) * 10 / 1000;
368
369 // Ceiling of integer division: 1 + ((x - 1) / y)
370 int buffers_per_10_ms =
371 1 + ((number_of_bytes_needed - 1) / buffer_size_bytes_);
372 // |num_fifo_buffers_needed_| is a multiple of 10ms of buffered up audio.
373 num_fifo_buffers_needed_ = kNum10MsToBuffer * buffers_per_10_ms;
374 }
375
AllocateBuffers()376 void OpenSlesOutput::AllocateBuffers() {
377 // Allocate fine buffer to provide frames of the desired size.
378 buffer_size_bytes_ = buffer_size_samples_ * kNumChannels * sizeof(int16_t);
379 fine_buffer_.reset(new FineAudioBuffer(audio_buffer_, buffer_size_bytes_,
380 speaker_sampling_rate_));
381
382 // Allocate FIFO to handle passing buffers between processing and OpenSl
383 // threads.
384 CalculateNumFifoBuffersNeeded(); // Needs |buffer_size_bytes_| to be known
385 assert(num_fifo_buffers_needed_ > 0);
386 fifo_.reset(new SingleRwFifo(num_fifo_buffers_needed_));
387
388 // Allocate the memory area to be used.
389 play_buf_.reset(new rtc::scoped_ptr<int8_t[]>[TotalBuffersUsed()]);
390 int required_buffer_size = fine_buffer_->RequiredBufferSizeBytes();
391 for (int i = 0; i < TotalBuffersUsed(); ++i) {
392 play_buf_[i].reset(new int8_t[required_buffer_size]);
393 }
394 }
395
TotalBuffersUsed() const396 int OpenSlesOutput::TotalBuffersUsed() const {
397 return num_fifo_buffers_needed_ + kNumOpenSlBuffers;
398 }
399
EnqueueAllBuffers()400 bool OpenSlesOutput::EnqueueAllBuffers() {
401 active_queue_ = 0;
402 number_underruns_ = 0;
403 for (int i = 0; i < kNumOpenSlBuffers; ++i) {
404 memset(play_buf_[i].get(), 0, buffer_size_bytes_);
405 OPENSL_RETURN_ON_FAILURE(
406 (*sles_player_sbq_itf_)->Enqueue(
407 sles_player_sbq_itf_,
408 reinterpret_cast<void*>(play_buf_[i].get()),
409 buffer_size_bytes_),
410 false);
411 }
412 // OpenSL playing has been stopped. I.e. only this thread is touching
413 // |fifo_|.
414 while (fifo_->size() != 0) {
415 // Underrun might have happened when pushing new buffers to the FIFO.
416 fifo_->Pop();
417 }
418 for (int i = kNumOpenSlBuffers; i < TotalBuffersUsed(); ++i) {
419 memset(play_buf_[i].get(), 0, buffer_size_bytes_);
420 fifo_->Push(play_buf_[i].get());
421 }
422 return true;
423 }
424
CreateAudioPlayer()425 bool OpenSlesOutput::CreateAudioPlayer() {
426 if (!event_.Start()) {
427 assert(false);
428 return false;
429 }
430 SLDataLocator_AndroidSimpleBufferQueue simple_buf_queue = {
431 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
432 static_cast<SLuint32>(kNumOpenSlBuffers)
433 };
434 SLDataFormat_PCM configuration =
435 webrtc_opensl::CreatePcmConfiguration(speaker_sampling_rate_);
436 SLDataSource audio_source = { &simple_buf_queue, &configuration };
437
438 SLDataLocator_OutputMix locator_outputmix;
439 // Setup the data sink structure.
440 locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
441 locator_outputmix.outputMix = sles_output_mixer_;
442 SLDataSink audio_sink = { &locator_outputmix, NULL };
443
444 // Interfaces for streaming audio data, setting volume and Android are needed.
445 // Note the interfaces still need to be initialized. This only tells OpenSl
446 // that the interfaces will be needed at some point.
447 SLInterfaceID ids[kNumInterfaces] = {
448 SL_IID_BUFFERQUEUE_, SL_IID_VOLUME_, SL_IID_ANDROIDCONFIGURATION_ };
449 SLboolean req[kNumInterfaces] = {
450 SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
451 OPENSL_RETURN_ON_FAILURE(
452 (*sles_engine_itf_)->CreateAudioPlayer(sles_engine_itf_, &sles_player_,
453 &audio_source, &audio_sink,
454 kNumInterfaces, ids, req),
455 false);
456
457 SLAndroidConfigurationItf player_config;
458 OPENSL_RETURN_ON_FAILURE(
459 (*sles_player_)->GetInterface(sles_player_,
460 SL_IID_ANDROIDCONFIGURATION_,
461 &player_config),
462 false);
463
464 // Set audio player configuration to SL_ANDROID_STREAM_VOICE which corresponds
465 // to android.media.AudioManager.STREAM_VOICE_CALL.
466 SLint32 stream_type = SL_ANDROID_STREAM_VOICE;
467 OPENSL_RETURN_ON_FAILURE(
468 (*player_config)->SetConfiguration(player_config,
469 SL_ANDROID_KEY_STREAM_TYPE,
470 &stream_type,
471 sizeof(SLint32)),
472 false);
473
474 // Realize the player in synchronous mode.
475 OPENSL_RETURN_ON_FAILURE((*sles_player_)->Realize(sles_player_,
476 SL_BOOLEAN_FALSE),
477 false);
478 OPENSL_RETURN_ON_FAILURE(
479 (*sles_player_)->GetInterface(sles_player_, SL_IID_PLAY_,
480 &sles_player_itf_),
481 false);
482 OPENSL_RETURN_ON_FAILURE(
483 (*sles_player_)->GetInterface(sles_player_, SL_IID_BUFFERQUEUE_,
484 &sles_player_sbq_itf_),
485 false);
486 return true;
487 }
488
DestroyAudioPlayer()489 void OpenSlesOutput::DestroyAudioPlayer() {
490 SLAndroidSimpleBufferQueueItf sles_player_sbq_itf = sles_player_sbq_itf_;
491 {
492 CriticalSectionScoped lock(crit_sect_.get());
493 sles_player_sbq_itf_ = NULL;
494 sles_player_itf_ = NULL;
495 }
496 event_.Stop();
497 if (sles_player_sbq_itf) {
498 // Release all buffers currently queued up.
499 OPENSL_RETURN_ON_FAILURE(
500 (*sles_player_sbq_itf)->Clear(sles_player_sbq_itf),
501 VOID_RETURN);
502 }
503
504 if (sles_player_) {
505 (*sles_player_)->Destroy(sles_player_);
506 sles_player_ = NULL;
507 }
508 }
509
HandleUnderrun(int event_id,int event_msg)510 bool OpenSlesOutput::HandleUnderrun(int event_id, int event_msg) {
511 if (!playing_) {
512 return false;
513 }
514 if (event_id == kNoUnderrun) {
515 return false;
516 }
517 assert(event_id == kUnderrun);
518 assert(event_msg > 0);
519 // Wait for all enqueued buffers to be flushed.
520 if (event_msg != kNumOpenSlBuffers) {
521 return true;
522 }
523 // All buffers have been flushed. Restart the audio from scratch.
524 // No need to check sles_player_itf_ as playing_ would be false before it is
525 // set to NULL.
526 OPENSL_RETURN_ON_FAILURE(
527 (*sles_player_itf_)->SetPlayState(sles_player_itf_,
528 SL_PLAYSTATE_STOPPED),
529 true);
530 EnqueueAllBuffers();
531 OPENSL_RETURN_ON_FAILURE(
532 (*sles_player_itf_)->SetPlayState(sles_player_itf_,
533 SL_PLAYSTATE_PLAYING),
534 true);
535 return true;
536 }
537
PlayerSimpleBufferQueueCallback(SLAndroidSimpleBufferQueueItf sles_player_sbq_itf,void * p_context)538 void OpenSlesOutput::PlayerSimpleBufferQueueCallback(
539 SLAndroidSimpleBufferQueueItf sles_player_sbq_itf,
540 void* p_context) {
541 OpenSlesOutput* audio_device = reinterpret_cast<OpenSlesOutput*>(p_context);
542 audio_device->PlayerSimpleBufferQueueCallbackHandler(sles_player_sbq_itf);
543 }
544
PlayerSimpleBufferQueueCallbackHandler(SLAndroidSimpleBufferQueueItf sles_player_sbq_itf)545 void OpenSlesOutput::PlayerSimpleBufferQueueCallbackHandler(
546 SLAndroidSimpleBufferQueueItf sles_player_sbq_itf) {
547 if (fifo_->size() <= 0 || number_underruns_ > 0) {
548 ++number_underruns_;
549 event_.SignalEvent(kUnderrun, number_underruns_);
550 return;
551 }
552 int8_t* audio = fifo_->Pop();
553 if (audio)
554 OPENSL_RETURN_ON_FAILURE(
555 (*sles_player_sbq_itf)->Enqueue(sles_player_sbq_itf,
556 audio,
557 buffer_size_bytes_),
558 VOID_RETURN);
559 event_.SignalEvent(kNoUnderrun, 0);
560 }
561
StartCbThreads()562 bool OpenSlesOutput::StartCbThreads() {
563 play_thread_ = ThreadWrapper::CreateThread(CbThread, this,
564 "opensl_play_thread");
565 assert(play_thread_.get());
566 OPENSL_RETURN_ON_FAILURE(
567 (*sles_player_itf_)->SetPlayState(sles_player_itf_,
568 SL_PLAYSTATE_PLAYING),
569 false);
570
571 if (!play_thread_->Start()) {
572 assert(false);
573 return false;
574 }
575 play_thread_->SetPriority(kRealtimePriority);
576 return true;
577 }
578
StopCbThreads()579 void OpenSlesOutput::StopCbThreads() {
580 {
581 CriticalSectionScoped lock(crit_sect_.get());
582 playing_ = false;
583 }
584 if (sles_player_itf_) {
585 OPENSL_RETURN_ON_FAILURE(
586 (*sles_player_itf_)->SetPlayState(sles_player_itf_,
587 SL_PLAYSTATE_STOPPED),
588 VOID_RETURN);
589 }
590 if (play_thread_.get() == NULL) {
591 return;
592 }
593 event_.Stop();
594 if (play_thread_->Stop()) {
595 play_thread_.reset();
596 } else {
597 assert(false);
598 }
599 }
600
CbThread(void * context)601 bool OpenSlesOutput::CbThread(void* context) {
602 return reinterpret_cast<OpenSlesOutput*>(context)->CbThreadImpl();
603 }
604
CbThreadImpl()605 bool OpenSlesOutput::CbThreadImpl() {
606 assert(fine_buffer_.get() != NULL);
607 int event_id;
608 int event_msg;
609 // event_ must not be waited on while a lock has been taken.
610 event_.WaitOnEvent(&event_id, &event_msg);
611
612 CriticalSectionScoped lock(crit_sect_.get());
613 if (HandleUnderrun(event_id, event_msg)) {
614 return playing_;
615 }
616 // if fifo_ is not full it means next item in memory must be free.
617 while (fifo_->size() < num_fifo_buffers_needed_ && playing_) {
618 int8_t* audio = play_buf_[active_queue_].get();
619 fine_buffer_->GetBufferData(audio);
620 fifo_->Push(audio);
621 active_queue_ = (active_queue_ + 1) % TotalBuffersUsed();
622 }
623 return playing_;
624 }
625
626 } // namespace webrtc
627
628 #endif
629