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