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