Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / media / audio / android / opensles_output.cc
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.
4
5 #include "media/audio/android/opensles_output.h"
6
7 #include "base/debug/trace_event.h"
8 #include "base/logging.h"
9 #include "media/audio/android/audio_manager_android.h"
10
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)
19
20 namespace media {
21
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;
50
51   buffer_size_bytes_ = params.GetBytesPerBuffer();
52   audio_bus_ = AudioBus::Create(params);
53
54   memset(&audio_data_, 0, sizeof(audio_data_));
55 }
56
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]);
66 }
67
68 bool OpenSLESOutputStream::Open() {
69   DVLOG(2) << "OpenSLESOutputStream::Open()";
70   DCHECK(thread_checker_.CalledOnValidThread());
71   if (engine_object_.Get())
72     return false;
73
74   if (!CreatePlayer())
75     return false;
76
77   SetupAudioBuffer();
78   active_buffer_index_ = 0;
79
80   return true;
81 }
82
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;
91
92   base::AutoLock lock(lock_);
93   DCHECK(callback_ == NULL || callback_ == callback);
94   callback_ = callback;
95
96   // Avoid start-up glitches by filling up one buffer queue before starting
97   // the stream.
98   FillBufferQueueNoLock();
99
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));
105
106   started_ = true;
107 }
108
109 void OpenSLESOutputStream::Stop() {
110   DVLOG(2) << "OpenSLESOutputStream::Stop()";
111   DCHECK(thread_checker_.CalledOnValidThread());
112   if (!started_)
113     return;
114
115   base::AutoLock lock(lock_);
116
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));
120
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_));
125
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
134
135   callback_ = NULL;
136   started_ = false;
137 }
138
139 void OpenSLESOutputStream::Close() {
140   DVLOG(2) << "OpenSLESOutputStream::Close()";
141   DCHECK(thread_checker_.CalledOnValidThread());
142
143   // Stop the stream if it is still playing.
144   Stop();
145   {
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;
151
152     // Destroy the mixer object. We don't store any associated interface for
153     // this object.
154     output_mixer_.Reset();
155
156     // Destroy the engine object. We don't store any associated interface for
157     // this object.
158     engine_object_.Reset();
159     ReleaseAudioBuffer();
160   }
161
162   audio_manager_->ReleaseOutputStream(this);
163 }
164
165 void OpenSLESOutputStream::SetVolume(double volume) {
166   DVLOG(2) << "OpenSLESOutputStream::SetVolume(" << volume << ")";
167   DCHECK(thread_checker_.CalledOnValidThread());
168   float volume_float = static_cast<float>(volume);
169   if (volume_float < 0.0f || volume_float > 1.0f) {
170     return;
171   }
172   volume_ = volume_float;
173 }
174
175 void OpenSLESOutputStream::GetVolume(double* volume) {
176   DCHECK(thread_checker_.CalledOnValidThread());
177   *volume = static_cast<double>(volume_);
178 }
179
180 void OpenSLESOutputStream::SetMute(bool muted) {
181   DVLOG(2) << "OpenSLESOutputStream::SetMute(" << muted << ")";
182   DCHECK(thread_checker_.CalledOnValidThread());
183   muted_ = muted;
184 }
185
186 bool OpenSLESOutputStream::CreatePlayer() {
187   DCHECK(thread_checker_.CalledOnValidThread());
188   DCHECK(!engine_object_.Get());
189   DCHECK(!player_object_.Get());
190   DCHECK(!output_mixer_.Get());
191   DCHECK(!player_);
192   DCHECK(!simple_buffer_queue_);
193
194   // Initializes the engine object with specific option. After working with the
195   // object, we need to free the object and its resources.
196   SLEngineOption option[] = {
197       {SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE)}};
198   LOG_ON_FAILURE_AND_RETURN(
199       slCreateEngine(engine_object_.Receive(), 1, option, 0, NULL, NULL),
200       false);
201
202   // Realize the SL engine object in synchronous mode.
203   LOG_ON_FAILURE_AND_RETURN(
204       engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE), false);
205
206   // Get the SL engine interface which is implicit.
207   SLEngineItf engine;
208   LOG_ON_FAILURE_AND_RETURN(engine_object_->GetInterface(
209                                 engine_object_.Get(), SL_IID_ENGINE, &engine),
210                             false);
211
212   // Create ouput mixer object to be used by the player.
213   LOG_ON_FAILURE_AND_RETURN((*engine)->CreateOutputMix(
214                                 engine, output_mixer_.Receive(), 0, NULL, NULL),
215                             false);
216
217   // Realizing the output mix object in synchronous mode.
218   LOG_ON_FAILURE_AND_RETURN(
219       output_mixer_->Realize(output_mixer_.Get(), SL_BOOLEAN_FALSE), false);
220
221   // Audio source configuration.
222   SLDataLocator_AndroidSimpleBufferQueue simple_buffer_queue = {
223       SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
224       static_cast<SLuint32>(kMaxNumOfBuffersInQueue)};
225   SLDataSource audio_source = {&simple_buffer_queue, &format_};
226
227   // Audio sink configuration.
228   SLDataLocator_OutputMix locator_output_mix = {SL_DATALOCATOR_OUTPUTMIX,
229                                                 output_mixer_.Get()};
230   SLDataSink audio_sink = {&locator_output_mix, NULL};
231
232   // Create an audio player.
233   const SLInterfaceID interface_id[] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME,
234                                         SL_IID_ANDROIDCONFIGURATION};
235   const SLboolean interface_required[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE,
236                                           SL_BOOLEAN_TRUE};
237   LOG_ON_FAILURE_AND_RETURN(
238       (*engine)->CreateAudioPlayer(engine,
239                                    player_object_.Receive(),
240                                    &audio_source,
241                                    &audio_sink,
242                                    arraysize(interface_id),
243                                    interface_id,
244                                    interface_required),
245       false);
246
247   // Create AudioPlayer and specify SL_IID_ANDROIDCONFIGURATION.
248   SLAndroidConfigurationItf player_config;
249   LOG_ON_FAILURE_AND_RETURN(
250       player_object_->GetInterface(
251           player_object_.Get(), SL_IID_ANDROIDCONFIGURATION, &player_config),
252       false);
253
254   // Set configuration using the stream type provided at construction.
255   LOG_ON_FAILURE_AND_RETURN(
256       (*player_config)->SetConfiguration(player_config,
257                                          SL_ANDROID_KEY_STREAM_TYPE,
258                                          &stream_type_,
259                                          sizeof(SLint32)),
260       false);
261
262   // Realize the player object in synchronous mode.
263   LOG_ON_FAILURE_AND_RETURN(
264       player_object_->Realize(player_object_.Get(), SL_BOOLEAN_FALSE), false);
265
266   // Get an implicit player interface.
267   LOG_ON_FAILURE_AND_RETURN(
268       player_object_->GetInterface(player_object_.Get(), SL_IID_PLAY, &player_),
269       false);
270
271   // Get the simple buffer queue interface.
272   LOG_ON_FAILURE_AND_RETURN(
273       player_object_->GetInterface(
274           player_object_.Get(), SL_IID_BUFFERQUEUE, &simple_buffer_queue_),
275       false);
276
277   // Register the input callback for the simple buffer queue.
278   // This callback will be called when the soundcard needs data.
279   LOG_ON_FAILURE_AND_RETURN(
280       (*simple_buffer_queue_)->RegisterCallback(
281           simple_buffer_queue_, SimpleBufferQueueCallback, this),
282       false);
283
284   return true;
285 }
286
287 void OpenSLESOutputStream::SimpleBufferQueueCallback(
288     SLAndroidSimpleBufferQueueItf buffer_queue,
289     void* instance) {
290   OpenSLESOutputStream* stream =
291       reinterpret_cast<OpenSLESOutputStream*>(instance);
292   stream->FillBufferQueue();
293 }
294
295 void OpenSLESOutputStream::FillBufferQueue() {
296   base::AutoLock lock(lock_);
297   if (!started_)
298     return;
299
300   TRACE_EVENT0("audio", "OpenSLESOutputStream::FillBufferQueue");
301
302   // Verify that we are in a playing state.
303   SLuint32 state;
304   SLresult err = (*player_)->GetPlayState(player_, &state);
305   if (SL_RESULT_SUCCESS != err) {
306     HandleError(err);
307     return;
308   }
309   if (state != SL_PLAYSTATE_PLAYING) {
310     DLOG(WARNING) << "Received callback in non-playing state";
311     return;
312   }
313
314   // Fill up one buffer in the queue by asking the registered source for
315   // data using the OnMoreData() callback.
316   FillBufferQueueNoLock();
317 }
318
319 void OpenSLESOutputStream::FillBufferQueueNoLock() {
320   // Ensure that the calling thread has acquired the lock since it is not
321   // done in this method.
322   lock_.AssertAcquired();
323
324   // Read data from the registered client source.
325   // TODO(henrika): Investigate if it is possible to get a more accurate
326   // delay estimation.
327   const uint32 hardware_delay = buffer_size_bytes_;
328   int frames_filled = callback_->OnMoreData(
329       audio_bus_.get(), hardware_delay);
330   if (frames_filled <= 0) {
331     // Audio source is shutting down, or halted on error.
332     return;
333   }
334
335   // Note: If the internal representation ever changes from 16-bit PCM to
336   // raw float, the data must be clipped and sanitized since it may come
337   // from an untrusted source such as NaCl.
338   audio_bus_->Scale(muted_ ? 0.0f : volume_);
339   audio_bus_->ToInterleaved(frames_filled,
340                             format_.bitsPerSample / 8,
341                             audio_data_[active_buffer_index_]);
342
343   const int num_filled_bytes =
344       frames_filled * audio_bus_->channels() * format_.bitsPerSample / 8;
345   DCHECK_LE(static_cast<size_t>(num_filled_bytes), buffer_size_bytes_);
346
347   // Enqueue the buffer for playback.
348   SLresult err =
349       (*simple_buffer_queue_)->Enqueue(simple_buffer_queue_,
350                                        audio_data_[active_buffer_index_],
351                                        num_filled_bytes);
352   if (SL_RESULT_SUCCESS != err)
353     HandleError(err);
354
355   active_buffer_index_ = (active_buffer_index_ + 1) % kMaxNumOfBuffersInQueue;
356 }
357
358 void OpenSLESOutputStream::SetupAudioBuffer() {
359   DCHECK(thread_checker_.CalledOnValidThread());
360   DCHECK(!audio_data_[0]);
361   for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) {
362     audio_data_[i] = new uint8[buffer_size_bytes_];
363   }
364 }
365
366 void OpenSLESOutputStream::ReleaseAudioBuffer() {
367   DCHECK(thread_checker_.CalledOnValidThread());
368   if (audio_data_[0]) {
369     for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) {
370       delete[] audio_data_[i];
371       audio_data_[i] = NULL;
372     }
373   }
374 }
375
376 void OpenSLESOutputStream::HandleError(SLresult error) {
377   DLOG(ERROR) << "OpenSLES Output error " << error;
378   if (callback_)
379     callback_->OnError(this);
380 }
381
382 }  // namespace media