| 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/logging.h" | 7 #include "base/logging.h" |
| 8 #include "media/audio/audio_util.h" | 8 #include "media/audio/audio_util.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, ...) \ |
| 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 |
| 11 namespace media { | 20 namespace media { |
| 12 | 21 |
| 13 OpenSLESOutputStream::OpenSLESOutputStream(AudioManagerAndroid* manager, | 22 OpenSLESOutputStream::OpenSLESOutputStream(AudioManagerAndroid* manager, |
| 14 const AudioParameters& params) | 23 const AudioParameters& params) |
| 15 : audio_manager_(manager), | 24 : audio_manager_(manager), |
| 16 callback_(NULL), | 25 callback_(NULL), |
| 17 player_(NULL), | 26 player_(NULL), |
| 18 simple_buffer_queue_(NULL), | 27 simple_buffer_queue_(NULL), |
| 19 active_queue_(0), | 28 active_queue_(0), |
| 20 buffer_size_bytes_(0), | 29 buffer_size_bytes_(0), |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 // Enable the flags before streaming. | 80 // Enable the flags before streaming. |
| 72 callback_ = callback; | 81 callback_ = callback; |
| 73 active_queue_ = 0; | 82 active_queue_ = 0; |
| 74 started_ = true; | 83 started_ = true; |
| 75 | 84 |
| 76 // Avoid start-up glitches by filling up one buffer queue before starting | 85 // Avoid start-up glitches by filling up one buffer queue before starting |
| 77 // the stream. | 86 // the stream. |
| 78 FillBufferQueue(); | 87 FillBufferQueue(); |
| 79 | 88 |
| 80 // Start streaming data by setting the play state to |SL_PLAYSTATE_PLAYING|. | 89 // Start streaming data by setting the play state to |SL_PLAYSTATE_PLAYING|. |
| 81 SLresult err = (*player_)->SetPlayState(player_, SL_PLAYSTATE_PLAYING); | 90 LOG_ON_FAILURE_AND_RETURN( |
| 82 DCHECK_EQ(SL_RESULT_SUCCESS, err); | 91 (*player_)->SetPlayState(player_, SL_PLAYSTATE_PLAYING)); |
| 83 if (SL_RESULT_SUCCESS != err) { | |
| 84 DLOG(WARNING) << "SetPlayState() failed to start playing"; | |
| 85 } | |
| 86 } | 92 } |
| 87 | 93 |
| 88 void OpenSLESOutputStream::Stop() { | 94 void OpenSLESOutputStream::Stop() { |
| 89 if (!started_) | 95 if (!started_) |
| 90 return; | 96 return; |
| 91 | 97 |
| 92 started_ = false; | 98 started_ = false; |
| 93 // Stop playing by setting the play state to |SL_PLAYSTATE_STOPPED|. | 99 // Stop playing by setting the play state to |SL_PLAYSTATE_STOPPED|. |
| 94 SLresult err = (*player_)->SetPlayState(player_, SL_PLAYSTATE_STOPPED); | 100 LOG_ON_FAILURE_AND_RETURN( |
| 95 if (SL_RESULT_SUCCESS != err) { | 101 (*player_)->SetPlayState(player_, SL_PLAYSTATE_STOPPED)); |
| 96 DLOG(WARNING) << "SetPlayState() failed to set the state to stop"; | |
| 97 } | |
| 98 | 102 |
| 99 // Clear the buffer queue so that the old data won't be played when | 103 // Clear the buffer queue so that the old data won't be played when |
| 100 // resuming playing. | 104 // resuming playing. |
| 101 err = (*simple_buffer_queue_)->Clear(simple_buffer_queue_); | 105 LOG_ON_FAILURE_AND_RETURN( |
| 102 if (SL_RESULT_SUCCESS != err) { | 106 (*simple_buffer_queue_)->Clear(simple_buffer_queue_)); |
| 103 DLOG(WARNING) << "Clear() failed to clear the buffer queue"; | |
| 104 } | |
| 105 } | 107 } |
| 106 | 108 |
| 107 void OpenSLESOutputStream::Close() { | 109 void OpenSLESOutputStream::Close() { |
| 108 // Stop the stream if it is still playing. | 110 // Stop the stream if it is still playing. |
| 109 Stop(); | 111 Stop(); |
| 110 | 112 |
| 111 // Explicitly free the player objects and invalidate their associated | 113 // Explicitly free the player objects and invalidate their associated |
| 112 // interfaces. They have to be done in the correct order. | 114 // interfaces. They have to be done in the correct order. |
| 113 output_mixer_.Reset(); | 115 output_mixer_.Reset(); |
| 114 player_object_.Reset(); | 116 player_object_.Reset(); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 132 void OpenSLESOutputStream::GetVolume(double* volume) { | 134 void OpenSLESOutputStream::GetVolume(double* volume) { |
| 133 *volume = static_cast<double>(volume_); | 135 *volume = static_cast<double>(volume_); |
| 134 } | 136 } |
| 135 | 137 |
| 136 bool OpenSLESOutputStream::CreatePlayer() { | 138 bool OpenSLESOutputStream::CreatePlayer() { |
| 137 // Initializes the engine object with specific option. After working with the | 139 // Initializes the engine object with specific option. After working with the |
| 138 // object, we need to free the object and its resources. | 140 // object, we need to free the object and its resources. |
| 139 SLEngineOption option[] = { | 141 SLEngineOption option[] = { |
| 140 { SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE) } | 142 { SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE) } |
| 141 }; | 143 }; |
| 142 SLresult err = slCreateEngine(engine_object_.Receive(), 1, option, 0, | 144 LOG_ON_FAILURE_AND_RETURN( |
| 143 NULL, NULL); | 145 slCreateEngine(engine_object_.Receive(), 1, option, 0, NULL, NULL), |
| 144 DCHECK_EQ(SL_RESULT_SUCCESS, err); | 146 false); |
| 145 if (SL_RESULT_SUCCESS != err) | |
| 146 return false; | |
| 147 | 147 |
| 148 // Realize the SL engine object in synchronous mode. | 148 // Realize the SL engine object in synchronous mode. |
| 149 err = engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE); | 149 LOG_ON_FAILURE_AND_RETURN( |
| 150 DCHECK_EQ(SL_RESULT_SUCCESS, err); | 150 engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE), |
| 151 if (SL_RESULT_SUCCESS != err) | 151 false); |
| 152 return false; | |
| 153 | 152 |
| 154 // Get the SL engine interface which is implicit. | 153 // Get the SL engine interface which is implicit. |
| 155 SLEngineItf engine; | 154 SLEngineItf engine; |
| 156 err = engine_object_->GetInterface(engine_object_.Get(), | 155 LOG_ON_FAILURE_AND_RETURN( |
| 157 SL_IID_ENGINE, | 156 engine_object_->GetInterface(engine_object_.Get(), |
| 158 &engine); | 157 SL_IID_ENGINE, |
| 159 DCHECK_EQ(SL_RESULT_SUCCESS, err); | 158 &engine), |
| 160 if (SL_RESULT_SUCCESS != err) | 159 false); |
| 161 return false; | |
| 162 | 160 |
| 163 // Create ouput mixer object to be used by the player. | 161 // Create ouput mixer object to be used by the player. |
| 164 // TODO(xians): Do we need the environmental reverb auxiliary effect? | 162 LOG_ON_FAILURE_AND_RETURN( |
| 165 err = (*engine)->CreateOutputMix(engine, | 163 (*engine)->CreateOutputMix(engine, |
| 166 output_mixer_.Receive(), | 164 output_mixer_.Receive(), |
| 167 0, | 165 0, |
| 168 NULL, | 166 NULL, |
| 169 NULL); | 167 NULL), |
| 170 DCHECK_EQ(SL_RESULT_SUCCESS, err); | 168 false); |
| 171 if (SL_RESULT_SUCCESS != err) | |
| 172 return false; | |
| 173 | 169 |
| 174 // Realizing the output mix object in synchronous mode. | 170 // Realizing the output mix object in synchronous mode. |
| 175 err = output_mixer_->Realize(output_mixer_.Get(), SL_BOOLEAN_FALSE); | 171 LOG_ON_FAILURE_AND_RETURN( |
| 176 DCHECK_EQ(SL_RESULT_SUCCESS, err); | 172 output_mixer_->Realize(output_mixer_.Get(), SL_BOOLEAN_FALSE), |
| 177 if (SL_RESULT_SUCCESS != err) | 173 false); |
| 178 return false; | |
| 179 | 174 |
| 180 // Audio source configuration. | 175 // Audio source configuration. |
| 181 SLDataLocator_AndroidSimpleBufferQueue simple_buffer_queue = { | 176 SLDataLocator_AndroidSimpleBufferQueue simple_buffer_queue = { |
| 182 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, | 177 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, |
| 183 static_cast<SLuint32>(kNumOfQueuesInBuffer) | 178 static_cast<SLuint32>(kNumOfQueuesInBuffer) |
| 184 }; | 179 }; |
| 185 SLDataSource audio_source = { &simple_buffer_queue, &format_ }; | 180 SLDataSource audio_source = { &simple_buffer_queue, &format_ }; |
| 186 | 181 |
| 187 // Audio sink configuration. | 182 // Audio sink configuration. |
| 188 SLDataLocator_OutputMix locator_output_mix = { | 183 SLDataLocator_OutputMix locator_output_mix = { |
| 189 SL_DATALOCATOR_OUTPUTMIX, output_mixer_.Get() | 184 SL_DATALOCATOR_OUTPUTMIX, output_mixer_.Get() |
| 190 }; | 185 }; |
| 191 SLDataSink audio_sink = { &locator_output_mix, NULL }; | 186 SLDataSink audio_sink = { &locator_output_mix, NULL }; |
| 192 | 187 |
| 193 // Create an audio player. | 188 // Create an audio player. |
| 194 const SLuint32 number_of_interfaces = 1; | 189 const SLInterfaceID interface_id[] = { |
| 195 const SLInterfaceID interface_id[number_of_interfaces] = { | 190 SL_IID_BUFFERQUEUE, |
| 196 SL_IID_BUFFERQUEUE | 191 SL_IID_VOLUME, |
| 192 SL_IID_ANDROIDCONFIGURATION |
| 197 }; | 193 }; |
| 198 const SLboolean interface_required[number_of_interfaces] = { | 194 const SLboolean interface_required[] = { |
| 195 SL_BOOLEAN_TRUE, |
| 196 SL_BOOLEAN_TRUE, |
| 199 SL_BOOLEAN_TRUE | 197 SL_BOOLEAN_TRUE |
| 200 }; | 198 }; |
| 201 err = (*engine)->CreateAudioPlayer(engine, | 199 LOG_ON_FAILURE_AND_RETURN( |
| 202 player_object_.Receive(), | 200 (*engine)->CreateAudioPlayer(engine, |
| 203 &audio_source, | 201 player_object_.Receive(), |
| 204 &audio_sink, | 202 &audio_source, |
| 205 number_of_interfaces, | 203 &audio_sink, |
| 206 interface_id, | 204 arraysize(interface_id), |
| 207 interface_required); | 205 interface_id, |
| 208 DCHECK_EQ(SL_RESULT_SUCCESS, err); | 206 interface_required), |
| 209 if (SL_RESULT_SUCCESS != err) { | 207 false); |
| 210 DLOG(ERROR) << "CreateAudioPlayer() failed with error code " << err; | 208 |
| 211 return false; | 209 // Create AudioPlayer and specify SL_IID_ANDROIDCONFIGURATION. |
| 212 } | 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); |
| 213 | 223 |
| 214 // Realize the player object in synchronous mode. | 224 // Realize the player object in synchronous mode. |
| 215 err = player_object_->Realize(player_object_.Get(), SL_BOOLEAN_FALSE); | 225 LOG_ON_FAILURE_AND_RETURN( |
| 216 DCHECK_EQ(SL_RESULT_SUCCESS, err); | 226 player_object_->Realize(player_object_.Get(), SL_BOOLEAN_FALSE), |
| 217 if (SL_RESULT_SUCCESS != err) { | 227 false); |
| 218 DLOG(ERROR) << "Player Realize() failed with error code " << err; | |
| 219 return false; | |
| 220 } | |
| 221 | 228 |
| 222 // Get an implicit player interface. | 229 // Get an implicit player interface. |
| 223 err = player_object_->GetInterface( | 230 LOG_ON_FAILURE_AND_RETURN( |
| 224 player_object_.Get(), SL_IID_PLAY, &player_); | 231 player_object_->GetInterface(player_object_.Get(), SL_IID_PLAY, &player_), |
| 225 DCHECK_EQ(SL_RESULT_SUCCESS, err); | 232 false); |
| 226 if (SL_RESULT_SUCCESS != err) | |
| 227 return false; | |
| 228 | 233 |
| 229 // Get the simple buffer queue interface. | 234 // Get the simple buffer queue interface. |
| 230 err = player_object_->GetInterface(player_object_.Get(), | 235 LOG_ON_FAILURE_AND_RETURN( |
| 231 SL_IID_BUFFERQUEUE, | 236 player_object_->GetInterface(player_object_.Get(), |
| 232 &simple_buffer_queue_); | 237 SL_IID_BUFFERQUEUE, |
| 233 DCHECK_EQ(SL_RESULT_SUCCESS, err); | 238 &simple_buffer_queue_), |
| 234 if (SL_RESULT_SUCCESS != err) | 239 false); |
| 235 return false; | |
| 236 | 240 |
| 237 // Register the input callback for the simple buffer queue. | 241 // Register the input callback for the simple buffer queue. |
| 238 // This callback will be called when the soundcard needs data. | 242 // This callback will be called when the soundcard needs data. |
| 239 err = (*simple_buffer_queue_)->RegisterCallback(simple_buffer_queue_, | 243 LOG_ON_FAILURE_AND_RETURN( |
| 240 SimpleBufferQueueCallback, | 244 (*simple_buffer_queue_)->RegisterCallback(simple_buffer_queue_, |
| 241 this); | 245 SimpleBufferQueueCallback, |
| 242 DCHECK_EQ(SL_RESULT_SUCCESS, err); | 246 this), |
| 247 false); |
| 243 | 248 |
| 244 return (SL_RESULT_SUCCESS == err); | 249 return true; |
| 245 } | 250 } |
| 246 | 251 |
| 247 void OpenSLESOutputStream::SimpleBufferQueueCallback( | 252 void OpenSLESOutputStream::SimpleBufferQueueCallback( |
| 248 SLAndroidSimpleBufferQueueItf buffer_queue, void* instance) { | 253 SLAndroidSimpleBufferQueueItf buffer_queue, void* instance) { |
| 249 OpenSLESOutputStream* stream = | 254 OpenSLESOutputStream* stream = |
| 250 reinterpret_cast<OpenSLESOutputStream*>(instance); | 255 reinterpret_cast<OpenSLESOutputStream*>(instance); |
| 251 stream->FillBufferQueue(); | 256 stream->FillBufferQueue(); |
| 252 } | 257 } |
| 253 | 258 |
| 254 void OpenSLESOutputStream::FillBufferQueue() { | 259 void OpenSLESOutputStream::FillBufferQueue() { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 298 void OpenSLESOutputStream::ReleaseAudioBuffer() { | 303 void OpenSLESOutputStream::ReleaseAudioBuffer() { |
| 299 if (audio_data_[0]) { | 304 if (audio_data_[0]) { |
| 300 for (int i = 0; i < kNumOfQueuesInBuffer; ++i) { | 305 for (int i = 0; i < kNumOfQueuesInBuffer; ++i) { |
| 301 delete [] audio_data_[i]; | 306 delete [] audio_data_[i]; |
| 302 audio_data_[i] = NULL; | 307 audio_data_[i] = NULL; |
| 303 } | 308 } |
| 304 } | 309 } |
| 305 } | 310 } |
| 306 | 311 |
| 307 void OpenSLESOutputStream::HandleError(SLresult error) { | 312 void OpenSLESOutputStream::HandleError(SLresult error) { |
| 308 DLOG(ERROR) << "OpenSLES error " << error; | 313 DLOG(ERROR) << "OpenSLES Output error " << error; |
| 309 if (callback_) | 314 if (callback_) |
| 310 callback_->OnError(this, error); | 315 callback_->OnError(this, error); |
| 311 } | 316 } |
| 312 | 317 |
| 313 } // namespace media | 318 } // namespace media |
| OLD | NEW |