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