Add some instrumentation for jank in URLRequest::Start.
[chromium-blink-merge.git] / media / audio / android / opensles_output.cc
blob2974e1418ca57454bfeff4c5abbfba4631860015
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
3 // found in the LICENSE file.
5 #include "media/audio/android/opensles_output.h"
7 #include "base/logging.h"
8 #include "base/trace_event/trace_event.h"
9 #include "media/audio/android/audio_manager_android.h"
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)
20 namespace media {
22 OpenSLESOutputStream::OpenSLESOutputStream(AudioManagerAndroid* manager,
23 const AudioParameters& params,
24 SLint32 stream_type)
25 : audio_manager_(manager),
26 stream_type_(stream_type),
27 callback_(NULL),
28 player_(NULL),
29 simple_buffer_queue_(NULL),
30 active_buffer_index_(0),
31 buffer_size_bytes_(0),
32 started_(false),
33 muted_(false),
34 volume_(1.0) {
35 DVLOG(2) << "OpenSLESOutputStream::OpenSLESOutputStream("
36 << "stream_type=" << stream_type << ")";
37 format_.formatType = SL_DATAFORMAT_PCM;
38 format_.numChannels = static_cast<SLuint32>(params.channels());
39 // Provides sampling rate in milliHertz to OpenSLES.
40 format_.samplesPerSec = static_cast<SLuint32>(params.sample_rate() * 1000);
41 format_.bitsPerSample = params.bits_per_sample();
42 format_.containerSize = params.bits_per_sample();
43 format_.endianness = SL_BYTEORDER_LITTLEENDIAN;
44 if (format_.numChannels == 1)
45 format_.channelMask = SL_SPEAKER_FRONT_CENTER;
46 else if (format_.numChannels == 2)
47 format_.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
48 else
49 NOTREACHED() << "Unsupported number of channels: " << format_.numChannels;
51 buffer_size_bytes_ = params.GetBytesPerBuffer();
52 audio_bus_ = AudioBus::Create(params);
54 memset(&audio_data_, 0, sizeof(audio_data_));
57 OpenSLESOutputStream::~OpenSLESOutputStream() {
58 DVLOG(2) << "OpenSLESOutputStream::~OpenSLESOutputStream()";
59 DCHECK(thread_checker_.CalledOnValidThread());
60 DCHECK(!engine_object_.Get());
61 DCHECK(!player_object_.Get());
62 DCHECK(!output_mixer_.Get());
63 DCHECK(!player_);
64 DCHECK(!simple_buffer_queue_);
65 DCHECK(!audio_data_[0]);
68 bool OpenSLESOutputStream::Open() {
69 DVLOG(2) << "OpenSLESOutputStream::Open()";
70 DCHECK(thread_checker_.CalledOnValidThread());
71 if (engine_object_.Get())
72 return false;
74 if (!CreatePlayer())
75 return false;
77 SetupAudioBuffer();
78 active_buffer_index_ = 0;
80 return true;
83 void OpenSLESOutputStream::Start(AudioSourceCallback* callback) {
84 DVLOG(2) << "OpenSLESOutputStream::Start()";
85 DCHECK(thread_checker_.CalledOnValidThread());
86 DCHECK(callback);
87 DCHECK(player_);
88 DCHECK(simple_buffer_queue_);
89 if (started_)
90 return;
92 base::AutoLock lock(lock_);
93 DCHECK(callback_ == NULL || callback_ == callback);
94 callback_ = callback;
96 // Avoid start-up glitches by filling up one buffer queue before starting
97 // the stream.
98 FillBufferQueueNoLock();
100 // 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
102 // state, adding buffers will implicitly start playback.
103 LOG_ON_FAILURE_AND_RETURN(
104 (*player_)->SetPlayState(player_, SL_PLAYSTATE_PLAYING));
106 started_ = true;
109 void OpenSLESOutputStream::Stop() {
110 DVLOG(2) << "OpenSLESOutputStream::Stop()";
111 DCHECK(thread_checker_.CalledOnValidThread());
112 if (!started_)
113 return;
115 base::AutoLock lock(lock_);
117 // Stop playing by setting the play state to SL_PLAYSTATE_STOPPED.
118 LOG_ON_FAILURE_AND_RETURN(
119 (*player_)->SetPlayState(player_, SL_PLAYSTATE_STOPPED));
121 // Clear the buffer queue so that the old data won't be played when
122 // resuming playing.
123 LOG_ON_FAILURE_AND_RETURN(
124 (*simple_buffer_queue_)->Clear(simple_buffer_queue_));
126 #ifndef NDEBUG
127 // Verify that the buffer queue is in fact cleared as it should.
128 SLAndroidSimpleBufferQueueState buffer_queue_state;
129 LOG_ON_FAILURE_AND_RETURN((*simple_buffer_queue_)->GetState(
130 simple_buffer_queue_, &buffer_queue_state));
131 DCHECK_EQ(0u, buffer_queue_state.count);
132 DCHECK_EQ(0u, buffer_queue_state.index);
133 #endif
135 callback_ = NULL;
136 started_ = false;
139 void OpenSLESOutputStream::Close() {
140 DVLOG(2) << "OpenSLESOutputStream::Close()";
141 DCHECK(thread_checker_.CalledOnValidThread());
143 // Stop the stream if it is still playing.
144 Stop();
146 // Destroy the buffer queue player object and invalidate all associated
147 // interfaces.
148 player_object_.Reset();
149 simple_buffer_queue_ = NULL;
150 player_ = NULL;
152 // Destroy the mixer object. We don't store any associated interface for
153 // this object.
154 output_mixer_.Reset();
156 // Destroy the engine object. We don't store any associated interface for
157 // this object.
158 engine_object_.Reset();
159 ReleaseAudioBuffer();
162 audio_manager_->ReleaseOutputStream(this);
165 void OpenSLESOutputStream::SetVolume(double volume) {
166 DVLOG(2) << "OpenSLESOutputStream::SetVolume(" << volume << ")";
167 DCHECK(thread_checker_.CalledOnValidThread());
169 double volume_override = 0;
170 if (audio_manager_->HasOutputVolumeOverride(&volume_override)) {
171 volume = volume_override;
174 float volume_float = static_cast<float>(volume);
175 if (volume_float < 0.0f || volume_float > 1.0f) {
176 return;
178 volume_ = volume_float;
181 void OpenSLESOutputStream::GetVolume(double* volume) {
182 DCHECK(thread_checker_.CalledOnValidThread());
183 *volume = static_cast<double>(volume_);
186 void OpenSLESOutputStream::SetMute(bool muted) {
187 DVLOG(2) << "OpenSLESOutputStream::SetMute(" << muted << ")";
188 DCHECK(thread_checker_.CalledOnValidThread());
189 muted_ = muted;
192 bool OpenSLESOutputStream::CreatePlayer() {
193 DCHECK(thread_checker_.CalledOnValidThread());
194 DCHECK(!engine_object_.Get());
195 DCHECK(!player_object_.Get());
196 DCHECK(!output_mixer_.Get());
197 DCHECK(!player_);
198 DCHECK(!simple_buffer_queue_);
200 // Initializes the engine object with specific option. After working with the
201 // object, we need to free the object and its resources.
202 SLEngineOption option[] = {
203 {SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE)}};
204 LOG_ON_FAILURE_AND_RETURN(
205 slCreateEngine(engine_object_.Receive(), 1, option, 0, NULL, NULL),
206 false);
208 // Realize the SL engine object in synchronous mode.
209 LOG_ON_FAILURE_AND_RETURN(
210 engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE), false);
212 // Get the SL engine interface which is implicit.
213 SLEngineItf engine;
214 LOG_ON_FAILURE_AND_RETURN(engine_object_->GetInterface(
215 engine_object_.Get(), SL_IID_ENGINE, &engine),
216 false);
218 // Create ouput mixer object to be used by the player.
219 LOG_ON_FAILURE_AND_RETURN((*engine)->CreateOutputMix(
220 engine, output_mixer_.Receive(), 0, NULL, NULL),
221 false);
223 // Realizing the output mix object in synchronous mode.
224 LOG_ON_FAILURE_AND_RETURN(
225 output_mixer_->Realize(output_mixer_.Get(), SL_BOOLEAN_FALSE), false);
227 // Audio source configuration.
228 SLDataLocator_AndroidSimpleBufferQueue simple_buffer_queue = {
229 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
230 static_cast<SLuint32>(kMaxNumOfBuffersInQueue)};
231 SLDataSource audio_source = {&simple_buffer_queue, &format_};
233 // Audio sink configuration.
234 SLDataLocator_OutputMix locator_output_mix = {SL_DATALOCATOR_OUTPUTMIX,
235 output_mixer_.Get()};
236 SLDataSink audio_sink = {&locator_output_mix, NULL};
238 // Create an audio player.
239 const SLInterfaceID interface_id[] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME,
240 SL_IID_ANDROIDCONFIGURATION};
241 const SLboolean interface_required[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE,
242 SL_BOOLEAN_TRUE};
243 LOG_ON_FAILURE_AND_RETURN(
244 (*engine)->CreateAudioPlayer(engine,
245 player_object_.Receive(),
246 &audio_source,
247 &audio_sink,
248 arraysize(interface_id),
249 interface_id,
250 interface_required),
251 false);
253 // Create AudioPlayer and specify SL_IID_ANDROIDCONFIGURATION.
254 SLAndroidConfigurationItf player_config;
255 LOG_ON_FAILURE_AND_RETURN(
256 player_object_->GetInterface(
257 player_object_.Get(), SL_IID_ANDROIDCONFIGURATION, &player_config),
258 false);
260 // Set configuration using the stream type provided at construction.
261 LOG_ON_FAILURE_AND_RETURN(
262 (*player_config)->SetConfiguration(player_config,
263 SL_ANDROID_KEY_STREAM_TYPE,
264 &stream_type_,
265 sizeof(SLint32)),
266 false);
268 // Realize the player object in synchronous mode.
269 LOG_ON_FAILURE_AND_RETURN(
270 player_object_->Realize(player_object_.Get(), SL_BOOLEAN_FALSE), false);
272 // Get an implicit player interface.
273 LOG_ON_FAILURE_AND_RETURN(
274 player_object_->GetInterface(player_object_.Get(), SL_IID_PLAY, &player_),
275 false);
277 // Get the simple buffer queue interface.
278 LOG_ON_FAILURE_AND_RETURN(
279 player_object_->GetInterface(
280 player_object_.Get(), SL_IID_BUFFERQUEUE, &simple_buffer_queue_),
281 false);
283 // Register the input callback for the simple buffer queue.
284 // This callback will be called when the soundcard needs data.
285 LOG_ON_FAILURE_AND_RETURN(
286 (*simple_buffer_queue_)->RegisterCallback(
287 simple_buffer_queue_, SimpleBufferQueueCallback, this),
288 false);
290 return true;
293 void OpenSLESOutputStream::SimpleBufferQueueCallback(
294 SLAndroidSimpleBufferQueueItf buffer_queue,
295 void* instance) {
296 OpenSLESOutputStream* stream =
297 reinterpret_cast<OpenSLESOutputStream*>(instance);
298 stream->FillBufferQueue();
301 void OpenSLESOutputStream::FillBufferQueue() {
302 base::AutoLock lock(lock_);
303 if (!started_)
304 return;
306 TRACE_EVENT0("audio", "OpenSLESOutputStream::FillBufferQueue");
308 // Verify that we are in a playing state.
309 SLuint32 state;
310 SLresult err = (*player_)->GetPlayState(player_, &state);
311 if (SL_RESULT_SUCCESS != err) {
312 HandleError(err);
313 return;
315 if (state != SL_PLAYSTATE_PLAYING) {
316 DLOG(WARNING) << "Received callback in non-playing state";
317 return;
320 // Fill up one buffer in the queue by asking the registered source for
321 // data using the OnMoreData() callback.
322 FillBufferQueueNoLock();
325 void OpenSLESOutputStream::FillBufferQueueNoLock() {
326 // Ensure that the calling thread has acquired the lock since it is not
327 // done in this method.
328 lock_.AssertAcquired();
330 // Read data from the registered client source.
331 // TODO(henrika): Investigate if it is possible to get a more accurate
332 // delay estimation.
333 const uint32 hardware_delay = buffer_size_bytes_;
334 int frames_filled = callback_->OnMoreData(
335 audio_bus_.get(), hardware_delay);
336 if (frames_filled <= 0) {
337 // Audio source is shutting down, or halted on error.
338 return;
341 // 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
343 // from an untrusted source such as NaCl.
344 audio_bus_->Scale(muted_ ? 0.0f : volume_);
345 audio_bus_->ToInterleaved(frames_filled,
346 format_.bitsPerSample / 8,
347 audio_data_[active_buffer_index_]);
349 const int num_filled_bytes =
350 frames_filled * audio_bus_->channels() * format_.bitsPerSample / 8;
351 DCHECK_LE(static_cast<size_t>(num_filled_bytes), buffer_size_bytes_);
353 // Enqueue the buffer for playback.
354 SLresult err =
355 (*simple_buffer_queue_)->Enqueue(simple_buffer_queue_,
356 audio_data_[active_buffer_index_],
357 num_filled_bytes);
358 if (SL_RESULT_SUCCESS != err)
359 HandleError(err);
361 active_buffer_index_ = (active_buffer_index_ + 1) % kMaxNumOfBuffersInQueue;
364 void OpenSLESOutputStream::SetupAudioBuffer() {
365 DCHECK(thread_checker_.CalledOnValidThread());
366 DCHECK(!audio_data_[0]);
367 for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) {
368 audio_data_[i] = new uint8[buffer_size_bytes_];
372 void OpenSLESOutputStream::ReleaseAudioBuffer() {
373 DCHECK(thread_checker_.CalledOnValidThread());
374 if (audio_data_[0]) {
375 for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) {
376 delete[] audio_data_[i];
377 audio_data_[i] = NULL;
382 void OpenSLESOutputStream::HandleError(SLresult error) {
383 DLOG(ERROR) << "OpenSLES Output error " << error;
384 if (callback_)
385 callback_->OnError(this);
388 } // namespace media