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 |