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