Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(199)

Side by Side Diff: media/audio/android/opensles_output.cc

Issue 23296008: Adding audio unit tests for Android (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: fixed includes Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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_index_(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_index_ = 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
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
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,
350 audio_data_[active_buffer_index_]);
351
352 const int num_filled_bytes =
272 frames_filled * audio_bus_->channels() * format_.bitsPerSample / 8; 353 frames_filled * audio_bus_->channels() * format_.bitsPerSample / 8;
273 DCHECK_LE(static_cast<size_t>(num_filled_bytes), buffer_size_bytes_); 354 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 355
280 // Enqueue the buffer for playback. 356 // Enqueue the buffer for playback.
281 SLresult err = (*simple_buffer_queue_)->Enqueue( 357 SLresult err = (*simple_buffer_queue_)->Enqueue(
282 simple_buffer_queue_, 358 simple_buffer_queue_,
283 audio_data_[active_queue_], 359 audio_data_[active_buffer_index_],
284 num_filled_bytes); 360 num_filled_bytes);
285 if (SL_RESULT_SUCCESS != err) 361 if (SL_RESULT_SUCCESS != err)
286 HandleError(err); 362 HandleError(err);
287 363
288 active_queue_ = (active_queue_ + 1) % kNumOfQueuesInBuffer; 364 active_buffer_index_ = (active_buffer_index_ + 1) % kMaxNumOfBuffersInQueue;
289 } 365 }
290 366
291 void OpenSLESOutputStream::SetupAudioBuffer() { 367 void OpenSLESOutputStream::SetupAudioBuffer() {
368 DCHECK(thread_checker_.CalledOnValidThread());
292 DCHECK(!audio_data_[0]); 369 DCHECK(!audio_data_[0]);
293 for (int i = 0; i < kNumOfQueuesInBuffer; ++i) { 370 for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) {
294 audio_data_[i] = new uint8[buffer_size_bytes_]; 371 audio_data_[i] = new uint8[buffer_size_bytes_];
295 } 372 }
296 } 373 }
297 374
298 void OpenSLESOutputStream::ReleaseAudioBuffer() { 375 void OpenSLESOutputStream::ReleaseAudioBuffer() {
376 DCHECK(thread_checker_.CalledOnValidThread());
299 if (audio_data_[0]) { 377 if (audio_data_[0]) {
300 for (int i = 0; i < kNumOfQueuesInBuffer; ++i) { 378 for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) {
301 delete [] audio_data_[i]; 379 delete [] audio_data_[i];
302 audio_data_[i] = NULL; 380 audio_data_[i] = NULL;
303 } 381 }
304 } 382 }
305 } 383 }
306 384
307 void OpenSLESOutputStream::HandleError(SLresult error) { 385 void OpenSLESOutputStream::HandleError(SLresult error) {
308 DLOG(ERROR) << "OpenSLES Output error " << error; 386 DLOG(ERROR) << "OpenSLES Output error " << error;
309 if (callback_) 387 if (callback_)
310 callback_->OnError(this); 388 callback_->OnError(this);
311 } 389 }
312 390
313 } // namespace media 391 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698