opensles_input.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_input.h"
6
7#include "base/logging.h"
8#include "media/audio/android/audio_manager_android.h"
9
10#define LOG_ON_FAILURE_AND_RETURN(op, ...) \
11  do { \
12    SLresult err = (op);            \
13    if (err != SL_RESULT_SUCCESS) { \
14      DLOG(ERROR) << #op << " failed: " << err; \
15      return __VA_ARGS__; \
16    } \
17  } while (0)
18
19namespace media {
20
21OpenSLESInputStream::OpenSLESInputStream(AudioManagerAndroid* audio_manager,
22                                         const AudioParameters& params)
23    : audio_manager_(audio_manager),
24      callback_(NULL),
25      recorder_(NULL),
26      simple_buffer_queue_(NULL),
27      active_queue_(0),
28      buffer_size_bytes_(0),
29      started_(false) {
30  format_.formatType = SL_DATAFORMAT_PCM;
31  format_.numChannels = static_cast<SLuint32>(params.channels());
32  // Provides sampling rate in milliHertz to OpenSLES.
33  format_.samplesPerSec = static_cast<SLuint32>(params.sample_rate() * 1000);
34  format_.bitsPerSample = params.bits_per_sample();
35  format_.containerSize = params.bits_per_sample();
36  format_.endianness = SL_BYTEORDER_LITTLEENDIAN;
37  if (format_.numChannels == 1)
38    format_.channelMask = SL_SPEAKER_FRONT_CENTER;
39  else if (format_.numChannels == 2)
40    format_.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
41  else
42    NOTREACHED() << "Unsupported number of channels: " << format_.numChannels;
43
44  buffer_size_bytes_ = params.GetBytesPerBuffer();
45
46  memset(&audio_data_, 0, sizeof(audio_data_));
47}
48
49OpenSLESInputStream::~OpenSLESInputStream() {
50  DCHECK(!recorder_object_.Get());
51  DCHECK(!engine_object_.Get());
52  DCHECK(!recorder_);
53  DCHECK(!simple_buffer_queue_);
54  DCHECK(!audio_data_[0]);
55}
56
57bool OpenSLESInputStream::Open() {
58  if (engine_object_.Get())
59    return false;
60
61  if (!CreateRecorder())
62    return false;
63
64  SetupAudioBuffer();
65
66  return true;
67}
68
69void OpenSLESInputStream::Start(AudioInputCallback* callback) {
70  DCHECK(callback);
71  DCHECK(recorder_);
72  DCHECK(simple_buffer_queue_);
73  if (started_)
74    return;
75
76  // Enable the flags before streaming.
77  callback_ = callback;
78  active_queue_ = 0;
79  started_ = true;
80
81  SLresult err = SL_RESULT_UNKNOWN_ERROR;
82  // Enqueues |kNumOfQueuesInBuffer| zero buffers to get the ball rolling.
83  for (int i = 0; i < kNumOfQueuesInBuffer; ++i) {
84    err = (*simple_buffer_queue_)->Enqueue(
85        simple_buffer_queue_,
86        audio_data_[i],
87        buffer_size_bytes_);
88    if (SL_RESULT_SUCCESS != err) {
89      HandleError(err);
90      return;
91    }
92  }
93
94  // Start the recording by setting the state to |SL_RECORDSTATE_RECORDING|.
95  err = (*recorder_)->SetRecordState(recorder_, SL_RECORDSTATE_RECORDING);
96  if (SL_RESULT_SUCCESS != err)
97    HandleError(err);
98}
99
100void OpenSLESInputStream::Stop() {
101  if (!started_)
102    return;
103
104  // Stop recording by setting the record state to |SL_RECORDSTATE_STOPPED|.
105  LOG_ON_FAILURE_AND_RETURN(
106      (*recorder_)->SetRecordState(recorder_,
107                                   SL_RECORDSTATE_STOPPED));
108
109  // Clear the buffer queue to get rid of old data when resuming recording.
110  LOG_ON_FAILURE_AND_RETURN(
111      (*simple_buffer_queue_)->Clear(simple_buffer_queue_));
112
113  started_ = false;
114}
115
116void OpenSLESInputStream::Close() {
117  // Stop the stream if it is still recording.
118  Stop();
119
120  // Explicitly free the player objects and invalidate their associated
121  // interfaces. They have to be done in the correct order.
122  recorder_object_.Reset();
123  engine_object_.Reset();
124  simple_buffer_queue_ = NULL;
125  recorder_ = NULL;
126
127  ReleaseAudioBuffer();
128
129  audio_manager_->ReleaseInputStream(this);
130}
131
132double OpenSLESInputStream::GetMaxVolume() {
133  NOTIMPLEMENTED();
134  return 0.0;
135}
136
137void OpenSLESInputStream::SetVolume(double volume) {
138  NOTIMPLEMENTED();
139}
140
141double OpenSLESInputStream::GetVolume() {
142  NOTIMPLEMENTED();
143  return 0.0;
144}
145
146void OpenSLESInputStream::SetAutomaticGainControl(bool enabled) {
147  NOTIMPLEMENTED();
148}
149
150bool OpenSLESInputStream::GetAutomaticGainControl() {
151  NOTIMPLEMENTED();
152  return false;
153}
154
155bool OpenSLESInputStream::CreateRecorder() {
156  // Initializes the engine object with specific option. After working with the
157  // object, we need to free the object and its resources.
158  SLEngineOption option[] = {
159    { SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE) }
160  };
161  LOG_ON_FAILURE_AND_RETURN(slCreateEngine(engine_object_.Receive(),
162                                           1,
163                                           option,
164                                           0,
165                                           NULL,
166                                           NULL),
167                            false);
168
169  // Realize the SL engine object in synchronous mode.
170  LOG_ON_FAILURE_AND_RETURN(engine_object_->Realize(engine_object_.Get(),
171                                                    SL_BOOLEAN_FALSE),
172                            false);
173
174  // Get the SL engine interface which is implicit.
175  SLEngineItf engine;
176  LOG_ON_FAILURE_AND_RETURN(engine_object_->GetInterface(engine_object_.Get(),
177                                                         SL_IID_ENGINE,
178                                                         &engine),
179                            false);
180
181  // Audio source configuration.
182  SLDataLocator_IODevice mic_locator = {
183    SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
184    SL_DEFAULTDEVICEID_AUDIOINPUT, NULL
185  };
186  SLDataSource audio_source = { &mic_locator, NULL };
187
188  // Audio sink configuration.
189  SLDataLocator_AndroidSimpleBufferQueue buffer_queue = {
190    SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,  // Locator type.
191    static_cast<SLuint32>(kNumOfQueuesInBuffer)  // Number of buffers.
192  };
193  SLDataSink audio_sink = { &buffer_queue, &format_ };
194
195  // Create an audio recorder.
196  const SLInterfaceID interface_id[] = {
197    SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
198    SL_IID_ANDROIDCONFIGURATION
199  };
200  const SLboolean interface_required[] = {
201    SL_BOOLEAN_TRUE,
202    SL_BOOLEAN_TRUE
203  };
204  // Create AudioRecorder and specify SL_IID_ANDROIDCONFIGURATION.
205  LOG_ON_FAILURE_AND_RETURN(
206      (*engine)->CreateAudioRecorder(engine,
207                                     recorder_object_.Receive(),
208                                     &audio_source,
209                                     &audio_sink,
210                                     arraysize(interface_id),
211                                     interface_id,
212                                     interface_required),
213      false);
214
215  SLAndroidConfigurationItf recorder_config;
216  LOG_ON_FAILURE_AND_RETURN(
217      recorder_object_->GetInterface(recorder_object_.Get(),
218                                     SL_IID_ANDROIDCONFIGURATION,
219                                     &recorder_config),
220      false);
221
222  SLint32 stream_type = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION;
223  LOG_ON_FAILURE_AND_RETURN(
224      (*recorder_config)->SetConfiguration(recorder_config,
225                                           SL_ANDROID_KEY_RECORDING_PRESET,
226                                           &stream_type, sizeof(SLint32)),
227      false);
228
229  // Realize the recorder object in synchronous mode.
230  LOG_ON_FAILURE_AND_RETURN(
231      recorder_object_->Realize(recorder_object_.Get(),
232                                SL_BOOLEAN_FALSE),
233      false);
234
235  // Get an implicit recorder interface.
236  LOG_ON_FAILURE_AND_RETURN(
237      recorder_object_->GetInterface(recorder_object_.Get(),
238                                     SL_IID_RECORD,
239                                     &recorder_),
240      false);
241
242  // Get the simple buffer queue interface.
243  LOG_ON_FAILURE_AND_RETURN(
244      recorder_object_->GetInterface(recorder_object_.Get(),
245                                     SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
246                                     &simple_buffer_queue_),
247      false);
248
249  // Register the input callback for the simple buffer queue.
250  // This callback will be called when receiving new data from the device.
251  LOG_ON_FAILURE_AND_RETURN(
252      (*simple_buffer_queue_)->RegisterCallback(simple_buffer_queue_,
253                                                SimpleBufferQueueCallback,
254                                                this),
255      false);
256
257  return true;
258}
259
260void OpenSLESInputStream::SimpleBufferQueueCallback(
261    SLAndroidSimpleBufferQueueItf buffer_queue, void* instance) {
262  OpenSLESInputStream* stream =
263      reinterpret_cast<OpenSLESInputStream*>(instance);
264  stream->ReadBufferQueue();
265}
266
267void OpenSLESInputStream::ReadBufferQueue() {
268  if (!started_)
269    return;
270
271  // TODO(xians): Get an accurate delay estimation.
272  callback_->OnData(this,
273                    audio_data_[active_queue_],
274                    buffer_size_bytes_,
275                    buffer_size_bytes_,
276                    0.0);
277
278  // Done with this buffer. Send it to device for recording.
279  SLresult err = (*simple_buffer_queue_)->Enqueue(
280      simple_buffer_queue_,
281      audio_data_[active_queue_],
282      buffer_size_bytes_);
283  if (SL_RESULT_SUCCESS != err)
284    HandleError(err);
285
286  active_queue_ = (active_queue_ + 1) % kNumOfQueuesInBuffer;
287}
288
289void OpenSLESInputStream::SetupAudioBuffer() {
290  DCHECK(!audio_data_[0]);
291  for (int i = 0; i < kNumOfQueuesInBuffer; ++i) {
292    audio_data_[i] = new uint8[buffer_size_bytes_];
293  }
294}
295
296void OpenSLESInputStream::ReleaseAudioBuffer() {
297  if (audio_data_[0]) {
298    for (int i = 0; i < kNumOfQueuesInBuffer; ++i) {
299      delete [] audio_data_[i];
300      audio_data_[i] = NULL;
301    }
302  }
303}
304
305void OpenSLESInputStream::HandleError(SLresult error) {
306  DLOG(FATAL) << "OpenSLES Input error " << error;
307  if (callback_)
308    callback_->OnError(this);
309}
310
311}  // namespace media
312