opensles_output.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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/logging.h"
8#include "media/audio/audio_util.h"
9#include "media/audio/android/audio_manager_android.h"
10
11namespace media {
12
13OpenSLESOutputStream::OpenSLESOutputStream(AudioManagerAndroid* manager,
14                                           const AudioParameters& params)
15    : audio_manager_(manager),
16      callback_(NULL),
17      player_(NULL),
18      simple_buffer_queue_(NULL),
19      active_queue_(0),
20      buffer_size_bytes_(0),
21      started_(false),
22      volume_(1.0) {
23  format_.formatType = SL_DATAFORMAT_PCM;
24  format_.numChannels = static_cast<SLuint32>(params.channels());
25  // Provides sampling rate in milliHertz to OpenSLES.
26  format_.samplesPerSec = static_cast<SLuint32>(params.sample_rate() * 1000);
27  format_.bitsPerSample = params.bits_per_sample();
28  format_.containerSize = params.bits_per_sample();
29  format_.endianness = SL_BYTEORDER_LITTLEENDIAN;
30  if (format_.numChannels == 1)
31    format_.channelMask = SL_SPEAKER_FRONT_CENTER;
32  else if (format_.numChannels == 2)
33    format_.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
34  else
35    NOTREACHED() << "Unsupported number of channels: " << format_.numChannels;
36
37  buffer_size_bytes_ = params.GetBytesPerBuffer();
38  audio_bus_ = AudioBus::Create(params);
39
40  memset(&audio_data_, 0, sizeof(audio_data_));
41}
42
43OpenSLESOutputStream::~OpenSLESOutputStream() {
44  DCHECK(!engine_object_.Get());
45  DCHECK(!player_object_.Get());
46  DCHECK(!output_mixer_.Get());
47  DCHECK(!player_);
48  DCHECK(!simple_buffer_queue_);
49  DCHECK(!audio_data_[0]);
50}
51
52bool OpenSLESOutputStream::Open() {
53  if (engine_object_.Get())
54    return false;
55
56  if (!CreatePlayer())
57    return false;
58
59  SetupAudioBuffer();
60
61  return true;
62}
63
64void OpenSLESOutputStream::Start(AudioSourceCallback* callback) {
65  DCHECK(callback);
66  DCHECK(player_);
67  DCHECK(simple_buffer_queue_);
68  if (started_)
69    return;
70
71  // Enable the flags before streaming.
72  callback_ = callback;
73  active_queue_ = 0;
74  started_ = true;
75
76  // Avoid start-up glitches by filling up one buffer queue before starting
77  // the stream.
78  FillBufferQueue();
79
80  // Start streaming data by setting the play state to |SL_PLAYSTATE_PLAYING|.
81  SLresult err = (*player_)->SetPlayState(player_, SL_PLAYSTATE_PLAYING);
82  DCHECK_EQ(SL_RESULT_SUCCESS, err);
83  if (SL_RESULT_SUCCESS != err) {
84    DLOG(WARNING) << "SetPlayState() failed to start playing";
85  }
86}
87
88void OpenSLESOutputStream::Stop() {
89  if (!started_)
90    return;
91
92  started_ = false;
93  // Stop playing by setting the play state to |SL_PLAYSTATE_STOPPED|.
94  SLresult err = (*player_)->SetPlayState(player_, SL_PLAYSTATE_STOPPED);
95  if (SL_RESULT_SUCCESS != err) {
96    DLOG(WARNING) << "SetPlayState() failed to set the state to stop";
97  }
98
99  // Clear the buffer queue so that the old data won't be played when
100  // resuming playing.
101  err = (*simple_buffer_queue_)->Clear(simple_buffer_queue_);
102  if (SL_RESULT_SUCCESS != err) {
103    DLOG(WARNING) << "Clear() failed to clear the buffer queue";
104  }
105}
106
107void OpenSLESOutputStream::Close() {
108  // Stop the stream if it is still playing.
109  Stop();
110
111  // Explicitly free the player objects and invalidate their associated
112  // interfaces. They have to be done in the correct order.
113  output_mixer_.Reset();
114  player_object_.Reset();
115  engine_object_.Reset();
116  simple_buffer_queue_ = NULL;
117  player_ = NULL;
118
119  ReleaseAudioBuffer();
120
121  audio_manager_->ReleaseOutputStream(this);
122}
123
124void OpenSLESOutputStream::SetVolume(double volume) {
125  float volume_float = static_cast<float>(volume);
126  if (volume_float < 0.0f || volume_float > 1.0f) {
127    return;
128  }
129  volume_ = volume_float;
130}
131
132void OpenSLESOutputStream::GetVolume(double* volume) {
133  *volume = static_cast<double>(volume_);
134}
135
136bool OpenSLESOutputStream::CreatePlayer() {
137  // Initializes the engine object with specific option. After working with the
138  // object, we need to free the object and its resources.
139  SLEngineOption option[] = {
140    { SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE) }
141  };
142  SLresult err = slCreateEngine(engine_object_.Receive(), 1, option, 0,
143                                NULL, NULL);
144  DCHECK_EQ(SL_RESULT_SUCCESS, err);
145  if (SL_RESULT_SUCCESS != err)
146    return false;
147
148  // Realize the SL engine object in synchronous mode.
149  err = engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE);
150  DCHECK_EQ(SL_RESULT_SUCCESS, err);
151  if (SL_RESULT_SUCCESS != err)
152    return false;
153
154  // Get the SL engine interface which is implicit.
155  SLEngineItf engine;
156  err = engine_object_->GetInterface(engine_object_.Get(),
157                                     SL_IID_ENGINE,
158                                     &engine);
159  DCHECK_EQ(SL_RESULT_SUCCESS, err);
160  if (SL_RESULT_SUCCESS != err)
161    return false;
162
163  // Create ouput mixer object to be used by the player.
164  // TODO(xians): Do we need the environmental reverb auxiliary effect?
165  err = (*engine)->CreateOutputMix(engine,
166                                   output_mixer_.Receive(),
167                                   0,
168                                   NULL,
169                                   NULL);
170  DCHECK_EQ(SL_RESULT_SUCCESS, err);
171  if (SL_RESULT_SUCCESS != err)
172    return false;
173
174  // Realizing the output mix object in synchronous mode.
175  err = output_mixer_->Realize(output_mixer_.Get(), SL_BOOLEAN_FALSE);
176  DCHECK_EQ(SL_RESULT_SUCCESS, err);
177  if (SL_RESULT_SUCCESS != err)
178    return false;
179
180  // Audio source configuration.
181  SLDataLocator_AndroidSimpleBufferQueue simple_buffer_queue = {
182    SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
183    static_cast<SLuint32>(kNumOfQueuesInBuffer)
184  };
185  SLDataSource audio_source = { &simple_buffer_queue, &format_ };
186
187  // Audio sink configuration.
188  SLDataLocator_OutputMix locator_output_mix = {
189    SL_DATALOCATOR_OUTPUTMIX, output_mixer_.Get()
190  };
191  SLDataSink audio_sink = { &locator_output_mix, NULL };
192
193  // Create an audio player.
194  const SLuint32 number_of_interfaces = 1;
195  const SLInterfaceID interface_id[number_of_interfaces] = {
196    SL_IID_BUFFERQUEUE
197  };
198  const SLboolean interface_required[number_of_interfaces] = {
199    SL_BOOLEAN_TRUE
200  };
201  err = (*engine)->CreateAudioPlayer(engine,
202                                     player_object_.Receive(),
203                                     &audio_source,
204                                     &audio_sink,
205                                     number_of_interfaces,
206                                     interface_id,
207                                     interface_required);
208  DCHECK_EQ(SL_RESULT_SUCCESS, err);
209  if (SL_RESULT_SUCCESS != err) {
210    DLOG(ERROR) << "CreateAudioPlayer() failed with error code " << err;
211    return false;
212  }
213
214  // Realize the player object in synchronous mode.
215  err = player_object_->Realize(player_object_.Get(), SL_BOOLEAN_FALSE);
216  DCHECK_EQ(SL_RESULT_SUCCESS, err);
217  if (SL_RESULT_SUCCESS != err) {
218    DLOG(ERROR) << "Player Realize() failed with error code " << err;
219    return false;
220  }
221
222  // Get an implicit player interface.
223  err = player_object_->GetInterface(
224      player_object_.Get(), SL_IID_PLAY, &player_);
225  DCHECK_EQ(SL_RESULT_SUCCESS, err);
226  if (SL_RESULT_SUCCESS != err)
227    return false;
228
229  // Get the simple buffer queue interface.
230  err = player_object_->GetInterface(player_object_.Get(),
231                                     SL_IID_BUFFERQUEUE,
232                                     &simple_buffer_queue_);
233  DCHECK_EQ(SL_RESULT_SUCCESS, err);
234  if (SL_RESULT_SUCCESS != err)
235    return false;
236
237  // Register the input callback for the simple buffer queue.
238  // This callback will be called when the soundcard needs data.
239  err = (*simple_buffer_queue_)->RegisterCallback(simple_buffer_queue_,
240                                                  SimpleBufferQueueCallback,
241                                                  this);
242  DCHECK_EQ(SL_RESULT_SUCCESS, err);
243
244  return (SL_RESULT_SUCCESS == err);
245}
246
247void OpenSLESOutputStream::SimpleBufferQueueCallback(
248    SLAndroidSimpleBufferQueueItf buffer_queue, void* instance) {
249  OpenSLESOutputStream* stream =
250      reinterpret_cast<OpenSLESOutputStream*>(instance);
251  stream->FillBufferQueue();
252}
253
254void OpenSLESOutputStream::FillBufferQueue() {
255  if (!started_)
256    return;
257
258  // Read data from the registered client source.
259  // TODO(xians): Get an accurate delay estimation.
260  uint32 hardware_delay = buffer_size_bytes_;
261  int frames_filled = callback_->OnMoreData(
262      audio_bus_.get(), AudioBuffersState(0, hardware_delay));
263  if (frames_filled <= 0)
264    return;  // Audio source is shutting down, or halted on error.
265  int num_filled_bytes =
266      frames_filled * audio_bus_->channels() * format_.bitsPerSample / 8;
267  DCHECK_LE(static_cast<size_t>(num_filled_bytes), buffer_size_bytes_);
268  // Note: If this ever changes to output raw float the data must be clipped and
269  // sanitized since it may come from an untrusted source such as NaCl.
270  audio_bus_->ToInterleaved(
271      frames_filled, format_.bitsPerSample / 8, audio_data_[active_queue_]);
272
273  // Perform in-place, software-volume adjustments.
274  media::AdjustVolume(audio_data_[active_queue_],
275                      num_filled_bytes,
276                      format_.numChannels,
277                      format_.bitsPerSample / 8,
278                      volume_);
279
280  // Enqueue the buffer for playback.
281  SLresult err = (*simple_buffer_queue_)->Enqueue(
282      simple_buffer_queue_,
283      audio_data_[active_queue_],
284      num_filled_bytes);
285  if (SL_RESULT_SUCCESS != err)
286    HandleError(err);
287
288  active_queue_ = (active_queue_  + 1) % kNumOfQueuesInBuffer;
289}
290
291void OpenSLESOutputStream::SetupAudioBuffer() {
292  DCHECK(!audio_data_[0]);
293  for (int i = 0; i < kNumOfQueuesInBuffer; ++i) {
294    audio_data_[i] = new uint8[buffer_size_bytes_];
295  }
296}
297
298void OpenSLESOutputStream::ReleaseAudioBuffer() {
299  if (audio_data_[0]) {
300    for (int i = 0; i < kNumOfQueuesInBuffer; ++i) {
301      delete [] audio_data_[i];
302      audio_data_[i] = NULL;
303    }
304  }
305}
306
307void OpenSLESOutputStream::HandleError(SLresult error) {
308  DLOG(ERROR) << "OpenSLES error " << error;
309  if (callback_)
310    callback_->OnError(this);
311}
312
313}  // namespace media
314