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