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

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

Issue 1166483002: Stop enqueueing data to output audio device if consecutive empty buffers are received (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 6 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
« no previous file with comments | « media/audio/android/opensles_output.h ('k') | media/base/audio_bus.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/logging.h" 7 #include "base/logging.h"
8 #include "base/single_thread_task_runner.h"
9 #include "base/thread_task_runner_handle.h"
8 #include "base/trace_event/trace_event.h" 10 #include "base/trace_event/trace_event.h"
9 #include "media/audio/android/audio_manager_android.h" 11 #include "media/audio/android/audio_manager_android.h"
10 12
11 #define LOG_ON_FAILURE_AND_RETURN(op, ...) \ 13 #define LOG_ON_FAILURE_AND_RETURN(op, ...) \
12 do { \ 14 do { \
13 SLresult err = (op); \ 15 SLresult err = (op); \
14 if (err != SL_RESULT_SUCCESS) { \ 16 if (err != SL_RESULT_SUCCESS) { \
15 DLOG(ERROR) << #op << " failed: " << err; \ 17 DLOG(ERROR) << #op << " failed: " << err; \
16 return __VA_ARGS__; \ 18 return __VA_ARGS__; \
17 } \ 19 } \
18 } while (0) 20 } while (0)
19 21
20 namespace media { 22 namespace media {
21 23
24 // Threshold for consecutive number of empty buffers to let the player enter
25 // idle state.
26 // TODO(qinmin): change this threshold to count the number of frames.
27 static const int kEmptyBufferThreasholdForIdleMode = 2;
28
22 OpenSLESOutputStream::OpenSLESOutputStream(AudioManagerAndroid* manager, 29 OpenSLESOutputStream::OpenSLESOutputStream(AudioManagerAndroid* manager,
23 const AudioParameters& params, 30 const AudioParameters& params,
24 SLint32 stream_type) 31 SLint32 stream_type)
25 : audio_manager_(manager), 32 : audio_manager_(manager),
26 stream_type_(stream_type), 33 stream_type_(stream_type),
27 callback_(NULL), 34 callback_(NULL),
28 player_(NULL), 35 player_(NULL),
29 simple_buffer_queue_(NULL), 36 simple_buffer_queue_(NULL),
30 active_buffer_index_(0), 37 active_buffer_index_(0),
31 buffer_size_bytes_(0), 38 buffer_size_bytes_(0),
32 started_(false), 39 started_(false),
33 muted_(false), 40 muted_(false),
34 volume_(1.0) { 41 volume_(1.0),
42 consecutive_empty_buffer_count_(0),
43 task_runner_(base::ThreadTaskRunnerHandle::Get()),
44 weak_factory_(this) {
35 DVLOG(2) << "OpenSLESOutputStream::OpenSLESOutputStream(" 45 DVLOG(2) << "OpenSLESOutputStream::OpenSLESOutputStream("
36 << "stream_type=" << stream_type << ")"; 46 << "stream_type=" << stream_type << ")";
37 format_.formatType = SL_DATAFORMAT_PCM; 47 format_.formatType = SL_DATAFORMAT_PCM;
38 format_.numChannels = static_cast<SLuint32>(params.channels()); 48 format_.numChannels = static_cast<SLuint32>(params.channels());
39 // Provides sampling rate in milliHertz to OpenSLES. 49 // Provides sampling rate in milliHertz to OpenSLES.
40 format_.samplesPerSec = static_cast<SLuint32>(params.sample_rate() * 1000); 50 format_.samplesPerSec = static_cast<SLuint32>(params.sample_rate() * 1000);
41 format_.bitsPerSample = params.bits_per_sample(); 51 format_.bitsPerSample = params.bits_per_sample();
42 format_.containerSize = params.bits_per_sample(); 52 format_.containerSize = params.bits_per_sample();
43 format_.endianness = SL_BYTEORDER_LITTLEENDIAN; 53 format_.endianness = SL_BYTEORDER_LITTLEENDIAN;
44 if (format_.numChannels == 1) 54 if (format_.numChannels == 1)
45 format_.channelMask = SL_SPEAKER_FRONT_CENTER; 55 format_.channelMask = SL_SPEAKER_FRONT_CENTER;
46 else if (format_.numChannels == 2) 56 else if (format_.numChannels == 2)
47 format_.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; 57 format_.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
48 else 58 else
49 NOTREACHED() << "Unsupported number of channels: " << format_.numChannels; 59 NOTREACHED() << "Unsupported number of channels: " << format_.numChannels;
50 60
51 buffer_size_bytes_ = params.GetBytesPerBuffer(); 61 buffer_size_bytes_ = params.GetBytesPerBuffer();
52 audio_bus_ = AudioBus::Create(params); 62 audio_bus_ = AudioBus::Create(params);
53 63
54 memset(&audio_data_, 0, sizeof(audio_data_)); 64 memset(&audio_data_, 0, sizeof(audio_data_));
65 weak_this_ = weak_factory_.GetWeakPtr();
66 audio_timestamp_helper_.reset(new AudioTimestampHelper(params.sample_rate()));
55 } 67 }
56 68
57 OpenSLESOutputStream::~OpenSLESOutputStream() { 69 OpenSLESOutputStream::~OpenSLESOutputStream() {
58 DVLOG(2) << "OpenSLESOutputStream::~OpenSLESOutputStream()"; 70 DVLOG(2) << "OpenSLESOutputStream::~OpenSLESOutputStream()";
59 DCHECK(thread_checker_.CalledOnValidThread()); 71 DCHECK(thread_checker_.CalledOnValidThread());
60 DCHECK(!engine_object_.Get()); 72 DCHECK(!engine_object_.Get());
61 DCHECK(!player_object_.Get()); 73 DCHECK(!player_object_.Get());
62 DCHECK(!output_mixer_.Get()); 74 DCHECK(!output_mixer_.Get());
63 DCHECK(!player_); 75 DCHECK(!player_);
64 DCHECK(!simple_buffer_queue_); 76 DCHECK(!simple_buffer_queue_);
(...skipping 23 matching lines...) Expand all
88 DCHECK(simple_buffer_queue_); 100 DCHECK(simple_buffer_queue_);
89 if (started_) 101 if (started_)
90 return; 102 return;
91 103
92 base::AutoLock lock(lock_); 104 base::AutoLock lock(lock_);
93 DCHECK(callback_ == NULL || callback_ == callback); 105 DCHECK(callback_ == NULL || callback_ == callback);
94 callback_ = callback; 106 callback_ = callback;
95 107
96 // Avoid start-up glitches by filling up one buffer queue before starting 108 // Avoid start-up glitches by filling up one buffer queue before starting
97 // the stream. 109 // the stream.
98 FillBufferQueueNoLock(); 110 FillBufferQueueNoLock(false);
99 111
100 // Start streaming data by setting the play state to SL_PLAYSTATE_PLAYING. 112 // Start streaming data by setting the play state to SL_PLAYSTATE_PLAYING.
101 // For a player object, when the object is in the SL_PLAYSTATE_PLAYING 113 // For a player object, when the object is in the SL_PLAYSTATE_PLAYING
102 // state, adding buffers will implicitly start playback. 114 // state, adding buffers will implicitly start playback.
103 LOG_ON_FAILURE_AND_RETURN( 115 LOG_ON_FAILURE_AND_RETURN(
104 (*player_)->SetPlayState(player_, SL_PLAYSTATE_PLAYING)); 116 (*player_)->SetPlayState(player_, SL_PLAYSTATE_PLAYING));
105 117
106 started_ = true; 118 started_ = true;
107 } 119 }
108 120
(...skipping 18 matching lines...) Expand all
127 // Verify that the buffer queue is in fact cleared as it should. 139 // Verify that the buffer queue is in fact cleared as it should.
128 SLAndroidSimpleBufferQueueState buffer_queue_state; 140 SLAndroidSimpleBufferQueueState buffer_queue_state;
129 LOG_ON_FAILURE_AND_RETURN((*simple_buffer_queue_)->GetState( 141 LOG_ON_FAILURE_AND_RETURN((*simple_buffer_queue_)->GetState(
130 simple_buffer_queue_, &buffer_queue_state)); 142 simple_buffer_queue_, &buffer_queue_state));
131 DCHECK_EQ(0u, buffer_queue_state.count); 143 DCHECK_EQ(0u, buffer_queue_state.count);
132 DCHECK_EQ(0u, buffer_queue_state.index); 144 DCHECK_EQ(0u, buffer_queue_state.index);
133 #endif 145 #endif
134 146
135 callback_ = NULL; 147 callback_ = NULL;
136 started_ = false; 148 started_ = false;
149 CancelIdleCheck();
150 consecutive_empty_buffer_count_ = 0;
137 } 151 }
138 152
139 void OpenSLESOutputStream::Close() { 153 void OpenSLESOutputStream::Close() {
140 DVLOG(2) << "OpenSLESOutputStream::Close()"; 154 DVLOG(2) << "OpenSLESOutputStream::Close()";
141 DCHECK(thread_checker_.CalledOnValidThread()); 155 DCHECK(thread_checker_.CalledOnValidThread());
142 156
143 // Stop the stream if it is still playing. 157 // Stop the stream if it is still playing.
144 Stop(); 158 Stop();
145 { 159 {
146 // Destroy the buffer queue player object and invalidate all associated 160 // Destroy the buffer queue player object and invalidate all associated
(...skipping 13 matching lines...) Expand all
160 } 174 }
161 175
162 audio_manager_->ReleaseOutputStream(this); 176 audio_manager_->ReleaseOutputStream(this);
163 } 177 }
164 178
165 void OpenSLESOutputStream::SetVolume(double volume) { 179 void OpenSLESOutputStream::SetVolume(double volume) {
166 DVLOG(2) << "OpenSLESOutputStream::SetVolume(" << volume << ")"; 180 DVLOG(2) << "OpenSLESOutputStream::SetVolume(" << volume << ")";
167 DCHECK(thread_checker_.CalledOnValidThread()); 181 DCHECK(thread_checker_.CalledOnValidThread());
168 182
169 double volume_override = 0; 183 double volume_override = 0;
170 if (audio_manager_->HasOutputVolumeOverride(&volume_override)) { 184 if (audio_manager_->HasOutputVolumeOverride(&volume_override))
171 volume = volume_override; 185 volume = volume_override;
172 }
173 186
174 float volume_float = static_cast<float>(volume); 187 float volume_float = static_cast<float>(volume);
175 if (volume_float < 0.0f || volume_float > 1.0f) { 188 if (volume_float < 0.0f || volume_float > 1.0f)
176 return; 189 return;
177 }
178 volume_ = volume_float; 190 volume_ = volume_float;
179 } 191 }
180 192
181 void OpenSLESOutputStream::GetVolume(double* volume) { 193 void OpenSLESOutputStream::GetVolume(double* volume) {
182 DCHECK(thread_checker_.CalledOnValidThread()); 194 DCHECK(thread_checker_.CalledOnValidThread());
183 *volume = static_cast<double>(volume_); 195 *volume = static_cast<double>(volume_);
184 } 196 }
185 197
186 void OpenSLESOutputStream::SetMute(bool muted) { 198 void OpenSLESOutputStream::SetMute(bool muted) {
187 DVLOG(2) << "OpenSLESOutputStream::SetMute(" << muted << ")"; 199 DVLOG(2) << "OpenSLESOutputStream::SetMute(" << muted << ")";
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 HandleError(err); 324 HandleError(err);
313 return; 325 return;
314 } 326 }
315 if (state != SL_PLAYSTATE_PLAYING) { 327 if (state != SL_PLAYSTATE_PLAYING) {
316 DLOG(WARNING) << "Received callback in non-playing state"; 328 DLOG(WARNING) << "Received callback in non-playing state";
317 return; 329 return;
318 } 330 }
319 331
320 // Fill up one buffer in the queue by asking the registered source for 332 // Fill up one buffer in the queue by asking the registered source for
321 // data using the OnMoreData() callback. 333 // data using the OnMoreData() callback.
322 FillBufferQueueNoLock(); 334 FillBufferQueueNoLock(false);
323 } 335 }
324 336
325 void OpenSLESOutputStream::FillBufferQueueNoLock() { 337 void OpenSLESOutputStream::FillBufferQueueNoLock(bool in_idle_mode) {
326 // Ensure that the calling thread has acquired the lock since it is not 338 // Ensure that the calling thread has acquired the lock since it is not
327 // done in this method. 339 // done in this method.
328 lock_.AssertAcquired(); 340 lock_.AssertAcquired();
329 341
330 // Read data from the registered client source. 342 // Read data from the registered client source.
331 // TODO(henrika): Investigate if it is possible to get a more accurate 343 // TODO(henrika): Investigate if it is possible to get a more accurate
332 // delay estimation. 344 // delay estimation.
333 const uint32 hardware_delay = buffer_size_bytes_; 345 const uint32 hardware_delay = buffer_size_bytes_;
334 int frames_filled = callback_->OnMoreData( 346 int frames_filled = callback_->OnMoreData(audio_bus_.get(), hardware_delay);
335 audio_bus_.get(), hardware_delay);
336 if (frames_filled <= 0) { 347 if (frames_filled <= 0) {
337 // Audio source is shutting down, or halted on error. 348 // Audio source is shutting down, or halted on error.
338 return; 349 return;
339 } 350 }
340 351
352 // Skip enqueueing data if the output is empty to save power.
353 if (audio_bus_->AreFramesZero()) {
354 // TODO(qinmin): check if this variable overflows.
355 consecutive_empty_buffer_count_++;
356 if (consecutive_empty_buffer_count_ >= kEmptyBufferThreasholdForIdleMode) {
357 WaitingForAudio(in_idle_mode, frames_filled, base::TimeTicks::Now());
358 return;
359 }
360 } else {
361 consecutive_empty_buffer_count_ = 0;
362 }
363
341 // Note: If the internal representation ever changes from 16-bit PCM to 364 // Note: If the internal representation ever changes from 16-bit PCM to
342 // raw float, the data must be clipped and sanitized since it may come 365 // raw float, the data must be clipped and sanitized since it may come
343 // from an untrusted source such as NaCl. 366 // from an untrusted source such as NaCl.
344 audio_bus_->Scale(muted_ ? 0.0f : volume_); 367 audio_bus_->Scale(muted_ ? 0.0f : volume_);
345 audio_bus_->ToInterleaved(frames_filled, 368 audio_bus_->ToInterleaved(frames_filled,
346 format_.bitsPerSample / 8, 369 format_.bitsPerSample / 8,
347 audio_data_[active_buffer_index_]); 370 audio_data_[active_buffer_index_]);
348 371
349 const int num_filled_bytes = 372 const int num_filled_bytes =
350 frames_filled * audio_bus_->channels() * format_.bitsPerSample / 8; 373 frames_filled * audio_bus_->channels() * format_.bitsPerSample / 8;
351 DCHECK_LE(static_cast<size_t>(num_filled_bytes), buffer_size_bytes_); 374 DCHECK_LE(static_cast<size_t>(num_filled_bytes), buffer_size_bytes_);
352 375
353 // Enqueue the buffer for playback. 376 // Enqueue the buffer for playback.
354 SLresult err = 377 SLresult err =
355 (*simple_buffer_queue_)->Enqueue(simple_buffer_queue_, 378 (*simple_buffer_queue_)->Enqueue(simple_buffer_queue_,
356 audio_data_[active_buffer_index_], 379 audio_data_[active_buffer_index_],
357 num_filled_bytes); 380 num_filled_bytes);
358 if (SL_RESULT_SUCCESS != err) 381 if (SL_RESULT_SUCCESS != err)
359 HandleError(err); 382 HandleError(err);
360 383
361 active_buffer_index_ = (active_buffer_index_ + 1) % kMaxNumOfBuffersInQueue; 384 active_buffer_index_ = (active_buffer_index_ + 1) % kMaxNumOfBuffersInQueue;
362 } 385 }
363 386
364 void OpenSLESOutputStream::SetupAudioBuffer() { 387 void OpenSLESOutputStream::SetupAudioBuffer() {
365 DCHECK(thread_checker_.CalledOnValidThread()); 388 DCHECK(thread_checker_.CalledOnValidThread());
366 DCHECK(!audio_data_[0]); 389 DCHECK(!audio_data_[0]);
367 for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) { 390 for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i)
368 audio_data_[i] = new uint8[buffer_size_bytes_]; 391 audio_data_[i] = new uint8[buffer_size_bytes_];
369 }
370 } 392 }
371 393
372 void OpenSLESOutputStream::ReleaseAudioBuffer() { 394 void OpenSLESOutputStream::ReleaseAudioBuffer() {
373 DCHECK(thread_checker_.CalledOnValidThread()); 395 DCHECK(thread_checker_.CalledOnValidThread());
374 if (audio_data_[0]) { 396 if (audio_data_[0]) {
375 for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) { 397 for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) {
376 delete[] audio_data_[i]; 398 delete[] audio_data_[i];
377 audio_data_[i] = NULL; 399 audio_data_[i] = NULL;
378 } 400 }
379 } 401 }
380 } 402 }
381 403
382 void OpenSLESOutputStream::HandleError(SLresult error) { 404 void OpenSLESOutputStream::HandleError(SLresult error) {
383 DLOG(ERROR) << "OpenSLES Output error " << error; 405 DLOG(ERROR) << "OpenSLES Output error " << error;
384 if (callback_) 406 if (callback_)
385 callback_->OnError(this); 407 callback_->OnError(this);
408 CancelIdleCheck();
409 }
410
411 void OpenSLESOutputStream::CheckForIdle() {
412 DCHECK(thread_checker_.CalledOnValidThread());
413 DCHECK(!idle_check_callback_.IsCancelled());
414
415 if (!started_)
416 return;
417 base::AutoLock lock(lock_);
418 FillBufferQueueNoLock(true);
419 }
420
421 void OpenSLESOutputStream::CancelIdleCheck() {
422 if (!task_runner_->BelongsToCurrentThread()) {
423 task_runner_->PostTask(
424 FROM_HERE,
425 base::Bind(&OpenSLESOutputStream::CancelIdleCheck, weak_this_));
426 return;
427 }
428 idle_check_callback_.Cancel();
429 }
430
431 void OpenSLESOutputStream::WaitingForAudio(
432 bool in_idle_mode, int frames_filled, base::TimeTicks idle_start_time) {
433 if (!task_runner_->BelongsToCurrentThread()) {
434 task_runner_->PostTask(
435 FROM_HERE,
436 base::Bind(&OpenSLESOutputStream::WaitingForAudio,
437 weak_this_, in_idle_mode, frames_filled, idle_start_time));
438 return;
439 }
440
441 if (!in_idle_mode) {
442 audio_timestamp_helper_->SetBaseTimestamp(base::TimeDelta());
443 idle_start_time_ = idle_start_time;
444 idle_check_callback_.Reset(
445 base::Bind(&OpenSLESOutputStream::CheckForIdle, weak_this_));
446 }
447
448 audio_timestamp_helper_->AddFrames(frames_filled);
449 base::TimeDelta delay_to_next_read = audio_timestamp_helper_->GetTimestamp() +
450 (idle_start_time_ - base::TimeTicks::Now());
451 if (delay_to_next_read < base::TimeDelta())
452 delay_to_next_read = base::TimeDelta();
453 task_runner_->PostDelayedTask(
454 FROM_HERE,
455 idle_check_callback_.callback(),
456 delay_to_next_read);
386 } 457 }
387 458
388 } // namespace media 459 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/android/opensles_output.h ('k') | media/base/audio_bus.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698