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 SLint32 stream_type) 25 : audio_manager_(manager), 26 stream_type_(stream_type), 27 callback_(NULL), 28 player_(NULL), 29 simple_buffer_queue_(NULL), 30 active_buffer_index_(0), 31 buffer_size_bytes_(0), 32 started_(false), 33 muted_(false), 34 volume_(1.0) { 35 DVLOG(2) << "OpenSLESOutputStream::OpenSLESOutputStream(" 36 << "stream_type=" << stream_type << ")"; 37 format_.formatType = SL_DATAFORMAT_PCM; 38 format_.numChannels = static_cast<SLuint32>(params.channels()); 39 // Provides sampling rate in milliHertz to OpenSLES. 40 format_.samplesPerSec = static_cast<SLuint32>(params.sample_rate() * 1000); 41 format_.bitsPerSample = params.bits_per_sample(); 42 format_.containerSize = params.bits_per_sample(); 43 format_.endianness = SL_BYTEORDER_LITTLEENDIAN; 44 if (format_.numChannels == 1) 45 format_.channelMask = SL_SPEAKER_FRONT_CENTER; 46 else if (format_.numChannels == 2) 47 format_.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; 48 else 49 NOTREACHED() << "Unsupported number of channels: " << format_.numChannels; 50 51 buffer_size_bytes_ = params.GetBytesPerBuffer(); 52 audio_bus_ = AudioBus::Create(params); 53 54 memset(&audio_data_, 0, sizeof(audio_data_)); 55 } 56 57 OpenSLESOutputStream::~OpenSLESOutputStream() { 58 DVLOG(2) << "OpenSLESOutputStream::~OpenSLESOutputStream()"; 59 DCHECK(thread_checker_.CalledOnValidThread()); 60 DCHECK(!engine_object_.Get()); 61 DCHECK(!player_object_.Get()); 62 DCHECK(!output_mixer_.Get()); 63 DCHECK(!player_); 64 DCHECK(!simple_buffer_queue_); 65 DCHECK(!audio_data_[0]); 66 } 67 68 bool OpenSLESOutputStream::Open() { 69 DVLOG(2) << "OpenSLESOutputStream::Open()"; 70 DCHECK(thread_checker_.CalledOnValidThread()); 71 if (engine_object_.Get()) 72 return false; 73 74 if (!CreatePlayer()) 75 return false; 76 77 SetupAudioBuffer(); 78 active_buffer_index_ = 0; 79 80 return true; 81 } 82 83 void OpenSLESOutputStream::Start(AudioSourceCallback* callback) { 84 DVLOG(2) << "OpenSLESOutputStream::Start()"; 85 DCHECK(thread_checker_.CalledOnValidThread()); 86 DCHECK(callback); 87 DCHECK(player_); 88 DCHECK(simple_buffer_queue_); 89 if (started_) 90 return; 91 92 base::AutoLock lock(lock_); 93 DCHECK(callback_ == NULL || callback_ == callback); 94 callback_ = callback; 95 96 // Avoid start-up glitches by filling up one buffer queue before starting 97 // the stream. 98 FillBufferQueueNoLock(); 99 100 // Start streaming data by setting the play state to SL_PLAYSTATE_PLAYING. 101 // For a player object, when the object is in the SL_PLAYSTATE_PLAYING 102 // state, adding buffers will implicitly start playback. 103 LOG_ON_FAILURE_AND_RETURN( 104 (*player_)->SetPlayState(player_, SL_PLAYSTATE_PLAYING)); 105 106 started_ = true; 107 } 108 109 void OpenSLESOutputStream::Stop() { 110 DVLOG(2) << "OpenSLESOutputStream::Stop()"; 111 DCHECK(thread_checker_.CalledOnValidThread()); 112 if (!started_) 113 return; 114 115 base::AutoLock lock(lock_); 116 117 // Stop playing by setting the play state to SL_PLAYSTATE_STOPPED. 118 LOG_ON_FAILURE_AND_RETURN( 119 (*player_)->SetPlayState(player_, SL_PLAYSTATE_STOPPED)); 120 121 // Clear the buffer queue so that the old data won't be played when 122 // resuming playing. 123 LOG_ON_FAILURE_AND_RETURN( 124 (*simple_buffer_queue_)->Clear(simple_buffer_queue_)); 125 126 #ifndef NDEBUG 127 // Verify that the buffer queue is in fact cleared as it should. 128 SLAndroidSimpleBufferQueueState buffer_queue_state; 129 LOG_ON_FAILURE_AND_RETURN((*simple_buffer_queue_)->GetState( 130 simple_buffer_queue_, &buffer_queue_state)); 131 DCHECK_EQ(0u, buffer_queue_state.count); 132 DCHECK_EQ(0u, buffer_queue_state.index); 133 #endif 134 135 callback_ = NULL; 136 started_ = false; 137 } 138 139 void OpenSLESOutputStream::Close() { 140 DVLOG(2) << "OpenSLESOutputStream::Close()"; 141 DCHECK(thread_checker_.CalledOnValidThread()); 142 143 // Stop the stream if it is still playing. 144 Stop(); 145 { 146 // Destroy the buffer queue player object and invalidate all associated 147 // interfaces. 148 player_object_.Reset(); 149 simple_buffer_queue_ = NULL; 150 player_ = NULL; 151 152 // Destroy the mixer object. We don't store any associated interface for 153 // this object. 154 output_mixer_.Reset(); 155 156 // Destroy the engine object. We don't store any associated interface for 157 // this object. 158 engine_object_.Reset(); 159 ReleaseAudioBuffer(); 160 } 161 162 audio_manager_->ReleaseOutputStream(this); 163 } 164 165 void OpenSLESOutputStream::SetVolume(double volume) { 166 DVLOG(2) << "OpenSLESOutputStream::SetVolume(" << volume << ")"; 167 DCHECK(thread_checker_.CalledOnValidThread()); 168 float volume_float = static_cast<float>(volume); 169 if (volume_float < 0.0f || volume_float > 1.0f) { 170 return; 171 } 172 volume_ = volume_float; 173 } 174 175 void OpenSLESOutputStream::GetVolume(double* volume) { 176 DCHECK(thread_checker_.CalledOnValidThread()); 177 *volume = static_cast<double>(volume_); 178 } 179 180 void OpenSLESOutputStream::SetMute(bool muted) { 181 DVLOG(2) << "OpenSLESOutputStream::SetMute(" << muted << ")"; 182 DCHECK(thread_checker_.CalledOnValidThread()); 183 muted_ = muted; 184 } 185 186 bool OpenSLESOutputStream::CreatePlayer() { 187 DCHECK(thread_checker_.CalledOnValidThread()); 188 DCHECK(!engine_object_.Get()); 189 DCHECK(!player_object_.Get()); 190 DCHECK(!output_mixer_.Get()); 191 DCHECK(!player_); 192 DCHECK(!simple_buffer_queue_); 193 194 // Initializes the engine object with specific option. After working with the 195 // object, we need to free the object and its resources. 196 SLEngineOption option[] = { 197 {SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE)}}; 198 LOG_ON_FAILURE_AND_RETURN( 199 slCreateEngine(engine_object_.Receive(), 1, option, 0, NULL, NULL), 200 false); 201 202 // Realize the SL engine object in synchronous mode. 203 LOG_ON_FAILURE_AND_RETURN( 204 engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE), false); 205 206 // Get the SL engine interface which is implicit. 207 SLEngineItf engine; 208 LOG_ON_FAILURE_AND_RETURN(engine_object_->GetInterface( 209 engine_object_.Get(), SL_IID_ENGINE, &engine), 210 false); 211 212 // Create ouput mixer object to be used by the player. 213 LOG_ON_FAILURE_AND_RETURN((*engine)->CreateOutputMix( 214 engine, output_mixer_.Receive(), 0, NULL, NULL), 215 false); 216 217 // Realizing the output mix object in synchronous mode. 218 LOG_ON_FAILURE_AND_RETURN( 219 output_mixer_->Realize(output_mixer_.Get(), SL_BOOLEAN_FALSE), false); 220 221 // Audio source configuration. 222 SLDataLocator_AndroidSimpleBufferQueue simple_buffer_queue = { 223 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 224 static_cast<SLuint32>(kMaxNumOfBuffersInQueue)}; 225 SLDataSource audio_source = {&simple_buffer_queue, &format_}; 226 227 // Audio sink configuration. 228 SLDataLocator_OutputMix locator_output_mix = {SL_DATALOCATOR_OUTPUTMIX, 229 output_mixer_.Get()}; 230 SLDataSink audio_sink = {&locator_output_mix, NULL}; 231 232 // Create an audio player. 233 const SLInterfaceID interface_id[] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME, 234 SL_IID_ANDROIDCONFIGURATION}; 235 const SLboolean interface_required[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, 236 SL_BOOLEAN_TRUE}; 237 LOG_ON_FAILURE_AND_RETURN( 238 (*engine)->CreateAudioPlayer(engine, 239 player_object_.Receive(), 240 &audio_source, 241 &audio_sink, 242 arraysize(interface_id), 243 interface_id, 244 interface_required), 245 false); 246 247 // Create AudioPlayer and specify SL_IID_ANDROIDCONFIGURATION. 248 SLAndroidConfigurationItf player_config; 249 LOG_ON_FAILURE_AND_RETURN( 250 player_object_->GetInterface( 251 player_object_.Get(), SL_IID_ANDROIDCONFIGURATION, &player_config), 252 false); 253 254 // Set configuration using the stream type provided at construction. 255 LOG_ON_FAILURE_AND_RETURN( 256 (*player_config)->SetConfiguration(player_config, 257 SL_ANDROID_KEY_STREAM_TYPE, 258 &stream_type_, 259 sizeof(SLint32)), 260 false); 261 262 // Realize the player object in synchronous mode. 263 LOG_ON_FAILURE_AND_RETURN( 264 player_object_->Realize(player_object_.Get(), SL_BOOLEAN_FALSE), false); 265 266 // Get an implicit player interface. 267 LOG_ON_FAILURE_AND_RETURN( 268 player_object_->GetInterface(player_object_.Get(), SL_IID_PLAY, &player_), 269 false); 270 271 // Get the simple buffer queue interface. 272 LOG_ON_FAILURE_AND_RETURN( 273 player_object_->GetInterface( 274 player_object_.Get(), SL_IID_BUFFERQUEUE, &simple_buffer_queue_), 275 false); 276 277 // Register the input callback for the simple buffer queue. 278 // This callback will be called when the soundcard needs data. 279 LOG_ON_FAILURE_AND_RETURN( 280 (*simple_buffer_queue_)->RegisterCallback( 281 simple_buffer_queue_, SimpleBufferQueueCallback, this), 282 false); 283 284 return true; 285 } 286 287 void OpenSLESOutputStream::SimpleBufferQueueCallback( 288 SLAndroidSimpleBufferQueueItf buffer_queue, 289 void* instance) { 290 OpenSLESOutputStream* stream = 291 reinterpret_cast<OpenSLESOutputStream*>(instance); 292 stream->FillBufferQueue(); 293 } 294 295 void OpenSLESOutputStream::FillBufferQueue() { 296 base::AutoLock lock(lock_); 297 if (!started_) 298 return; 299 300 TRACE_EVENT0("audio", "OpenSLESOutputStream::FillBufferQueue"); 301 302 // Verify that we are in a playing state. 303 SLuint32 state; 304 SLresult err = (*player_)->GetPlayState(player_, &state); 305 if (SL_RESULT_SUCCESS != err) { 306 HandleError(err); 307 return; 308 } 309 if (state != SL_PLAYSTATE_PLAYING) { 310 DLOG(WARNING) << "Received callback in non-playing state"; 311 return; 312 } 313 314 // Fill up one buffer in the queue by asking the registered source for 315 // data using the OnMoreData() callback. 316 FillBufferQueueNoLock(); 317 } 318 319 void OpenSLESOutputStream::FillBufferQueueNoLock() { 320 // Ensure that the calling thread has acquired the lock since it is not 321 // done in this method. 322 lock_.AssertAcquired(); 323 324 // Read data from the registered client source. 325 // TODO(henrika): Investigate if it is possible to get a more accurate 326 // delay estimation. 327 const uint32 hardware_delay = buffer_size_bytes_; 328 int frames_filled = callback_->OnMoreData( 329 audio_bus_.get(), AudioBuffersState(0, hardware_delay)); 330 if (frames_filled <= 0) { 331 // Audio source is shutting down, or halted on error. 332 return; 333 } 334 335 // Note: If the internal representation ever changes from 16-bit PCM to 336 // raw float, the data must be clipped and sanitized since it may come 337 // from an untrusted source such as NaCl. 338 audio_bus_->Scale(muted_ ? 0.0f : volume_); 339 audio_bus_->ToInterleaved(frames_filled, 340 format_.bitsPerSample / 8, 341 audio_data_[active_buffer_index_]); 342 343 const int num_filled_bytes = 344 frames_filled * audio_bus_->channels() * format_.bitsPerSample / 8; 345 DCHECK_LE(static_cast<size_t>(num_filled_bytes), buffer_size_bytes_); 346 347 // Enqueue the buffer for playback. 348 SLresult err = 349 (*simple_buffer_queue_)->Enqueue(simple_buffer_queue_, 350 audio_data_[active_buffer_index_], 351 num_filled_bytes); 352 if (SL_RESULT_SUCCESS != err) 353 HandleError(err); 354 355 active_buffer_index_ = (active_buffer_index_ + 1) % kMaxNumOfBuffersInQueue; 356 } 357 358 void OpenSLESOutputStream::SetupAudioBuffer() { 359 DCHECK(thread_checker_.CalledOnValidThread()); 360 DCHECK(!audio_data_[0]); 361 for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) { 362 audio_data_[i] = new uint8[buffer_size_bytes_]; 363 } 364 } 365 366 void OpenSLESOutputStream::ReleaseAudioBuffer() { 367 DCHECK(thread_checker_.CalledOnValidThread()); 368 if (audio_data_[0]) { 369 for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) { 370 delete[] audio_data_[i]; 371 audio_data_[i] = NULL; 372 } 373 } 374 } 375 376 void OpenSLESOutputStream::HandleError(SLresult error) { 377 DLOG(ERROR) << "OpenSLES Output error " << error; 378 if (callback_) 379 callback_->OnError(this); 380 } 381 382 } // namespace media 383