Home | History | Annotate | Download | only in android
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "media/audio/android/opensles_output.h"
      6 
      7 #include "base/debug/trace_event.h"
      8 #include "base/logging.h"
      9 #include "media/audio/android/audio_manager_android.h"
     10 
     11 #define LOG_ON_FAILURE_AND_RETURN(op, ...) \
     12   do { \
     13     SLresult err = (op);            \
     14     if (err != SL_RESULT_SUCCESS) { \
     15       DLOG(ERROR) << #op << " failed: " << err; \
     16       return __VA_ARGS__; \
     17     } \
     18   } while (0)
     19 
     20 namespace media {
     21 
     22 OpenSLESOutputStream::OpenSLESOutputStream(AudioManagerAndroid* manager,
     23                                            const AudioParameters& params)
     24     : audio_manager_(manager),
     25       callback_(NULL),
     26       player_(NULL),
     27       simple_buffer_queue_(NULL),
     28       active_queue_(0),
     29       buffer_size_bytes_(0),
     30       started_(false),
     31       volume_(1.0) {
     32   format_.formatType = SL_DATAFORMAT_PCM;
     33   format_.numChannels = static_cast<SLuint32>(params.channels());
     34   // Provides sampling rate in milliHertz to OpenSLES.
     35   format_.samplesPerSec = static_cast<SLuint32>(params.sample_rate() * 1000);
     36   format_.bitsPerSample = params.bits_per_sample();
     37   format_.containerSize = params.bits_per_sample();
     38   format_.endianness = SL_BYTEORDER_LITTLEENDIAN;
     39   if (format_.numChannels == 1)
     40     format_.channelMask = SL_SPEAKER_FRONT_CENTER;
     41   else if (format_.numChannels == 2)
     42     format_.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
     43   else
     44     NOTREACHED() << "Unsupported number of channels: " << format_.numChannels;
     45 
     46   buffer_size_bytes_ = params.GetBytesPerBuffer();
     47   audio_bus_ = AudioBus::Create(params);
     48 
     49   memset(&audio_data_, 0, sizeof(audio_data_));
     50 }
     51 
     52 OpenSLESOutputStream::~OpenSLESOutputStream() {
     53   DCHECK(!engine_object_.Get());
     54   DCHECK(!player_object_.Get());
     55   DCHECK(!output_mixer_.Get());
     56   DCHECK(!player_);
     57   DCHECK(!simple_buffer_queue_);
     58   DCHECK(!audio_data_[0]);
     59 }
     60 
     61 bool OpenSLESOutputStream::Open() {
     62   if (engine_object_.Get())
     63     return false;
     64 
     65   if (!CreatePlayer())
     66     return false;
     67 
     68   SetupAudioBuffer();
     69 
     70   return true;
     71 }
     72 
     73 void OpenSLESOutputStream::Start(AudioSourceCallback* callback) {
     74   DCHECK(callback);
     75   DCHECK(player_);
     76   DCHECK(simple_buffer_queue_);
     77   if (started_)
     78     return;
     79 
     80   // Enable the flags before streaming.
     81   callback_ = callback;
     82   active_queue_ = 0;
     83   started_ = true;
     84 
     85   // Avoid start-up glitches by filling up one buffer queue before starting
     86   // the stream.
     87   FillBufferQueue();
     88 
     89   // Start streaming data by setting the play state to |SL_PLAYSTATE_PLAYING|.
     90   LOG_ON_FAILURE_AND_RETURN(
     91       (*player_)->SetPlayState(player_, SL_PLAYSTATE_PLAYING));
     92 }
     93 
     94 void OpenSLESOutputStream::Stop() {
     95   if (!started_)
     96     return;
     97 
     98   started_ = false;
     99   // Stop playing by setting the play state to |SL_PLAYSTATE_STOPPED|.
    100   LOG_ON_FAILURE_AND_RETURN(
    101       (*player_)->SetPlayState(player_, SL_PLAYSTATE_STOPPED));
    102 
    103   // Clear the buffer queue so that the old data won't be played when
    104   // resuming playing.
    105   LOG_ON_FAILURE_AND_RETURN(
    106       (*simple_buffer_queue_)->Clear(simple_buffer_queue_));
    107 }
    108 
    109 void OpenSLESOutputStream::Close() {
    110   // Stop the stream if it is still playing.
    111   Stop();
    112 
    113   // Explicitly free the player objects and invalidate their associated
    114   // interfaces. They have to be done in the correct order.
    115   player_object_.Reset();
    116   output_mixer_.Reset();
    117   engine_object_.Reset();
    118   simple_buffer_queue_ = NULL;
    119   player_ = NULL;
    120 
    121   ReleaseAudioBuffer();
    122 
    123   audio_manager_->ReleaseOutputStream(this);
    124 }
    125 
    126 void OpenSLESOutputStream::SetVolume(double volume) {
    127   float volume_float = static_cast<float>(volume);
    128   if (volume_float < 0.0f || volume_float > 1.0f) {
    129     return;
    130   }
    131   volume_ = volume_float;
    132 }
    133 
    134 void OpenSLESOutputStream::GetVolume(double* volume) {
    135   *volume = static_cast<double>(volume_);
    136 }
    137 
    138 bool OpenSLESOutputStream::CreatePlayer() {
    139   // Initializes the engine object with specific option. After working with the
    140   // object, we need to free the object and its resources.
    141   SLEngineOption option[] = {
    142     { SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE) }
    143   };
    144   LOG_ON_FAILURE_AND_RETURN(
    145       slCreateEngine(engine_object_.Receive(), 1, option, 0, NULL, NULL),
    146       false);
    147 
    148   // Realize the SL engine object in synchronous mode.
    149   LOG_ON_FAILURE_AND_RETURN(
    150       engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE),
    151       false);
    152 
    153   // Get the SL engine interface which is implicit.
    154   SLEngineItf engine;
    155   LOG_ON_FAILURE_AND_RETURN(
    156       engine_object_->GetInterface(engine_object_.Get(),
    157                                    SL_IID_ENGINE,
    158                                    &engine),
    159       false);
    160 
    161   // Create ouput mixer object to be used by the player.
    162   LOG_ON_FAILURE_AND_RETURN(
    163       (*engine)->CreateOutputMix(engine,
    164                                  output_mixer_.Receive(),
    165                                  0,
    166                                  NULL,
    167                                  NULL),
    168       false);
    169 
    170   // Realizing the output mix object in synchronous mode.
    171   LOG_ON_FAILURE_AND_RETURN(
    172       output_mixer_->Realize(output_mixer_.Get(), SL_BOOLEAN_FALSE),
    173       false);
    174 
    175   // Audio source configuration.
    176   SLDataLocator_AndroidSimpleBufferQueue simple_buffer_queue = {
    177     SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
    178     static_cast<SLuint32>(kNumOfQueuesInBuffer)
    179   };
    180   SLDataSource audio_source = { &simple_buffer_queue, &format_ };
    181 
    182   // Audio sink configuration.
    183   SLDataLocator_OutputMix locator_output_mix = {
    184     SL_DATALOCATOR_OUTPUTMIX, output_mixer_.Get()
    185   };
    186   SLDataSink audio_sink = { &locator_output_mix, NULL };
    187 
    188   // Create an audio player.
    189   const SLInterfaceID interface_id[] = {
    190     SL_IID_BUFFERQUEUE,
    191     SL_IID_VOLUME,
    192     SL_IID_ANDROIDCONFIGURATION
    193   };
    194   const SLboolean interface_required[] = {
    195     SL_BOOLEAN_TRUE,
    196     SL_BOOLEAN_TRUE,
    197     SL_BOOLEAN_TRUE
    198   };
    199   LOG_ON_FAILURE_AND_RETURN(
    200       (*engine)->CreateAudioPlayer(engine,
    201                                    player_object_.Receive(),
    202                                    &audio_source,
    203                                    &audio_sink,
    204                                    arraysize(interface_id),
    205                                    interface_id,
    206                                    interface_required),
    207       false);
    208 
    209   // Create AudioPlayer and specify SL_IID_ANDROIDCONFIGURATION.
    210   SLAndroidConfigurationItf player_config;
    211   LOG_ON_FAILURE_AND_RETURN(
    212       player_object_->GetInterface(player_object_.Get(),
    213                                    SL_IID_ANDROIDCONFIGURATION,
    214                                    &player_config),
    215       false);
    216 
    217   SLint32 stream_type = SL_ANDROID_STREAM_VOICE;
    218   LOG_ON_FAILURE_AND_RETURN(
    219       (*player_config)->SetConfiguration(player_config,
    220                                          SL_ANDROID_KEY_STREAM_TYPE,
    221                                          &stream_type, sizeof(SLint32)),
    222       false);
    223 
    224   // Realize the player object in synchronous mode.
    225   LOG_ON_FAILURE_AND_RETURN(
    226       player_object_->Realize(player_object_.Get(), SL_BOOLEAN_FALSE),
    227       false);
    228 
    229   // Get an implicit player interface.
    230   LOG_ON_FAILURE_AND_RETURN(
    231       player_object_->GetInterface(player_object_.Get(), SL_IID_PLAY, &player_),
    232       false);
    233 
    234   // Get the simple buffer queue interface.
    235   LOG_ON_FAILURE_AND_RETURN(
    236       player_object_->GetInterface(player_object_.Get(),
    237                                    SL_IID_BUFFERQUEUE,
    238                                    &simple_buffer_queue_),
    239       false);
    240 
    241   // Register the input callback for the simple buffer queue.
    242   // This callback will be called when the soundcard needs data.
    243   LOG_ON_FAILURE_AND_RETURN(
    244       (*simple_buffer_queue_)->RegisterCallback(simple_buffer_queue_,
    245                                                 SimpleBufferQueueCallback,
    246                                                 this),
    247       false);
    248 
    249   return true;
    250 }
    251 
    252 void OpenSLESOutputStream::SimpleBufferQueueCallback(
    253     SLAndroidSimpleBufferQueueItf buffer_queue, void* instance) {
    254   OpenSLESOutputStream* stream =
    255       reinterpret_cast<OpenSLESOutputStream*>(instance);
    256   stream->FillBufferQueue();
    257 }
    258 
    259 void OpenSLESOutputStream::FillBufferQueue() {
    260   if (!started_)
    261     return;
    262 
    263   TRACE_EVENT0("audio", "OpenSLESOutputStream::FillBufferQueue");
    264   // Read data from the registered client source.
    265   // TODO(xians): Get an accurate delay estimation.
    266   uint32 hardware_delay = buffer_size_bytes_;
    267   int frames_filled = callback_->OnMoreData(
    268       audio_bus_.get(), AudioBuffersState(0, hardware_delay));
    269   if (frames_filled <= 0)
    270     return;  // Audio source is shutting down, or halted on error.
    271   int num_filled_bytes =
    272       frames_filled * audio_bus_->channels() * format_.bitsPerSample / 8;
    273   DCHECK_LE(static_cast<size_t>(num_filled_bytes), buffer_size_bytes_);
    274   // Note: If this ever changes to output raw float the data must be clipped and
    275   // sanitized since it may come from an untrusted source such as NaCl.
    276   audio_bus_->Scale(volume_);
    277   audio_bus_->ToInterleaved(
    278       frames_filled, format_.bitsPerSample / 8, audio_data_[active_queue_]);
    279 
    280   // Enqueue the buffer for playback.
    281   SLresult err = (*simple_buffer_queue_)->Enqueue(
    282       simple_buffer_queue_,
    283       audio_data_[active_queue_],
    284       num_filled_bytes);
    285   if (SL_RESULT_SUCCESS != err)
    286     HandleError(err);
    287 
    288   active_queue_ = (active_queue_  + 1) % kNumOfQueuesInBuffer;
    289 }
    290 
    291 void OpenSLESOutputStream::SetupAudioBuffer() {
    292   DCHECK(!audio_data_[0]);
    293   for (int i = 0; i < kNumOfQueuesInBuffer; ++i) {
    294     audio_data_[i] = new uint8[buffer_size_bytes_];
    295   }
    296 }
    297 
    298 void OpenSLESOutputStream::ReleaseAudioBuffer() {
    299   if (audio_data_[0]) {
    300     for (int i = 0; i < kNumOfQueuesInBuffer; ++i) {
    301       delete [] audio_data_[i];
    302       audio_data_[i] = NULL;
    303     }
    304   }
    305 }
    306 
    307 void OpenSLESOutputStream::HandleError(SLresult error) {
    308   DLOG(ERROR) << "OpenSLES Output error " << error;
    309   if (callback_)
    310     callback_->OnError(this);
    311 }
    312 
    313 }  // namespace media
    314