blob: ef6e7b62280c7d3da2273ea08e4edce121f3aa33 [file] [log] [blame]
henrike@webrtc.org82f014a2013-09-10 18:24:07 +00001/*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/modules/audio_device/android/opensles_input.h"
12
13#include <assert.h>
14
15#include "webrtc/modules/audio_device/android/single_rw_fifo.h"
16#include "webrtc/modules/audio_device/audio_device_buffer.h"
17#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
18#include "webrtc/system_wrappers/interface/thread_wrapper.h"
19#include "webrtc/system_wrappers/interface/trace.h"
20
21using webrtc_opensl::kDefaultSampleRate;
22using webrtc_opensl::kNumChannels;
23
24#define VOID_RETURN
25#define OPENSL_RETURN_ON_FAILURE(op, ret_val) \
26 do { \
27 SLresult err = (op); \
28 if (err != SL_RESULT_SUCCESS) { \
29 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, id_, \
30 "OpenSL error: %d", err); \
31 assert(false); \
32 return ret_val; \
33 } \
34 } while (0)
35
36static const SLEngineOption kOption[] = {
37 { SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE) },
38};
39
40enum {
41 kNoOverrun,
42 kOverrun,
43};
44
45namespace webrtc {
46
47OpenSlesInput::OpenSlesInput(
48 const int32_t id,
49 webrtc_opensl::PlayoutDelayProvider* delay_provider)
50 : id_(id),
51 delay_provider_(delay_provider),
52 initialized_(false),
53 mic_initialized_(false),
54 rec_initialized_(false),
55 crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
56 recording_(false),
57 num_fifo_buffers_needed_(0),
58 number_overruns_(0),
59 sles_engine_(NULL),
60 sles_engine_itf_(NULL),
61 sles_recorder_(NULL),
62 sles_recorder_itf_(NULL),
63 sles_recorder_sbq_itf_(NULL),
64 audio_buffer_(NULL),
65 active_queue_(0),
66 agc_enabled_(false),
67 recording_delay_(0) {
68}
69
70OpenSlesInput::~OpenSlesInput() {
71}
72
73int32_t OpenSlesInput::Init() {
74 assert(!initialized_);
75
76 // Set up OpenSL engine.
77 OPENSL_RETURN_ON_FAILURE(slCreateEngine(&sles_engine_, 1, kOption, 0,
78 NULL, NULL),
79 -1);
80 OPENSL_RETURN_ON_FAILURE((*sles_engine_)->Realize(sles_engine_,
81 SL_BOOLEAN_FALSE),
82 -1);
83 OPENSL_RETURN_ON_FAILURE((*sles_engine_)->GetInterface(sles_engine_,
84 SL_IID_ENGINE,
85 &sles_engine_itf_),
86 -1);
87
88 if (InitSampleRate() != 0) {
89 return -1;
90 }
91 AllocateBuffers();
92 initialized_ = true;
93 return 0;
94}
95
96int32_t OpenSlesInput::Terminate() {
97 // It is assumed that the caller has stopped recording before terminating.
98 assert(!recording_);
99 (*sles_engine_)->Destroy(sles_engine_);
100 initialized_ = false;
101 mic_initialized_ = false;
102 rec_initialized_ = false;
103 return 0;
104}
105
106int32_t OpenSlesInput::RecordingDeviceName(uint16_t index,
107 char name[kAdmMaxDeviceNameSize],
108 char guid[kAdmMaxGuidSize]) {
109 assert(index == 0);
110 // Empty strings.
111 name[0] = '\0';
112 guid[0] = '\0';
113 return 0;
114}
115
116int32_t OpenSlesInput::SetRecordingDevice(uint16_t index) {
117 assert(index == 0);
118 return 0;
119}
120
121int32_t OpenSlesInput::RecordingIsAvailable(bool& available) { // NOLINT
122 available = true;
123 return 0;
124}
125
126int32_t OpenSlesInput::InitRecording() {
127 assert(initialized_);
128 assert(!rec_initialized_);
129 rec_initialized_ = true;
130 return 0;
131}
132
133int32_t OpenSlesInput::StartRecording() {
134 assert(rec_initialized_);
135 assert(!recording_);
136 if (!CreateAudioRecorder()) {
137 return -1;
138 }
139 // Setup to receive buffer queue event callbacks.
140 OPENSL_RETURN_ON_FAILURE(
141 (*sles_recorder_sbq_itf_)->RegisterCallback(
142 sles_recorder_sbq_itf_,
143 RecorderSimpleBufferQueueCallback,
144 this),
145 -1);
146
147 if (!EnqueueAllBuffers()) {
148 return -1;
149 }
150
151 {
152 // To prevent the compiler from e.g. optimizing the code to
153 // recording_ = StartCbThreads() which wouldn't have been thread safe.
154 CriticalSectionScoped lock(crit_sect_.get());
155 recording_ = true;
156 }
157 if (!StartCbThreads()) {
158 recording_ = false;
159 return -1;
160 }
161 return 0;
162}
163
164int32_t OpenSlesInput::StopRecording() {
165 StopCbThreads();
166 DestroyAudioRecorder();
167 return 0;
168}
169
170int32_t OpenSlesInput::SetAGC(bool enable) {
171 agc_enabled_ = enable;
172 return 0;
173}
174
175int32_t OpenSlesInput::MicrophoneIsAvailable(bool& available) { // NOLINT
176 available = true;
177 return 0;
178}
179
180int32_t OpenSlesInput::InitMicrophone() {
181 assert(initialized_);
182 assert(!recording_);
183 mic_initialized_ = true;
184 return 0;
185}
186
187int32_t OpenSlesInput::MicrophoneVolumeIsAvailable(bool& available) { // NOLINT
188 available = false;
189 return 0;
190}
191
192int32_t OpenSlesInput::MinMicrophoneVolume(
193 uint32_t& minVolume) const { // NOLINT
194 minVolume = 0;
195 return 0;
196}
197
198int32_t OpenSlesInput::MicrophoneVolumeStepSize(
199 uint16_t& stepSize) const {
200 stepSize = 1;
201 return 0;
202}
203
204int32_t OpenSlesInput::MicrophoneMuteIsAvailable(bool& available) { // NOLINT
205 available = false; // Mic mute not supported on Android
206 return 0;
207}
208
209int32_t OpenSlesInput::MicrophoneBoostIsAvailable(bool& available) { // NOLINT
210 available = false; // Mic boost not supported on Android.
211 return 0;
212}
213
214int32_t OpenSlesInput::SetMicrophoneBoost(bool enable) {
215 assert(false);
216 return -1; // Not supported
217}
218
219int32_t OpenSlesInput::MicrophoneBoost(bool& enabled) const { // NOLINT
220 assert(false);
221 return -1; // Not supported
222}
223
224int32_t OpenSlesInput::StereoRecordingIsAvailable(bool& available) { // NOLINT
225 available = false; // Stereo recording not supported on Android.
226 return 0;
227}
228
229int32_t OpenSlesInput::StereoRecording(bool& enabled) const { // NOLINT
230 enabled = false;
231 return 0;
232}
233
234int32_t OpenSlesInput::RecordingDelay(uint16_t& delayMS) const { // NOLINT
235 delayMS = recording_delay_;
236 return 0;
237}
238
239void OpenSlesInput::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
240 audio_buffer_ = audioBuffer;
241}
242
243int32_t OpenSlesInput::InitSampleRate() {
244 audio_buffer_->SetRecordingSampleRate(kDefaultSampleRate);
245 audio_buffer_->SetRecordingChannels(kNumChannels);
246 UpdateRecordingDelay();
247 return 0;
248}
249
250void OpenSlesInput::UpdateRecordingDelay() {
251 // TODO(hellner): Add accurate delay estimate.
252 // On average half the current buffer will have been filled with audio.
253 int outstanding_samples =
254 (TotalBuffersUsed() - 0.5) * kDefaultBufSizeInSamples;
255 recording_delay_ = outstanding_samples / (kDefaultSampleRate / 1000);
256}
257
258void OpenSlesInput::CalculateNumFifoBuffersNeeded() {
259 // Buffer size is 10ms of data.
260 num_fifo_buffers_needed_ = kNum10MsToBuffer;
261}
262
263void OpenSlesInput::AllocateBuffers() {
264 // Allocate FIFO to handle passing buffers between processing and OpenSL
265 // threads.
266 CalculateNumFifoBuffersNeeded();
267 assert(num_fifo_buffers_needed_ > 0);
268 fifo_.reset(new SingleRwFifo(num_fifo_buffers_needed_));
269
270 // Allocate the memory area to be used.
271 rec_buf_.reset(new scoped_array<int8_t>[TotalBuffersUsed()]);
272 for (int i = 0; i < TotalBuffersUsed(); ++i) {
273 rec_buf_[i].reset(new int8_t[kDefaultBufSizeInBytes]);
274 }
275}
276
277int OpenSlesInput::TotalBuffersUsed() const {
278 return num_fifo_buffers_needed_ + kNumOpenSlBuffers;
279}
280
281bool OpenSlesInput::EnqueueAllBuffers() {
282 active_queue_ = 0;
283 number_overruns_ = 0;
284 for (int i = 0; i < kNumOpenSlBuffers; ++i) {
285 memset(rec_buf_[i].get(), 0, kDefaultBufSizeInBytes);
286 OPENSL_RETURN_ON_FAILURE(
287 (*sles_recorder_sbq_itf_)->Enqueue(
288 sles_recorder_sbq_itf_,
289 reinterpret_cast<void*>(rec_buf_[i].get()),
290 kDefaultBufSizeInBytes),
291 false);
292 }
293 // In case of underrun the fifo will be at capacity. In case of first enqueue
294 // no audio can have been returned yet meaning fifo must be empty. Any other
295 // values are unexpected.
296 assert(fifo_->size() == fifo_->capacity() ||
297 fifo_->size() == 0);
298 // OpenSL recording has been stopped. I.e. only this thread is touching
299 // |fifo_|.
300 while (fifo_->size() != 0) {
301 // Clear the fifo.
302 fifo_->Pop();
303 }
304 return true;
305}
306
307bool OpenSlesInput::CreateAudioRecorder() {
308 if (!event_.Start()) {
309 assert(false);
310 return false;
311 }
312 SLDataLocator_IODevice micLocator = {
313 SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
314 SL_DEFAULTDEVICEID_AUDIOINPUT, NULL };
315 SLDataSource audio_source = { &micLocator, NULL };
316
317 SLDataLocator_AndroidSimpleBufferQueue simple_buf_queue = {
318 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
319 static_cast<SLuint32>(TotalBuffersUsed())
320 };
321 SLDataFormat_PCM configuration =
322 webrtc_opensl::CreatePcmConfiguration(kDefaultSampleRate);
323 SLDataSink audio_sink = { &simple_buf_queue, &configuration };
324
325 // Interfaces for recording android audio data and Android are needed.
326 // Note the interfaces still need to be initialized. This only tells OpenSl
327 // that the interfaces will be needed at some point.
328 const SLInterfaceID id[kNumInterfaces] = {
329 SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION };
330 const SLboolean req[kNumInterfaces] = {
331 SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
332 OPENSL_RETURN_ON_FAILURE(
333 (*sles_engine_itf_)->CreateAudioRecorder(sles_engine_itf_,
334 &sles_recorder_,
335 &audio_source,
336 &audio_sink,
337 kNumInterfaces,
338 id,
339 req),
340 false);
341
342 // Realize the recorder in synchronous mode.
343 OPENSL_RETURN_ON_FAILURE((*sles_recorder_)->Realize(sles_recorder_,
344 SL_BOOLEAN_FALSE),
345 false);
346 OPENSL_RETURN_ON_FAILURE(
347 (*sles_recorder_)->GetInterface(sles_recorder_, SL_IID_RECORD,
348 static_cast<void*>(&sles_recorder_itf_)),
349 false);
350 OPENSL_RETURN_ON_FAILURE(
351 (*sles_recorder_)->GetInterface(
352 sles_recorder_,
353 SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
354 static_cast<void*>(&sles_recorder_sbq_itf_)),
355 false);
356 return true;
357}
358
359void OpenSlesInput::DestroyAudioRecorder() {
360 event_.Stop();
361 if (sles_recorder_sbq_itf_) {
362 // Release all buffers currently queued up.
363 OPENSL_RETURN_ON_FAILURE(
364 (*sles_recorder_sbq_itf_)->Clear(sles_recorder_sbq_itf_),
365 VOID_RETURN);
366 sles_recorder_sbq_itf_ = NULL;
367 }
368 sles_recorder_itf_ = NULL;
369
henrike@webrtc.org6138c5c2013-09-11 18:50:06 +0000370 if (sles_recorder_) {
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000371 (*sles_recorder_)->Destroy(sles_recorder_);
372 sles_recorder_ = NULL;
373 }
374}
375
376bool OpenSlesInput::HandleOverrun(int event_id, int event_msg) {
377 if (!recording_) {
378 return false;
379 }
380 if (event_id == kNoOverrun) {
381 return false;
382 }
383 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, id_, "Audio overrun");
384 assert(event_id == kOverrun);
385 assert(event_msg > 0);
386 // Wait for all enqueued buffers be flushed.
387 if (event_msg != kNumOpenSlBuffers) {
388 return true;
389 }
390 // All buffers passed to OpenSL have been flushed. Restart the audio from
391 // scratch.
392 // No need to check sles_recorder_itf_ as recording_ would be false before it
393 // is set to NULL.
394 OPENSL_RETURN_ON_FAILURE(
395 (*sles_recorder_itf_)->SetRecordState(sles_recorder_itf_,
396 SL_RECORDSTATE_STOPPED),
397 true);
398 EnqueueAllBuffers();
399 OPENSL_RETURN_ON_FAILURE(
400 (*sles_recorder_itf_)->SetRecordState(sles_recorder_itf_,
401 SL_RECORDSTATE_RECORDING),
402 true);
403 return true;
404}
405
406void OpenSlesInput::RecorderSimpleBufferQueueCallback(
407 SLAndroidSimpleBufferQueueItf queue_itf,
408 void* context) {
409 OpenSlesInput* audio_device = reinterpret_cast<OpenSlesInput*>(context);
410 audio_device->RecorderSimpleBufferQueueCallbackHandler(queue_itf);
411}
412
413void OpenSlesInput::RecorderSimpleBufferQueueCallbackHandler(
414 SLAndroidSimpleBufferQueueItf queue_itf) {
415 if (fifo_->size() >= fifo_->capacity() || number_overruns_ > 0) {
416 ++number_overruns_;
417 event_.SignalEvent(kOverrun, number_overruns_);
418 return;
419 }
420 int8_t* audio = rec_buf_[active_queue_].get();
421 // There is at least one spot available in the fifo.
422 fifo_->Push(audio);
423 active_queue_ = (active_queue_ + 1) % TotalBuffersUsed();
424 event_.SignalEvent(kNoOverrun, 0);
425 // active_queue_ is indexing the next buffer to record to. Since the current
426 // buffer has been recorded it means that the buffer index
427 // kNumOpenSlBuffers - 1 past |active_queue_| contains the next free buffer.
428 // Since |fifo_| wasn't at capacity, at least one buffer is free to be used.
429 int next_free_buffer =
430 (active_queue_ + kNumOpenSlBuffers - 1) % TotalBuffersUsed();
431 OPENSL_RETURN_ON_FAILURE(
432 (*sles_recorder_sbq_itf_)->Enqueue(
433 sles_recorder_sbq_itf_,
434 reinterpret_cast<void*>(rec_buf_[next_free_buffer].get()),
435 kDefaultBufSizeInBytes),
436 VOID_RETURN);
437}
438
439bool OpenSlesInput::StartCbThreads() {
440 rec_thread_.reset(ThreadWrapper::CreateThread(CbThread,
441 this,
442 kRealtimePriority,
443 "opensl_rec_thread"));
444 assert(rec_thread_.get());
445 unsigned int thread_id = 0;
446 if (!rec_thread_->Start(thread_id)) {
447 assert(false);
448 return false;
449 }
450 OPENSL_RETURN_ON_FAILURE(
451 (*sles_recorder_itf_)->SetRecordState(sles_recorder_itf_,
452 SL_RECORDSTATE_RECORDING),
453 false);
454 return true;
455}
456
457void OpenSlesInput::StopCbThreads() {
458 {
459 CriticalSectionScoped lock(crit_sect_.get());
460 recording_ = false;
461 }
462 if (sles_recorder_itf_) {
463 OPENSL_RETURN_ON_FAILURE(
464 (*sles_recorder_itf_)->SetRecordState(sles_recorder_itf_,
465 SL_RECORDSTATE_STOPPED),
466 VOID_RETURN);
467 }
468 if (rec_thread_.get() == NULL) {
469 return;
470 }
471 event_.Stop();
472 if (rec_thread_->Stop()) {
473 rec_thread_.reset();
474 } else {
475 assert(false);
476 }
477}
478
479bool OpenSlesInput::CbThread(void* context) {
480 return reinterpret_cast<OpenSlesInput*>(context)->CbThreadImpl();
481}
482
483bool OpenSlesInput::CbThreadImpl() {
484 int event_id;
485 int event_msg;
486 // event_ must not be waited on while a lock has been taken.
487 event_.WaitOnEvent(&event_id, &event_msg);
488
489 CriticalSectionScoped lock(crit_sect_.get());
490 if (HandleOverrun(event_id, event_msg)) {
491 return recording_;
492 }
493 // If the fifo_ has audio data process it.
494 while (fifo_->size() > 0 && recording_) {
495 int8_t* audio = fifo_->Pop();
496 audio_buffer_->SetRecordedBuffer(audio, kDefaultBufSizeInSamples);
497 audio_buffer_->SetVQEData(delay_provider_->PlayoutDelayMs(),
498 recording_delay_, 0);
499 audio_buffer_->DeliverRecordedData();
500 }
501 return recording_;
502}
503
504} // namespace webrtc