| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/audio/android/opensles_output.h" | 5 #include "media/audio/android/opensles_output.h" |
| 6 | 6 |
| 7 #include "base/debug/trace_event.h" | 7 #include "base/debug/trace_event.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "media/audio/android/audio_manager_android.h" | 9 #include "media/audio/android/audio_manager_android.h" |
| 10 | 10 |
| 11 #define LOG_ON_FAILURE_AND_RETURN(op, ...) \ | 11 #define LOG_ON_FAILURE_AND_RETURN(op, ...) \ |
| 12 do { \ | 12 do { \ |
| 13 SLresult err = (op); \ | 13 SLresult err = (op); \ |
| 14 if (err != SL_RESULT_SUCCESS) { \ | 14 if (err != SL_RESULT_SUCCESS) { \ |
| 15 DLOG(ERROR) << #op << " failed: " << err; \ | 15 DLOG(ERROR) << #op << " failed: " << err; \ |
| 16 return __VA_ARGS__; \ | 16 return __VA_ARGS__; \ |
| 17 } \ | 17 } \ |
| 18 } while (0) | 18 } while (0) |
| 19 | 19 |
| 20 namespace media { | 20 namespace media { |
| 21 | 21 |
| 22 OpenSLESOutputStream::OpenSLESOutputStream(AudioManagerAndroid* manager, | 22 OpenSLESOutputStream::OpenSLESOutputStream(AudioManagerAndroid* manager, |
| 23 const AudioParameters& params) | 23 const AudioParameters& params) |
| 24 : audio_manager_(manager), | 24 : audio_manager_(manager), |
| 25 callback_(NULL), | 25 callback_(NULL), |
| 26 player_(NULL), | 26 player_(NULL), |
| 27 simple_buffer_queue_(NULL), | 27 simple_buffer_queue_(NULL), |
| 28 active_queue_(0), | 28 active_buffer_(0), |
| 29 buffer_size_bytes_(0), | 29 buffer_size_bytes_(0), |
| 30 started_(false), | 30 started_(false), |
| 31 volume_(1.0) { | 31 volume_(1.0) { |
| 32 DVLOG(2) << "OpenSLESOutputStream::OpenSLESOutputStream()"; |
| 32 format_.formatType = SL_DATAFORMAT_PCM; | 33 format_.formatType = SL_DATAFORMAT_PCM; |
| 33 format_.numChannels = static_cast<SLuint32>(params.channels()); | 34 format_.numChannels = static_cast<SLuint32>(params.channels()); |
| 34 // Provides sampling rate in milliHertz to OpenSLES. | 35 // Provides sampling rate in milliHertz to OpenSLES. |
| 35 format_.samplesPerSec = static_cast<SLuint32>(params.sample_rate() * 1000); | 36 format_.samplesPerSec = static_cast<SLuint32>(params.sample_rate() * 1000); |
| 36 format_.bitsPerSample = params.bits_per_sample(); | 37 format_.bitsPerSample = params.bits_per_sample(); |
| 37 format_.containerSize = params.bits_per_sample(); | 38 format_.containerSize = params.bits_per_sample(); |
| 38 format_.endianness = SL_BYTEORDER_LITTLEENDIAN; | 39 format_.endianness = SL_BYTEORDER_LITTLEENDIAN; |
| 39 if (format_.numChannels == 1) | 40 if (format_.numChannels == 1) |
| 40 format_.channelMask = SL_SPEAKER_FRONT_CENTER; | 41 format_.channelMask = SL_SPEAKER_FRONT_CENTER; |
| 41 else if (format_.numChannels == 2) | 42 else if (format_.numChannels == 2) |
| 42 format_.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; | 43 format_.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; |
| 43 else | 44 else |
| 44 NOTREACHED() << "Unsupported number of channels: " << format_.numChannels; | 45 NOTREACHED() << "Unsupported number of channels: " << format_.numChannels; |
| 45 | 46 |
| 46 buffer_size_bytes_ = params.GetBytesPerBuffer(); | 47 buffer_size_bytes_ = params.GetBytesPerBuffer(); |
| 47 audio_bus_ = AudioBus::Create(params); | 48 audio_bus_ = AudioBus::Create(params); |
| 48 | 49 |
| 49 memset(&audio_data_, 0, sizeof(audio_data_)); | 50 memset(&audio_data_, 0, sizeof(audio_data_)); |
| 50 } | 51 } |
| 51 | 52 |
| 52 OpenSLESOutputStream::~OpenSLESOutputStream() { | 53 OpenSLESOutputStream::~OpenSLESOutputStream() { |
| 54 DVLOG(2) << "OpenSLESOutputStream::~OpenSLESOutputStream()"; |
| 55 DCHECK(thread_checker_.CalledOnValidThread()); |
| 53 DCHECK(!engine_object_.Get()); | 56 DCHECK(!engine_object_.Get()); |
| 54 DCHECK(!player_object_.Get()); | 57 DCHECK(!player_object_.Get()); |
| 55 DCHECK(!output_mixer_.Get()); | 58 DCHECK(!output_mixer_.Get()); |
| 56 DCHECK(!player_); | 59 DCHECK(!player_); |
| 57 DCHECK(!simple_buffer_queue_); | 60 DCHECK(!simple_buffer_queue_); |
| 58 DCHECK(!audio_data_[0]); | 61 DCHECK(!audio_data_[0]); |
| 59 } | 62 } |
| 60 | 63 |
| 61 bool OpenSLESOutputStream::Open() { | 64 bool OpenSLESOutputStream::Open() { |
| 65 DVLOG(2) << "OpenSLESOutputStream::Open()"; |
| 66 DCHECK(thread_checker_.CalledOnValidThread()); |
| 62 if (engine_object_.Get()) | 67 if (engine_object_.Get()) |
| 63 return false; | 68 return false; |
| 64 | 69 |
| 65 if (!CreatePlayer()) | 70 if (!CreatePlayer()) |
| 66 return false; | 71 return false; |
| 67 | 72 |
| 68 SetupAudioBuffer(); | 73 SetupAudioBuffer(); |
| 74 active_buffer_ = 0; |
| 69 | 75 |
| 70 return true; | 76 return true; |
| 71 } | 77 } |
| 72 | 78 |
| 73 void OpenSLESOutputStream::Start(AudioSourceCallback* callback) { | 79 void OpenSLESOutputStream::Start(AudioSourceCallback* callback) { |
| 80 DVLOG(2) << "OpenSLESOutputStream::Start()"; |
| 81 DCHECK(thread_checker_.CalledOnValidThread()); |
| 74 DCHECK(callback); | 82 DCHECK(callback); |
| 75 DCHECK(player_); | 83 DCHECK(player_); |
| 76 DCHECK(simple_buffer_queue_); | 84 DCHECK(simple_buffer_queue_); |
| 77 if (started_) | 85 if (started_) |
| 78 return; | 86 return; |
| 79 | 87 |
| 80 // Enable the flags before streaming. | 88 base::AutoLock lock(lock_); |
| 89 DCHECK(callback_ == NULL || callback_ == callback); |
| 81 callback_ = callback; | 90 callback_ = callback; |
| 82 active_queue_ = 0; | |
| 83 started_ = true; | |
| 84 | 91 |
| 85 // Avoid start-up glitches by filling up one buffer queue before starting | 92 // Avoid start-up glitches by filling up one buffer queue before starting |
| 86 // the stream. | 93 // the stream. |
| 87 FillBufferQueue(); | 94 FillBufferQueueNoLock(); |
| 88 | 95 |
| 89 // Start streaming data by setting the play state to |SL_PLAYSTATE_PLAYING|. | 96 // Start streaming data by setting the play state to SL_PLAYSTATE_PLAYING. |
| 97 // For a player object, when the object is in the SL_PLAYSTATE_PLAYING |
| 98 // state, adding buffers will implicitly start playback. |
| 90 LOG_ON_FAILURE_AND_RETURN( | 99 LOG_ON_FAILURE_AND_RETURN( |
| 91 (*player_)->SetPlayState(player_, SL_PLAYSTATE_PLAYING)); | 100 (*player_)->SetPlayState(player_, SL_PLAYSTATE_PLAYING)); |
| 101 |
| 102 started_ = true; |
| 92 } | 103 } |
| 93 | 104 |
| 94 void OpenSLESOutputStream::Stop() { | 105 void OpenSLESOutputStream::Stop() { |
| 106 DVLOG(2) << "OpenSLESOutputStream::Stop()"; |
| 107 DCHECK(thread_checker_.CalledOnValidThread()); |
| 95 if (!started_) | 108 if (!started_) |
| 96 return; | 109 return; |
| 97 | 110 |
| 98 started_ = false; | 111 base::AutoLock lock(lock_); |
| 99 // Stop playing by setting the play state to |SL_PLAYSTATE_STOPPED|. | 112 |
| 113 // Stop playing by setting the play state to SL_PLAYSTATE_STOPPED. |
| 100 LOG_ON_FAILURE_AND_RETURN( | 114 LOG_ON_FAILURE_AND_RETURN( |
| 101 (*player_)->SetPlayState(player_, SL_PLAYSTATE_STOPPED)); | 115 (*player_)->SetPlayState(player_, SL_PLAYSTATE_STOPPED)); |
| 102 | 116 |
| 103 // Clear the buffer queue so that the old data won't be played when | 117 // Clear the buffer queue so that the old data won't be played when |
| 104 // resuming playing. | 118 // resuming playing. |
| 105 LOG_ON_FAILURE_AND_RETURN( | 119 LOG_ON_FAILURE_AND_RETURN( |
| 106 (*simple_buffer_queue_)->Clear(simple_buffer_queue_)); | 120 (*simple_buffer_queue_)->Clear(simple_buffer_queue_)); |
| 121 |
| 122 #ifndef NDEBUG |
| 123 // Verify that the buffer queue is in fact cleared as it should. |
| 124 SLAndroidSimpleBufferQueueState buffer_queue_state; |
| 125 LOG_ON_FAILURE_AND_RETURN( |
| 126 (*simple_buffer_queue_)->GetState(simple_buffer_queue_, |
| 127 &buffer_queue_state)); |
| 128 DCHECK_EQ(0u, buffer_queue_state.count); |
| 129 DCHECK_EQ(0u, buffer_queue_state.index); |
| 130 #endif |
| 131 |
| 132 started_ = false; |
| 107 } | 133 } |
| 108 | 134 |
| 109 void OpenSLESOutputStream::Close() { | 135 void OpenSLESOutputStream::Close() { |
| 136 DVLOG(2) << "OpenSLESOutputStream::Close()"; |
| 137 DCHECK(thread_checker_.CalledOnValidThread()); |
| 138 |
| 110 // Stop the stream if it is still playing. | 139 // Stop the stream if it is still playing. |
| 111 Stop(); | 140 Stop(); |
| 141 { |
| 142 // Destroy the buffer queue player object and invalidate all associated |
| 143 // interfaces. |
| 144 player_object_.Reset(); |
| 145 simple_buffer_queue_ = NULL; |
| 146 player_ = NULL; |
| 112 | 147 |
| 113 // Explicitly free the player objects and invalidate their associated | 148 // Destroy the mixer object. We don't store any associated interface for |
| 114 // interfaces. They have to be done in the correct order. | 149 // this object. |
| 115 player_object_.Reset(); | 150 output_mixer_.Reset(); |
| 116 output_mixer_.Reset(); | |
| 117 engine_object_.Reset(); | |
| 118 simple_buffer_queue_ = NULL; | |
| 119 player_ = NULL; | |
| 120 | 151 |
| 121 ReleaseAudioBuffer(); | 152 // Destroy the engine object. We don't store any associated interface for |
| 153 // this object. |
| 154 engine_object_.Reset(); |
| 155 ReleaseAudioBuffer(); |
| 156 } |
| 122 | 157 |
| 123 audio_manager_->ReleaseOutputStream(this); | 158 audio_manager_->ReleaseOutputStream(this); |
| 124 } | 159 } |
| 125 | 160 |
| 126 void OpenSLESOutputStream::SetVolume(double volume) { | 161 void OpenSLESOutputStream::SetVolume(double volume) { |
| 162 DVLOG(2) << "OpenSLESOutputStream::SetVolume(" << volume << ")"; |
| 163 DCHECK(thread_checker_.CalledOnValidThread()); |
| 127 float volume_float = static_cast<float>(volume); | 164 float volume_float = static_cast<float>(volume); |
| 128 if (volume_float < 0.0f || volume_float > 1.0f) { | 165 if (volume_float < 0.0f || volume_float > 1.0f) { |
| 129 return; | 166 return; |
| 130 } | 167 } |
| 131 volume_ = volume_float; | 168 volume_ = volume_float; |
| 132 } | 169 } |
| 133 | 170 |
| 134 void OpenSLESOutputStream::GetVolume(double* volume) { | 171 void OpenSLESOutputStream::GetVolume(double* volume) { |
| 172 DCHECK(thread_checker_.CalledOnValidThread()); |
| 135 *volume = static_cast<double>(volume_); | 173 *volume = static_cast<double>(volume_); |
| 136 } | 174 } |
| 137 | 175 |
| 138 bool OpenSLESOutputStream::CreatePlayer() { | 176 bool OpenSLESOutputStream::CreatePlayer() { |
| 177 DCHECK(thread_checker_.CalledOnValidThread()); |
| 178 DCHECK(!engine_object_.Get()); |
| 179 DCHECK(!player_object_.Get()); |
| 180 DCHECK(!output_mixer_.Get()); |
| 181 DCHECK(!player_); |
| 182 DCHECK(!simple_buffer_queue_); |
| 183 |
| 139 // Initializes the engine object with specific option. After working with the | 184 // Initializes the engine object with specific option. After working with the |
| 140 // object, we need to free the object and its resources. | 185 // object, we need to free the object and its resources. |
| 141 SLEngineOption option[] = { | 186 SLEngineOption option[] = { |
| 142 { SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE) } | 187 { SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE) } |
| 143 }; | 188 }; |
| 144 LOG_ON_FAILURE_AND_RETURN( | 189 LOG_ON_FAILURE_AND_RETURN( |
| 145 slCreateEngine(engine_object_.Receive(), 1, option, 0, NULL, NULL), | 190 slCreateEngine(engine_object_.Receive(), 1, option, 0, NULL, NULL), |
| 146 false); | 191 false); |
| 147 | 192 |
| 148 // Realize the SL engine object in synchronous mode. | 193 // Realize the SL engine object in synchronous mode. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 168 false); | 213 false); |
| 169 | 214 |
| 170 // Realizing the output mix object in synchronous mode. | 215 // Realizing the output mix object in synchronous mode. |
| 171 LOG_ON_FAILURE_AND_RETURN( | 216 LOG_ON_FAILURE_AND_RETURN( |
| 172 output_mixer_->Realize(output_mixer_.Get(), SL_BOOLEAN_FALSE), | 217 output_mixer_->Realize(output_mixer_.Get(), SL_BOOLEAN_FALSE), |
| 173 false); | 218 false); |
| 174 | 219 |
| 175 // Audio source configuration. | 220 // Audio source configuration. |
| 176 SLDataLocator_AndroidSimpleBufferQueue simple_buffer_queue = { | 221 SLDataLocator_AndroidSimpleBufferQueue simple_buffer_queue = { |
| 177 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, | 222 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, |
| 178 static_cast<SLuint32>(kNumOfQueuesInBuffer) | 223 static_cast<SLuint32>(kMaxNumOfBuffersInQueue) |
| 179 }; | 224 }; |
| 180 SLDataSource audio_source = { &simple_buffer_queue, &format_ }; | 225 SLDataSource audio_source = { &simple_buffer_queue, &format_ }; |
| 181 | 226 |
| 182 // Audio sink configuration. | 227 // Audio sink configuration. |
| 183 SLDataLocator_OutputMix locator_output_mix = { | 228 SLDataLocator_OutputMix locator_output_mix = { |
| 184 SL_DATALOCATOR_OUTPUTMIX, output_mixer_.Get() | 229 SL_DATALOCATOR_OUTPUTMIX, output_mixer_.Get() |
| 185 }; | 230 }; |
| 186 SLDataSink audio_sink = { &locator_output_mix, NULL }; | 231 SLDataSink audio_sink = { &locator_output_mix, NULL }; |
| 187 | 232 |
| 188 // Create an audio player. | 233 // Create an audio player. |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 250 } | 295 } |
| 251 | 296 |
| 252 void OpenSLESOutputStream::SimpleBufferQueueCallback( | 297 void OpenSLESOutputStream::SimpleBufferQueueCallback( |
| 253 SLAndroidSimpleBufferQueueItf buffer_queue, void* instance) { | 298 SLAndroidSimpleBufferQueueItf buffer_queue, void* instance) { |
| 254 OpenSLESOutputStream* stream = | 299 OpenSLESOutputStream* stream = |
| 255 reinterpret_cast<OpenSLESOutputStream*>(instance); | 300 reinterpret_cast<OpenSLESOutputStream*>(instance); |
| 256 stream->FillBufferQueue(); | 301 stream->FillBufferQueue(); |
| 257 } | 302 } |
| 258 | 303 |
| 259 void OpenSLESOutputStream::FillBufferQueue() { | 304 void OpenSLESOutputStream::FillBufferQueue() { |
| 260 if (!started_) | 305 base::AutoLock lock(lock_); |
| 306 if (!player_) |
| 261 return; | 307 return; |
| 262 | 308 |
| 263 TRACE_EVENT0("audio", "OpenSLESOutputStream::FillBufferQueue"); | 309 TRACE_EVENT0("audio", "OpenSLESOutputStream::FillBufferQueue"); |
| 310 |
| 311 // Verify that we are in a playing state. |
| 312 SLuint32 state; |
| 313 SLresult err = (*player_)->GetPlayState(player_, &state); |
| 314 if (SL_RESULT_SUCCESS != err) { |
| 315 HandleError(err); |
| 316 return; |
| 317 } |
| 318 if (state != SL_PLAYSTATE_PLAYING) { |
| 319 DLOG(WARNING) << "Received callback in non-playing state"; |
| 320 return; |
| 321 } |
| 322 |
| 323 // Fill up one buffer in the queue by asking the registered source for |
| 324 // data using the OnMoreData() callback. |
| 325 FillBufferQueueNoLock(); |
| 326 } |
| 327 |
| 328 void OpenSLESOutputStream::FillBufferQueueNoLock() { |
| 329 // Ensure that the calling thread has acquired the lock since it is not |
| 330 // done in this method. |
| 331 lock_.AssertAcquired(); |
| 332 |
| 264 // Read data from the registered client source. | 333 // Read data from the registered client source. |
| 265 // TODO(xians): Get an accurate delay estimation. | 334 // TODO(henrika): Investigate if it is possible to get a more accurate |
| 266 uint32 hardware_delay = buffer_size_bytes_; | 335 // delay estimation. |
| 336 const uint32 hardware_delay = buffer_size_bytes_; |
| 267 int frames_filled = callback_->OnMoreData( | 337 int frames_filled = callback_->OnMoreData( |
| 268 audio_bus_.get(), AudioBuffersState(0, hardware_delay)); | 338 audio_bus_.get(), AudioBuffersState(0, hardware_delay)); |
| 269 if (frames_filled <= 0) | 339 if (frames_filled <= 0) { |
| 270 return; // Audio source is shutting down, or halted on error. | 340 // Audio source is shutting down, or halted on error. |
| 271 int num_filled_bytes = | 341 return; |
| 342 } |
| 343 |
| 344 // Note: If the internal representation ever changes from 16-bit PCM to |
| 345 // raw float, the data must be clipped and sanitized since it may come |
| 346 // from an untrusted source such as NaCl. |
| 347 audio_bus_->Scale(volume_); |
| 348 audio_bus_->ToInterleaved( |
| 349 frames_filled, format_.bitsPerSample / 8, audio_data_[active_buffer_]); |
| 350 |
| 351 const int num_filled_bytes = |
| 272 frames_filled * audio_bus_->channels() * format_.bitsPerSample / 8; | 352 frames_filled * audio_bus_->channels() * format_.bitsPerSample / 8; |
| 273 DCHECK_LE(static_cast<size_t>(num_filled_bytes), buffer_size_bytes_); | 353 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 | 354 |
| 280 // Enqueue the buffer for playback. | 355 // Enqueue the buffer for playback. |
| 281 SLresult err = (*simple_buffer_queue_)->Enqueue( | 356 SLresult err = (*simple_buffer_queue_)->Enqueue( |
| 282 simple_buffer_queue_, | 357 simple_buffer_queue_, |
| 283 audio_data_[active_queue_], | 358 audio_data_[active_buffer_], |
| 284 num_filled_bytes); | 359 num_filled_bytes); |
| 285 if (SL_RESULT_SUCCESS != err) | 360 if (SL_RESULT_SUCCESS != err) |
| 286 HandleError(err); | 361 HandleError(err); |
| 287 | 362 |
| 288 active_queue_ = (active_queue_ + 1) % kNumOfQueuesInBuffer; | 363 active_buffer_ = (active_buffer_ + 1) % kMaxNumOfBuffersInQueue; |
| 289 } | 364 } |
| 290 | 365 |
| 291 void OpenSLESOutputStream::SetupAudioBuffer() { | 366 void OpenSLESOutputStream::SetupAudioBuffer() { |
| 367 DCHECK(thread_checker_.CalledOnValidThread()); |
| 292 DCHECK(!audio_data_[0]); | 368 DCHECK(!audio_data_[0]); |
| 293 for (int i = 0; i < kNumOfQueuesInBuffer; ++i) { | 369 for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) { |
| 294 audio_data_[i] = new uint8[buffer_size_bytes_]; | 370 audio_data_[i] = new uint8[buffer_size_bytes_]; |
| 295 } | 371 } |
| 296 } | 372 } |
| 297 | 373 |
| 298 void OpenSLESOutputStream::ReleaseAudioBuffer() { | 374 void OpenSLESOutputStream::ReleaseAudioBuffer() { |
| 375 DCHECK(thread_checker_.CalledOnValidThread()); |
| 299 if (audio_data_[0]) { | 376 if (audio_data_[0]) { |
| 300 for (int i = 0; i < kNumOfQueuesInBuffer; ++i) { | 377 for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) { |
| 301 delete [] audio_data_[i]; | 378 delete [] audio_data_[i]; |
| 302 audio_data_[i] = NULL; | 379 audio_data_[i] = NULL; |
| 303 } | 380 } |
| 304 } | 381 } |
| 305 } | 382 } |
| 306 | 383 |
| 307 void OpenSLESOutputStream::HandleError(SLresult error) { | 384 void OpenSLESOutputStream::HandleError(SLresult error) { |
| 308 DLOG(ERROR) << "OpenSLES Output error " << error; | 385 DLOG(ERROR) << "OpenSLES Output error " << error; |
| 309 if (callback_) | 386 if (callback_) |
| 310 callback_->OnError(this); | 387 callback_->OnError(this); |
| 311 } | 388 } |
| 312 | 389 |
| 313 } // namespace media | 390 } // namespace media |
| OLD | NEW |