Add git cl format presubmit warning for extension and apps.
[chromium-blink-merge.git] / media / audio / android / opensles_output.cc
blobb71680f0a7ef38d5b969facf447522bc84292cdc
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/debug/trace_event.h"
8 #include "base/logging.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 : audio_manager_(manager),
25 callback_(NULL),
26 player_(NULL),
27 simple_buffer_queue_(NULL),
28 active_buffer_index_(0),
29 buffer_size_bytes_(0),
30 started_(false),
31 muted_(false),
32 volume_(1.0) {
33 DVLOG(2) << "OpenSLESOutputStream::OpenSLESOutputStream()";
34 format_.formatType = SL_DATAFORMAT_PCM;
35 format_.numChannels = static_cast<SLuint32>(params.channels());
36 // Provides sampling rate in milliHertz to OpenSLES.
37 format_.samplesPerSec = static_cast<SLuint32>(params.sample_rate() * 1000);
38 format_.bitsPerSample = params.bits_per_sample();
39 format_.containerSize = params.bits_per_sample();
40 format_.endianness = SL_BYTEORDER_LITTLEENDIAN;
41 if (format_.numChannels == 1)
42 format_.channelMask = SL_SPEAKER_FRONT_CENTER;
43 else if (format_.numChannels == 2)
44 format_.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
45 else
46 NOTREACHED() << "Unsupported number of channels: " << format_.numChannels;
48 buffer_size_bytes_ = params.GetBytesPerBuffer();
49 audio_bus_ = AudioBus::Create(params);
51 memset(&audio_data_, 0, sizeof(audio_data_));
54 OpenSLESOutputStream::~OpenSLESOutputStream() {
55 DVLOG(2) << "OpenSLESOutputStream::~OpenSLESOutputStream()";
56 DCHECK(thread_checker_.CalledOnValidThread());
57 DCHECK(!engine_object_.Get());
58 DCHECK(!player_object_.Get());
59 DCHECK(!output_mixer_.Get());
60 DCHECK(!player_);
61 DCHECK(!simple_buffer_queue_);
62 DCHECK(!audio_data_[0]);
65 bool OpenSLESOutputStream::Open() {
66 DVLOG(2) << "OpenSLESOutputStream::Open()";
67 DCHECK(thread_checker_.CalledOnValidThread());
68 if (engine_object_.Get())
69 return false;
71 if (!CreatePlayer())
72 return false;
74 SetupAudioBuffer();
75 active_buffer_index_ = 0;
77 return true;
80 void OpenSLESOutputStream::Start(AudioSourceCallback* callback) {
81 DVLOG(2) << "OpenSLESOutputStream::Start()";
82 DCHECK(thread_checker_.CalledOnValidThread());
83 DCHECK(callback);
84 DCHECK(player_);
85 DCHECK(simple_buffer_queue_);
86 if (started_)
87 return;
89 base::AutoLock lock(lock_);
90 DCHECK(callback_ == NULL || callback_ == callback);
91 callback_ = callback;
93 // Avoid start-up glitches by filling up one buffer queue before starting
94 // the stream.
95 FillBufferQueueNoLock();
97 // Start streaming data by setting the play state to SL_PLAYSTATE_PLAYING.
98 // For a player object, when the object is in the SL_PLAYSTATE_PLAYING
99 // state, adding buffers will implicitly start playback.
100 LOG_ON_FAILURE_AND_RETURN(
101 (*player_)->SetPlayState(player_, SL_PLAYSTATE_PLAYING));
103 started_ = true;
106 void OpenSLESOutputStream::Stop() {
107 DVLOG(2) << "OpenSLESOutputStream::Stop()";
108 DCHECK(thread_checker_.CalledOnValidThread());
109 if (!started_)
110 return;
112 base::AutoLock lock(lock_);
114 // Stop playing by setting the play state to SL_PLAYSTATE_STOPPED.
115 LOG_ON_FAILURE_AND_RETURN(
116 (*player_)->SetPlayState(player_, SL_PLAYSTATE_STOPPED));
118 // Clear the buffer queue so that the old data won't be played when
119 // resuming playing.
120 LOG_ON_FAILURE_AND_RETURN(
121 (*simple_buffer_queue_)->Clear(simple_buffer_queue_));
123 #ifndef NDEBUG
124 // Verify that the buffer queue is in fact cleared as it should.
125 SLAndroidSimpleBufferQueueState buffer_queue_state;
126 LOG_ON_FAILURE_AND_RETURN((*simple_buffer_queue_)->GetState(
127 simple_buffer_queue_, &buffer_queue_state));
128 DCHECK_EQ(0u, buffer_queue_state.count);
129 DCHECK_EQ(0u, buffer_queue_state.index);
130 #endif
132 callback_ = NULL;
133 started_ = false;
136 void OpenSLESOutputStream::Close() {
137 DVLOG(2) << "OpenSLESOutputStream::Close()";
138 DCHECK(thread_checker_.CalledOnValidThread());
140 // Stop the stream if it is still playing.
141 Stop();
143 // Destroy the buffer queue player object and invalidate all associated
144 // interfaces.
145 player_object_.Reset();
146 simple_buffer_queue_ = NULL;
147 player_ = NULL;
149 // Destroy the mixer object. We don't store any associated interface for
150 // this object.
151 output_mixer_.Reset();
153 // Destroy the engine object. We don't store any associated interface for
154 // this object.
155 engine_object_.Reset();
156 ReleaseAudioBuffer();
159 audio_manager_->ReleaseOutputStream(this);
162 void OpenSLESOutputStream::SetVolume(double volume) {
163 DVLOG(2) << "OpenSLESOutputStream::SetVolume(" << volume << ")";
164 DCHECK(thread_checker_.CalledOnValidThread());
165 float volume_float = static_cast<float>(volume);
166 if (volume_float < 0.0f || volume_float > 1.0f) {
167 return;
169 volume_ = volume_float;
172 void OpenSLESOutputStream::GetVolume(double* volume) {
173 DCHECK(thread_checker_.CalledOnValidThread());
174 *volume = static_cast<double>(volume_);
177 void OpenSLESOutputStream::SetMute(bool muted) {
178 DVLOG(2) << "OpenSLESOutputStream::SetMute(" << muted << ")";
179 DCHECK(thread_checker_.CalledOnValidThread());
180 muted_ = muted;
183 bool OpenSLESOutputStream::CreatePlayer() {
184 DCHECK(thread_checker_.CalledOnValidThread());
185 DCHECK(!engine_object_.Get());
186 DCHECK(!player_object_.Get());
187 DCHECK(!output_mixer_.Get());
188 DCHECK(!player_);
189 DCHECK(!simple_buffer_queue_);
191 // Initializes the engine object with specific option. After working with the
192 // object, we need to free the object and its resources.
193 SLEngineOption option[] = {
194 {SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE)}};
195 LOG_ON_FAILURE_AND_RETURN(
196 slCreateEngine(engine_object_.Receive(), 1, option, 0, NULL, NULL),
197 false);
199 // Realize the SL engine object in synchronous mode.
200 LOG_ON_FAILURE_AND_RETURN(
201 engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE), false);
203 // Get the SL engine interface which is implicit.
204 SLEngineItf engine;
205 LOG_ON_FAILURE_AND_RETURN(engine_object_->GetInterface(
206 engine_object_.Get(), SL_IID_ENGINE, &engine),
207 false);
209 // Create ouput mixer object to be used by the player.
210 LOG_ON_FAILURE_AND_RETURN((*engine)->CreateOutputMix(
211 engine, output_mixer_.Receive(), 0, NULL, NULL),
212 false);
214 // Realizing the output mix object in synchronous mode.
215 LOG_ON_FAILURE_AND_RETURN(
216 output_mixer_->Realize(output_mixer_.Get(), SL_BOOLEAN_FALSE), false);
218 // Audio source configuration.
219 SLDataLocator_AndroidSimpleBufferQueue simple_buffer_queue = {
220 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
221 static_cast<SLuint32>(kMaxNumOfBuffersInQueue)};
222 SLDataSource audio_source = {&simple_buffer_queue, &format_};
224 // Audio sink configuration.
225 SLDataLocator_OutputMix locator_output_mix = {SL_DATALOCATOR_OUTPUTMIX,
226 output_mixer_.Get()};
227 SLDataSink audio_sink = {&locator_output_mix, NULL};
229 // Create an audio player.
230 const SLInterfaceID interface_id[] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME,
231 SL_IID_ANDROIDCONFIGURATION};
232 const SLboolean interface_required[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE,
233 SL_BOOLEAN_TRUE};
234 LOG_ON_FAILURE_AND_RETURN(
235 (*engine)->CreateAudioPlayer(engine,
236 player_object_.Receive(),
237 &audio_source,
238 &audio_sink,
239 arraysize(interface_id),
240 interface_id,
241 interface_required),
242 false);
244 // Create AudioPlayer and specify SL_IID_ANDROIDCONFIGURATION.
245 SLAndroidConfigurationItf player_config;
246 LOG_ON_FAILURE_AND_RETURN(
247 player_object_->GetInterface(
248 player_object_.Get(), SL_IID_ANDROIDCONFIGURATION, &player_config),
249 false);
251 SLint32 stream_type = SL_ANDROID_STREAM_VOICE;
252 LOG_ON_FAILURE_AND_RETURN(
253 (*player_config)->SetConfiguration(player_config,
254 SL_ANDROID_KEY_STREAM_TYPE,
255 &stream_type,
256 sizeof(SLint32)),
257 false);
259 // Realize the player object in synchronous mode.
260 LOG_ON_FAILURE_AND_RETURN(
261 player_object_->Realize(player_object_.Get(), SL_BOOLEAN_FALSE), false);
263 // Get an implicit player interface.
264 LOG_ON_FAILURE_AND_RETURN(
265 player_object_->GetInterface(player_object_.Get(), SL_IID_PLAY, &player_),
266 false);
268 // Get the simple buffer queue interface.
269 LOG_ON_FAILURE_AND_RETURN(
270 player_object_->GetInterface(
271 player_object_.Get(), SL_IID_BUFFERQUEUE, &simple_buffer_queue_),
272 false);
274 // Register the input callback for the simple buffer queue.
275 // This callback will be called when the soundcard needs data.
276 LOG_ON_FAILURE_AND_RETURN(
277 (*simple_buffer_queue_)->RegisterCallback(
278 simple_buffer_queue_, SimpleBufferQueueCallback, this),
279 false);
281 return true;
284 void OpenSLESOutputStream::SimpleBufferQueueCallback(
285 SLAndroidSimpleBufferQueueItf buffer_queue,
286 void* instance) {
287 OpenSLESOutputStream* stream =
288 reinterpret_cast<OpenSLESOutputStream*>(instance);
289 stream->FillBufferQueue();
292 void OpenSLESOutputStream::FillBufferQueue() {
293 base::AutoLock lock(lock_);
294 if (!started_)
295 return;
297 TRACE_EVENT0("audio", "OpenSLESOutputStream::FillBufferQueue");
299 // Verify that we are in a playing state.
300 SLuint32 state;
301 SLresult err = (*player_)->GetPlayState(player_, &state);
302 if (SL_RESULT_SUCCESS != err) {
303 HandleError(err);
304 return;
306 if (state != SL_PLAYSTATE_PLAYING) {
307 DLOG(WARNING) << "Received callback in non-playing state";
308 return;
311 // Fill up one buffer in the queue by asking the registered source for
312 // data using the OnMoreData() callback.
313 FillBufferQueueNoLock();
316 void OpenSLESOutputStream::FillBufferQueueNoLock() {
317 // Ensure that the calling thread has acquired the lock since it is not
318 // done in this method.
319 lock_.AssertAcquired();
321 // Read data from the registered client source.
322 // TODO(henrika): Investigate if it is possible to get a more accurate
323 // delay estimation.
324 const uint32 hardware_delay = buffer_size_bytes_;
325 int frames_filled = callback_->OnMoreData(
326 audio_bus_.get(), AudioBuffersState(0, hardware_delay));
327 if (frames_filled <= 0) {
328 // Audio source is shutting down, or halted on error.
329 return;
332 // Note: If the internal representation ever changes from 16-bit PCM to
333 // raw float, the data must be clipped and sanitized since it may come
334 // from an untrusted source such as NaCl.
335 audio_bus_->Scale(muted_ ? 0.0f : volume_);
336 audio_bus_->ToInterleaved(frames_filled,
337 format_.bitsPerSample / 8,
338 audio_data_[active_buffer_index_]);
340 const int num_filled_bytes =
341 frames_filled * audio_bus_->channels() * format_.bitsPerSample / 8;
342 DCHECK_LE(static_cast<size_t>(num_filled_bytes), buffer_size_bytes_);
344 // Enqueue the buffer for playback.
345 SLresult err =
346 (*simple_buffer_queue_)->Enqueue(simple_buffer_queue_,
347 audio_data_[active_buffer_index_],
348 num_filled_bytes);
349 if (SL_RESULT_SUCCESS != err)
350 HandleError(err);
352 active_buffer_index_ = (active_buffer_index_ + 1) % kMaxNumOfBuffersInQueue;
355 void OpenSLESOutputStream::SetupAudioBuffer() {
356 DCHECK(thread_checker_.CalledOnValidThread());
357 DCHECK(!audio_data_[0]);
358 for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) {
359 audio_data_[i] = new uint8[buffer_size_bytes_];
363 void OpenSLESOutputStream::ReleaseAudioBuffer() {
364 DCHECK(thread_checker_.CalledOnValidThread());
365 if (audio_data_[0]) {
366 for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) {
367 delete[] audio_data_[i];
368 audio_data_[i] = NULL;
373 void OpenSLESOutputStream::HandleError(SLresult error) {
374 DLOG(ERROR) << "OpenSLES Output error " << error;
375 if (callback_)
376 callback_->OnError(this);
379 } // namespace media