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