opensles_input.cc revision ab8f6f0bd665d3c1ff476eb06c58c42630e462d4
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_input.h"
6
7#include "base/debug/trace_event.h"
8#include "base/logging.h"
9#include "media/audio/android/audio_manager_android.h"
10#include "media/base/audio_bus.h"
11
12#define LOG_ON_FAILURE_AND_RETURN(op, ...)      \
13  do {                                          \
14    SLresult err = (op);                        \
15    if (err != SL_RESULT_SUCCESS) {             \
16      DLOG(ERROR) << #op << " failed: " << err; \
17      return __VA_ARGS__;                       \
18    }                                           \
19  } while (0)
20
21namespace media {
22
23OpenSLESInputStream::OpenSLESInputStream(AudioManagerAndroid* audio_manager,
24                                         const AudioParameters& params)
25    : audio_manager_(audio_manager),
26      callback_(NULL),
27      recorder_(NULL),
28      simple_buffer_queue_(NULL),
29      active_buffer_index_(0),
30      buffer_size_bytes_(0),
31      started_(false),
32      audio_bus_(media::AudioBus::Create(params)) {
33  DVLOG(2) << __PRETTY_FUNCTION__;
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;
47
48  buffer_size_bytes_ = params.GetBytesPerBuffer();
49
50  memset(&audio_data_, 0, sizeof(audio_data_));
51}
52
53OpenSLESInputStream::~OpenSLESInputStream() {
54  DVLOG(2) << __PRETTY_FUNCTION__;
55  DCHECK(thread_checker_.CalledOnValidThread());
56  DCHECK(!recorder_object_.Get());
57  DCHECK(!engine_object_.Get());
58  DCHECK(!recorder_);
59  DCHECK(!simple_buffer_queue_);
60  DCHECK(!audio_data_[0]);
61}
62
63bool OpenSLESInputStream::Open() {
64  DVLOG(2) << __PRETTY_FUNCTION__;
65  DCHECK(thread_checker_.CalledOnValidThread());
66  if (engine_object_.Get())
67    return false;
68
69  if (!CreateRecorder())
70    return false;
71
72  SetupAudioBuffer();
73
74  return true;
75}
76
77void OpenSLESInputStream::Start(AudioInputCallback* callback) {
78  DVLOG(2) << __PRETTY_FUNCTION__;
79  DCHECK(thread_checker_.CalledOnValidThread());
80  DCHECK(callback);
81  DCHECK(recorder_);
82  DCHECK(simple_buffer_queue_);
83  if (started_)
84    return;
85
86  base::AutoLock lock(lock_);
87  DCHECK(callback_ == NULL || callback_ == callback);
88  callback_ = callback;
89  active_buffer_index_ = 0;
90
91  // Enqueues kMaxNumOfBuffersInQueue zero buffers to get the ball rolling.
92  // TODO(henrika): add support for Start/Stop/Start sequences when we are
93  // able to clear the buffer queue. There is currently a bug in the OpenSLES
94  // implementation which forces us to always call Stop() and Close() before
95  // calling Start() again.
96  SLresult err = SL_RESULT_UNKNOWN_ERROR;
97  for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) {
98    err = (*simple_buffer_queue_)->Enqueue(
99        simple_buffer_queue_, audio_data_[i], buffer_size_bytes_);
100    if (SL_RESULT_SUCCESS != err) {
101      HandleError(err);
102      started_ = false;
103      return;
104    }
105  }
106
107  // Start the recording by setting the state to SL_RECORDSTATE_RECORDING.
108  // When the object is in the SL_RECORDSTATE_RECORDING state, adding buffers
109  // will implicitly start the filling process.
110  err = (*recorder_)->SetRecordState(recorder_, SL_RECORDSTATE_RECORDING);
111  if (SL_RESULT_SUCCESS != err) {
112    HandleError(err);
113    started_ = false;
114    return;
115  }
116
117  started_ = true;
118}
119
120void OpenSLESInputStream::Stop() {
121  DVLOG(2) << __PRETTY_FUNCTION__;
122  DCHECK(thread_checker_.CalledOnValidThread());
123  if (!started_)
124    return;
125
126  base::AutoLock lock(lock_);
127
128  // Stop recording by setting the record state to SL_RECORDSTATE_STOPPED.
129  LOG_ON_FAILURE_AND_RETURN(
130      (*recorder_)->SetRecordState(recorder_, SL_RECORDSTATE_STOPPED));
131
132  // Clear the buffer queue to get rid of old data when resuming recording.
133  LOG_ON_FAILURE_AND_RETURN(
134      (*simple_buffer_queue_)->Clear(simple_buffer_queue_));
135
136  started_ = false;
137  callback_ = NULL;
138}
139
140void OpenSLESInputStream::Close() {
141  DVLOG(2) << __PRETTY_FUNCTION__;
142  DCHECK(thread_checker_.CalledOnValidThread());
143
144  // Stop the stream if it is still recording.
145  Stop();
146  {
147    // TODO(henrika): Do we need to hold the lock here?
148    base::AutoLock lock(lock_);
149
150    // Destroy the buffer queue recorder object and invalidate all associated
151    // interfaces.
152    recorder_object_.Reset();
153    simple_buffer_queue_ = NULL;
154    recorder_ = NULL;
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_->ReleaseInputStream(this);
163}
164
165double OpenSLESInputStream::GetMaxVolume() {
166  NOTIMPLEMENTED();
167  return 0.0;
168}
169
170void OpenSLESInputStream::SetVolume(double volume) {
171  NOTIMPLEMENTED();
172}
173
174double OpenSLESInputStream::GetVolume() {
175  NOTIMPLEMENTED();
176  return 0.0;
177}
178
179void OpenSLESInputStream::SetAutomaticGainControl(bool enabled) {
180  NOTIMPLEMENTED();
181}
182
183bool OpenSLESInputStream::GetAutomaticGainControl() {
184  NOTIMPLEMENTED();
185  return false;
186}
187
188bool OpenSLESInputStream::IsMuted() {
189  NOTIMPLEMENTED();
190  return false;
191}
192
193bool OpenSLESInputStream::CreateRecorder() {
194  DCHECK(thread_checker_.CalledOnValidThread());
195  DCHECK(!engine_object_.Get());
196  DCHECK(!recorder_object_.Get());
197  DCHECK(!recorder_);
198  DCHECK(!simple_buffer_queue_);
199
200  // Initializes the engine object with specific option. After working with the
201  // object, we need to free the object and its resources.
202  SLEngineOption option[] = {
203      {SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE)}};
204  LOG_ON_FAILURE_AND_RETURN(
205      slCreateEngine(engine_object_.Receive(), 1, option, 0, NULL, NULL),
206      false);
207
208  // Realize the SL engine object in synchronous mode.
209  LOG_ON_FAILURE_AND_RETURN(
210      engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE), false);
211
212  // Get the SL engine interface which is implicit.
213  SLEngineItf engine;
214  LOG_ON_FAILURE_AND_RETURN(engine_object_->GetInterface(
215                                engine_object_.Get(), SL_IID_ENGINE, &engine),
216                            false);
217
218  // Audio source configuration.
219  SLDataLocator_IODevice mic_locator = {
220      SL_DATALOCATOR_IODEVICE,       SL_IODEVICE_AUDIOINPUT,
221      SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};
222  SLDataSource audio_source = {&mic_locator, NULL};
223
224  // Audio sink configuration.
225  SLDataLocator_AndroidSimpleBufferQueue buffer_queue = {
226      SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
227      static_cast<SLuint32>(kMaxNumOfBuffersInQueue)};
228  SLDataSink audio_sink = {&buffer_queue, &format_};
229
230  // Create an audio recorder.
231  const SLInterfaceID interface_id[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
232                                        SL_IID_ANDROIDCONFIGURATION};
233  const SLboolean interface_required[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
234
235  // Create AudioRecorder and specify SL_IID_ANDROIDCONFIGURATION.
236  LOG_ON_FAILURE_AND_RETURN(
237      (*engine)->CreateAudioRecorder(engine,
238                                     recorder_object_.Receive(),
239                                     &audio_source,
240                                     &audio_sink,
241                                     arraysize(interface_id),
242                                     interface_id,
243                                     interface_required),
244      false);
245
246  SLAndroidConfigurationItf recorder_config;
247  LOG_ON_FAILURE_AND_RETURN(
248      recorder_object_->GetInterface(recorder_object_.Get(),
249                                     SL_IID_ANDROIDCONFIGURATION,
250                                     &recorder_config),
251      false);
252
253  // Uses the main microphone tuned for audio communications.
254  SLint32 stream_type = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION;
255  LOG_ON_FAILURE_AND_RETURN(
256      (*recorder_config)->SetConfiguration(recorder_config,
257                                           SL_ANDROID_KEY_RECORDING_PRESET,
258                                           &stream_type,
259                                           sizeof(SLint32)),
260      false);
261
262  // Realize the recorder object in synchronous mode.
263  LOG_ON_FAILURE_AND_RETURN(
264      recorder_object_->Realize(recorder_object_.Get(), SL_BOOLEAN_FALSE),
265      false);
266
267  // Get an implicit recorder interface.
268  LOG_ON_FAILURE_AND_RETURN(
269      recorder_object_->GetInterface(
270          recorder_object_.Get(), SL_IID_RECORD, &recorder_),
271      false);
272
273  // Get the simple buffer queue interface.
274  LOG_ON_FAILURE_AND_RETURN(
275      recorder_object_->GetInterface(recorder_object_.Get(),
276                                     SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
277                                     &simple_buffer_queue_),
278      false);
279
280  // Register the input callback for the simple buffer queue.
281  // This callback will be called when receiving new data from the device.
282  LOG_ON_FAILURE_AND_RETURN(
283      (*simple_buffer_queue_)->RegisterCallback(
284          simple_buffer_queue_, SimpleBufferQueueCallback, this),
285      false);
286
287  return true;
288}
289
290void OpenSLESInputStream::SimpleBufferQueueCallback(
291    SLAndroidSimpleBufferQueueItf buffer_queue,
292    void* instance) {
293  OpenSLESInputStream* stream =
294      reinterpret_cast<OpenSLESInputStream*>(instance);
295  stream->ReadBufferQueue();
296}
297
298void OpenSLESInputStream::ReadBufferQueue() {
299  base::AutoLock lock(lock_);
300  if (!started_)
301    return;
302
303  TRACE_EVENT0("audio", "OpenSLESOutputStream::ReadBufferQueue");
304
305  // Convert from interleaved format to deinterleaved audio bus format.
306  audio_bus_->FromInterleaved(audio_data_[active_buffer_index_],
307                              audio_bus_->frames(),
308                              format_.bitsPerSample / 8);
309
310  // TODO(henrika): Investigate if it is possible to get an accurate
311  // delay estimation.
312  callback_->OnData(this, audio_bus_.get(), buffer_size_bytes_, 0.0);
313
314  // Done with this buffer. Send it to device for recording.
315  SLresult err =
316      (*simple_buffer_queue_)->Enqueue(simple_buffer_queue_,
317                                       audio_data_[active_buffer_index_],
318                                       buffer_size_bytes_);
319  if (SL_RESULT_SUCCESS != err)
320    HandleError(err);
321
322  active_buffer_index_ = (active_buffer_index_ + 1) % kMaxNumOfBuffersInQueue;
323}
324
325void OpenSLESInputStream::SetupAudioBuffer() {
326  DCHECK(thread_checker_.CalledOnValidThread());
327  DCHECK(!audio_data_[0]);
328  for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) {
329    audio_data_[i] = new uint8[buffer_size_bytes_];
330  }
331}
332
333void OpenSLESInputStream::ReleaseAudioBuffer() {
334  DCHECK(thread_checker_.CalledOnValidThread());
335  if (audio_data_[0]) {
336    for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) {
337      delete[] audio_data_[i];
338      audio_data_[i] = NULL;
339    }
340  }
341}
342
343void OpenSLESInputStream::HandleError(SLresult error) {
344  DLOG(ERROR) << "OpenSLES Input error " << error;
345  if (callback_)
346    callback_->OnError(this);
347}
348
349}  // namespace media
350