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 |