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