opensles_input.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
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) << "OpenSLESInputStream::OpenSLESInputStream()";
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) << "OpenSLESInputStream::~OpenSLESInputStream()";
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) << "OpenSLESInputStream::Open()";
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) << "OpenSLESInputStream::Start()";
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) << "OpenSLESInputStream::Stop()";
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}
136
137void OpenSLESInputStream::Close() {
138  DVLOG(2) << "OpenSLESInputStream::Close()";
139  DCHECK(thread_checker_.CalledOnValidThread());
140
141  // Stop the stream if it is still recording.
142  Stop();
143  {
144    base::AutoLock lock(lock_);
145
146    // TODO(henrika): we use |callback_| in Close() but |callback_| is set
147    // in Start(). Hence, it should be cleared in Stop() and not used here.
148    if (callback_) {
149      callback_->OnClose(this);
150      callback_ = NULL;
151    }
152
153    // Destroy the buffer queue recorder object and invalidate all associated
154    // interfaces.
155    recorder_object_.Reset();
156    simple_buffer_queue_ = NULL;
157    recorder_ = NULL;
158
159    // Destroy the engine object. We don't store any associated interface for
160    // this object.
161    engine_object_.Reset();
162    ReleaseAudioBuffer();
163  }
164
165  audio_manager_->ReleaseInputStream(this);
166}
167
168double OpenSLESInputStream::GetMaxVolume() {
169  NOTIMPLEMENTED();
170  return 0.0;
171}
172
173void OpenSLESInputStream::SetVolume(double volume) { NOTIMPLEMENTED(); }
174
175double OpenSLESInputStream::GetVolume() {
176  NOTIMPLEMENTED();
177  return 0.0;
178}
179
180void OpenSLESInputStream::SetAutomaticGainControl(bool enabled) {
181  NOTIMPLEMENTED();
182}
183
184bool OpenSLESInputStream::GetAutomaticGainControl() {
185  NOTIMPLEMENTED();
186  return false;
187}
188
189bool OpenSLESInputStream::CreateRecorder() {
190  DCHECK(thread_checker_.CalledOnValidThread());
191  DCHECK(!engine_object_.Get());
192  DCHECK(!recorder_object_.Get());
193  DCHECK(!recorder_);
194  DCHECK(!simple_buffer_queue_);
195
196  // Initializes the engine object with specific option. After working with the
197  // object, we need to free the object and its resources.
198  SLEngineOption option[] = {
199      {SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE)}};
200  LOG_ON_FAILURE_AND_RETURN(
201      slCreateEngine(engine_object_.Receive(), 1, option, 0, NULL, NULL),
202      false);
203
204  // Realize the SL engine object in synchronous mode.
205  LOG_ON_FAILURE_AND_RETURN(
206      engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE), false);
207
208  // Get the SL engine interface which is implicit.
209  SLEngineItf engine;
210  LOG_ON_FAILURE_AND_RETURN(engine_object_->GetInterface(
211                                engine_object_.Get(), SL_IID_ENGINE, &engine),
212                            false);
213
214  // Audio source configuration.
215  SLDataLocator_IODevice mic_locator = {
216      SL_DATALOCATOR_IODEVICE,       SL_IODEVICE_AUDIOINPUT,
217      SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};
218  SLDataSource audio_source = {&mic_locator, NULL};
219
220  // Audio sink configuration.
221  SLDataLocator_AndroidSimpleBufferQueue buffer_queue = {
222      SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
223      static_cast<SLuint32>(kMaxNumOfBuffersInQueue)};
224  SLDataSink audio_sink = {&buffer_queue, &format_};
225
226  // Create an audio recorder.
227  const SLInterfaceID interface_id[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
228                                        SL_IID_ANDROIDCONFIGURATION};
229  const SLboolean interface_required[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
230
231  // Create AudioRecorder and specify SL_IID_ANDROIDCONFIGURATION.
232  LOG_ON_FAILURE_AND_RETURN(
233      (*engine)->CreateAudioRecorder(engine,
234                                     recorder_object_.Receive(),
235                                     &audio_source,
236                                     &audio_sink,
237                                     arraysize(interface_id),
238                                     interface_id,
239                                     interface_required),
240      false);
241
242  SLAndroidConfigurationItf recorder_config;
243  LOG_ON_FAILURE_AND_RETURN(
244      recorder_object_->GetInterface(recorder_object_.Get(),
245                                     SL_IID_ANDROIDCONFIGURATION,
246                                     &recorder_config),
247      false);
248
249  // Uses the main microphone tuned for audio communications.
250  SLint32 stream_type = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION;
251  LOG_ON_FAILURE_AND_RETURN(
252      (*recorder_config)->SetConfiguration(recorder_config,
253                                           SL_ANDROID_KEY_RECORDING_PRESET,
254                                           &stream_type,
255                                           sizeof(SLint32)),
256      false);
257
258  // Realize the recorder object in synchronous mode.
259  LOG_ON_FAILURE_AND_RETURN(
260      recorder_object_->Realize(recorder_object_.Get(), SL_BOOLEAN_FALSE),
261      false);
262
263  // Get an implicit recorder interface.
264  LOG_ON_FAILURE_AND_RETURN(
265      recorder_object_->GetInterface(
266          recorder_object_.Get(), SL_IID_RECORD, &recorder_),
267      false);
268
269  // Get the simple buffer queue interface.
270  LOG_ON_FAILURE_AND_RETURN(
271      recorder_object_->GetInterface(recorder_object_.Get(),
272                                     SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
273                                     &simple_buffer_queue_),
274      false);
275
276  // Register the input callback for the simple buffer queue.
277  // This callback will be called when receiving new data from the device.
278  LOG_ON_FAILURE_AND_RETURN(
279      (*simple_buffer_queue_)->RegisterCallback(
280          simple_buffer_queue_, SimpleBufferQueueCallback, this),
281      false);
282
283  return true;
284}
285
286void OpenSLESInputStream::SimpleBufferQueueCallback(
287    SLAndroidSimpleBufferQueueItf buffer_queue,
288    void* instance) {
289  OpenSLESInputStream* stream =
290      reinterpret_cast<OpenSLESInputStream*>(instance);
291  stream->ReadBufferQueue();
292}
293
294void OpenSLESInputStream::ReadBufferQueue() {
295  base::AutoLock lock(lock_);
296  if (!started_)
297    return;
298
299  TRACE_EVENT0("audio", "OpenSLESOutputStream::ReadBufferQueue");
300
301  // TODO(henrika): Investigate if it is possible to get an accurate
302  // delay estimation.
303  callback_->OnData(this,
304                    audio_data_[active_buffer_index_],
305                    buffer_size_bytes_,
306                    buffer_size_bytes_,
307                    0.0);
308
309  // Done with this buffer. Send it to device for recording.
310  SLresult err =
311      (*simple_buffer_queue_)->Enqueue(simple_buffer_queue_,
312                                       audio_data_[active_buffer_index_],
313                                       buffer_size_bytes_);
314  if (SL_RESULT_SUCCESS != err)
315    HandleError(err);
316
317  active_buffer_index_ = (active_buffer_index_ + 1) % kMaxNumOfBuffersInQueue;
318}
319
320void OpenSLESInputStream::SetupAudioBuffer() {
321  DCHECK(thread_checker_.CalledOnValidThread());
322  DCHECK(!audio_data_[0]);
323  for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) {
324    audio_data_[i] = new uint8[buffer_size_bytes_];
325  }
326}
327
328void OpenSLESInputStream::ReleaseAudioBuffer() {
329  DCHECK(thread_checker_.CalledOnValidThread());
330  if (audio_data_[0]) {
331    for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) {
332      delete[] audio_data_[i];
333      audio_data_[i] = NULL;
334    }
335  }
336}
337
338void OpenSLESInputStream::HandleError(SLresult error) {
339  DLOG(ERROR) << "OpenSLES Input error " << error;
340  if (callback_)
341    callback_->OnError(this);
342}
343
344}  // namespace media
345