blob: 12640e7fd9cc68ab5e5c1a465dddc6fa27b41b35 [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
henrike@webrtc.org9ee75e92013-12-11 21:42:44 +000015#include "webrtc/modules/audio_device/android/audio_common.h"
16#include "webrtc/modules/audio_device/android/opensles_common.h"
henrike@webrtc.org82f014a2013-09-10 18:24:07 +000017#include "webrtc/modules/audio_device/android/single_rw_fifo.h"
18#include "webrtc/modules/audio_device/audio_device_buffer.h"
19#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
20#include "webrtc/system_wrappers/interface/thread_wrapper.h"
21#include "webrtc/system_wrappers/interface/trace.h"
22
henrike@webrtc.org82f014a2013-09-10 18:24:07 +000023#define VOID_RETURN
24#define OPENSL_RETURN_ON_FAILURE(op, ret_val) \
25 do { \
26 SLresult err = (op); \
27 if (err != SL_RESULT_SUCCESS) { \
henrike@webrtc.org82f014a2013-09-10 18:24:07 +000028 assert(false); \
29 return ret_val; \
30 } \
31 } while (0)
32
33static const SLEngineOption kOption[] = {
34 { SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE) },
35};
36
37enum {
38 kNoOverrun,
39 kOverrun,
40};
41
42namespace webrtc {
43
henrika@webrtc.org962c6242015-02-23 11:54:05 +000044OpenSlesInput::OpenSlesInput(PlayoutDelayProvider* delay_provider)
45 : delay_provider_(delay_provider),
46 initialized_(false),
henrike@webrtc.org82f014a2013-09-10 18:24:07 +000047 mic_initialized_(false),
48 rec_initialized_(false),
49 crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
50 recording_(false),
51 num_fifo_buffers_needed_(0),
52 number_overruns_(0),
53 sles_engine_(NULL),
54 sles_engine_itf_(NULL),
55 sles_recorder_(NULL),
56 sles_recorder_itf_(NULL),
57 sles_recorder_sbq_itf_(NULL),
58 audio_buffer_(NULL),
59 active_queue_(0),
henrike@webrtc.orgc8dea6a2013-09-17 18:44:51 +000060 rec_sampling_rate_(0),
henrike@webrtc.org82f014a2013-09-10 18:24:07 +000061 agc_enabled_(false),
62 recording_delay_(0) {
63}
64
65OpenSlesInput::~OpenSlesInput() {
66}
67
henrike@webrtc.org9ee75e92013-12-11 21:42:44 +000068int32_t OpenSlesInput::SetAndroidAudioDeviceObjects(void* javaVM,
henrike@webrtc.org9ee75e92013-12-11 21:42:44 +000069 void* context) {
70 return 0;
71}
72
henrike@webrtc.org573a1b42014-01-10 22:58:06 +000073void OpenSlesInput::ClearAndroidAudioDeviceObjects() {
74}
75
henrike@webrtc.org82f014a2013-09-10 18:24:07 +000076int32_t OpenSlesInput::Init() {
77 assert(!initialized_);
78
79 // Set up OpenSL engine.
80 OPENSL_RETURN_ON_FAILURE(slCreateEngine(&sles_engine_, 1, kOption, 0,
81 NULL, NULL),
82 -1);
83 OPENSL_RETURN_ON_FAILURE((*sles_engine_)->Realize(sles_engine_,
84 SL_BOOLEAN_FALSE),
85 -1);
86 OPENSL_RETURN_ON_FAILURE((*sles_engine_)->GetInterface(sles_engine_,
87 SL_IID_ENGINE,
88 &sles_engine_itf_),
89 -1);
90
91 if (InitSampleRate() != 0) {
92 return -1;
93 }
94 AllocateBuffers();
95 initialized_ = true;
96 return 0;
97}
98
99int32_t OpenSlesInput::Terminate() {
100 // It is assumed that the caller has stopped recording before terminating.
101 assert(!recording_);
102 (*sles_engine_)->Destroy(sles_engine_);
103 initialized_ = false;
104 mic_initialized_ = false;
105 rec_initialized_ = false;
106 return 0;
107}
108
109int32_t OpenSlesInput::RecordingDeviceName(uint16_t index,
110 char name[kAdmMaxDeviceNameSize],
111 char guid[kAdmMaxGuidSize]) {
112 assert(index == 0);
113 // Empty strings.
114 name[0] = '\0';
115 guid[0] = '\0';
116 return 0;
117}
118
119int32_t OpenSlesInput::SetRecordingDevice(uint16_t index) {
120 assert(index == 0);
121 return 0;
122}
123
124int32_t OpenSlesInput::RecordingIsAvailable(bool& available) { // NOLINT
125 available = true;
126 return 0;
127}
128
129int32_t OpenSlesInput::InitRecording() {
130 assert(initialized_);
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000131 rec_initialized_ = true;
132 return 0;
133}
134
135int32_t OpenSlesInput::StartRecording() {
136 assert(rec_initialized_);
137 assert(!recording_);
138 if (!CreateAudioRecorder()) {
139 return -1;
140 }
141 // Setup to receive buffer queue event callbacks.
142 OPENSL_RETURN_ON_FAILURE(
143 (*sles_recorder_sbq_itf_)->RegisterCallback(
144 sles_recorder_sbq_itf_,
145 RecorderSimpleBufferQueueCallback,
146 this),
147 -1);
148
149 if (!EnqueueAllBuffers()) {
150 return -1;
151 }
152
153 {
154 // To prevent the compiler from e.g. optimizing the code to
155 // recording_ = StartCbThreads() which wouldn't have been thread safe.
156 CriticalSectionScoped lock(crit_sect_.get());
157 recording_ = true;
158 }
159 if (!StartCbThreads()) {
160 recording_ = false;
161 return -1;
162 }
163 return 0;
164}
165
166int32_t OpenSlesInput::StopRecording() {
167 StopCbThreads();
168 DestroyAudioRecorder();
henrike@webrtc.orga7500442013-11-20 22:32:12 +0000169 recording_ = false;
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000170 return 0;
171}
172
173int32_t OpenSlesInput::SetAGC(bool enable) {
174 agc_enabled_ = enable;
175 return 0;
176}
177
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000178int32_t OpenSlesInput::InitMicrophone() {
179 assert(initialized_);
180 assert(!recording_);
181 mic_initialized_ = true;
182 return 0;
183}
184
185int32_t OpenSlesInput::MicrophoneVolumeIsAvailable(bool& available) { // NOLINT
186 available = false;
187 return 0;
188}
189
190int32_t OpenSlesInput::MinMicrophoneVolume(
191 uint32_t& minVolume) const { // NOLINT
192 minVolume = 0;
193 return 0;
194}
195
196int32_t OpenSlesInput::MicrophoneVolumeStepSize(
197 uint16_t& stepSize) const {
198 stepSize = 1;
199 return 0;
200}
201
202int32_t OpenSlesInput::MicrophoneMuteIsAvailable(bool& available) { // NOLINT
203 available = false; // Mic mute not supported on Android
204 return 0;
205}
206
207int32_t OpenSlesInput::MicrophoneBoostIsAvailable(bool& available) { // NOLINT
208 available = false; // Mic boost not supported on Android.
209 return 0;
210}
211
212int32_t OpenSlesInput::SetMicrophoneBoost(bool enable) {
213 assert(false);
214 return -1; // Not supported
215}
216
217int32_t OpenSlesInput::MicrophoneBoost(bool& enabled) const { // NOLINT
218 assert(false);
219 return -1; // Not supported
220}
221
222int32_t OpenSlesInput::StereoRecordingIsAvailable(bool& available) { // NOLINT
223 available = false; // Stereo recording not supported on Android.
224 return 0;
225}
226
227int32_t OpenSlesInput::StereoRecording(bool& enabled) const { // NOLINT
228 enabled = false;
229 return 0;
230}
231
232int32_t OpenSlesInput::RecordingDelay(uint16_t& delayMS) const { // NOLINT
233 delayMS = recording_delay_;
234 return 0;
235}
236
237void OpenSlesInput::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
238 audio_buffer_ = audioBuffer;
239}
240
henrike@webrtc.orgc8dea6a2013-09-17 18:44:51 +0000241int OpenSlesInput::InitSampleRate() {
242 UpdateSampleRate();
243 audio_buffer_->SetRecordingSampleRate(rec_sampling_rate_);
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000244 audio_buffer_->SetRecordingChannels(kNumChannels);
245 UpdateRecordingDelay();
246 return 0;
247}
248
henrike@webrtc.orgc8dea6a2013-09-17 18:44:51 +0000249int OpenSlesInput::buffer_size_samples() const {
250 // Since there is no low latency recording, use buffer size corresponding to
251 // 10ms of data since that's the framesize WebRTC uses. Getting any other
252 // size would require patching together buffers somewhere before passing them
253 // to WebRTC.
254 return rec_sampling_rate_ * 10 / 1000;
255}
256
257int OpenSlesInput::buffer_size_bytes() const {
258 return buffer_size_samples() * kNumChannels * sizeof(int16_t);
259}
260
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000261void OpenSlesInput::UpdateRecordingDelay() {
262 // TODO(hellner): Add accurate delay estimate.
263 // On average half the current buffer will have been filled with audio.
264 int outstanding_samples =
henrike@webrtc.orgc8dea6a2013-09-17 18:44:51 +0000265 (TotalBuffersUsed() - 0.5) * buffer_size_samples();
266 recording_delay_ = outstanding_samples / (rec_sampling_rate_ / 1000);
267}
268
269void OpenSlesInput::UpdateSampleRate() {
270 rec_sampling_rate_ = audio_manager_.low_latency_supported() ?
271 audio_manager_.native_output_sample_rate() : kDefaultSampleRate;
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000272}
273
274void OpenSlesInput::CalculateNumFifoBuffersNeeded() {
275 // Buffer size is 10ms of data.
276 num_fifo_buffers_needed_ = kNum10MsToBuffer;
277}
278
279void OpenSlesInput::AllocateBuffers() {
280 // Allocate FIFO to handle passing buffers between processing and OpenSL
281 // threads.
282 CalculateNumFifoBuffersNeeded();
283 assert(num_fifo_buffers_needed_ > 0);
284 fifo_.reset(new SingleRwFifo(num_fifo_buffers_needed_));
285
286 // Allocate the memory area to be used.
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000287 rec_buf_.reset(new rtc::scoped_ptr<int8_t[]>[TotalBuffersUsed()]);
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000288 for (int i = 0; i < TotalBuffersUsed(); ++i) {
henrike@webrtc.orgc8dea6a2013-09-17 18:44:51 +0000289 rec_buf_[i].reset(new int8_t[buffer_size_bytes()]);
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000290 }
291}
292
293int OpenSlesInput::TotalBuffersUsed() const {
294 return num_fifo_buffers_needed_ + kNumOpenSlBuffers;
295}
296
297bool OpenSlesInput::EnqueueAllBuffers() {
298 active_queue_ = 0;
299 number_overruns_ = 0;
300 for (int i = 0; i < kNumOpenSlBuffers; ++i) {
henrike@webrtc.orgc8dea6a2013-09-17 18:44:51 +0000301 memset(rec_buf_[i].get(), 0, buffer_size_bytes());
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000302 OPENSL_RETURN_ON_FAILURE(
303 (*sles_recorder_sbq_itf_)->Enqueue(
304 sles_recorder_sbq_itf_,
305 reinterpret_cast<void*>(rec_buf_[i].get()),
henrike@webrtc.orgc8dea6a2013-09-17 18:44:51 +0000306 buffer_size_bytes()),
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000307 false);
308 }
309 // In case of underrun the fifo will be at capacity. In case of first enqueue
310 // no audio can have been returned yet meaning fifo must be empty. Any other
311 // values are unexpected.
312 assert(fifo_->size() == fifo_->capacity() ||
313 fifo_->size() == 0);
314 // OpenSL recording has been stopped. I.e. only this thread is touching
315 // |fifo_|.
316 while (fifo_->size() != 0) {
317 // Clear the fifo.
318 fifo_->Pop();
319 }
320 return true;
321}
322
323bool OpenSlesInput::CreateAudioRecorder() {
324 if (!event_.Start()) {
325 assert(false);
326 return false;
327 }
328 SLDataLocator_IODevice micLocator = {
329 SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
330 SL_DEFAULTDEVICEID_AUDIOINPUT, NULL };
331 SLDataSource audio_source = { &micLocator, NULL };
332
333 SLDataLocator_AndroidSimpleBufferQueue simple_buf_queue = {
334 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
335 static_cast<SLuint32>(TotalBuffersUsed())
336 };
337 SLDataFormat_PCM configuration =
henrike@webrtc.orgc8dea6a2013-09-17 18:44:51 +0000338 webrtc_opensl::CreatePcmConfiguration(rec_sampling_rate_);
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000339 SLDataSink audio_sink = { &simple_buf_queue, &configuration };
340
341 // Interfaces for recording android audio data and Android are needed.
342 // Note the interfaces still need to be initialized. This only tells OpenSl
343 // that the interfaces will be needed at some point.
344 const SLInterfaceID id[kNumInterfaces] = {
345 SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION };
346 const SLboolean req[kNumInterfaces] = {
347 SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
348 OPENSL_RETURN_ON_FAILURE(
349 (*sles_engine_itf_)->CreateAudioRecorder(sles_engine_itf_,
350 &sles_recorder_,
351 &audio_source,
352 &audio_sink,
353 kNumInterfaces,
354 id,
355 req),
356 false);
357
henrika@webrtc.orgdd43bbe2014-11-06 15:48:05 +0000358 SLAndroidConfigurationItf recorder_config;
359 OPENSL_RETURN_ON_FAILURE(
360 (*sles_recorder_)->GetInterface(sles_recorder_,
361 SL_IID_ANDROIDCONFIGURATION,
362 &recorder_config),
363 false);
364
365 // Set audio recorder configuration to
366 // SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION which ensures that we
367 // use the main microphone tuned for audio communications.
368 SLint32 stream_type = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION;
369 OPENSL_RETURN_ON_FAILURE(
370 (*recorder_config)->SetConfiguration(recorder_config,
371 SL_ANDROID_KEY_RECORDING_PRESET,
372 &stream_type,
373 sizeof(SLint32)),
374 false);
375
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000376 // Realize the recorder in synchronous mode.
377 OPENSL_RETURN_ON_FAILURE((*sles_recorder_)->Realize(sles_recorder_,
378 SL_BOOLEAN_FALSE),
379 false);
380 OPENSL_RETURN_ON_FAILURE(
381 (*sles_recorder_)->GetInterface(sles_recorder_, SL_IID_RECORD,
382 static_cast<void*>(&sles_recorder_itf_)),
383 false);
384 OPENSL_RETURN_ON_FAILURE(
385 (*sles_recorder_)->GetInterface(
386 sles_recorder_,
387 SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
388 static_cast<void*>(&sles_recorder_sbq_itf_)),
389 false);
390 return true;
391}
392
393void OpenSlesInput::DestroyAudioRecorder() {
394 event_.Stop();
395 if (sles_recorder_sbq_itf_) {
396 // Release all buffers currently queued up.
397 OPENSL_RETURN_ON_FAILURE(
398 (*sles_recorder_sbq_itf_)->Clear(sles_recorder_sbq_itf_),
399 VOID_RETURN);
400 sles_recorder_sbq_itf_ = NULL;
401 }
402 sles_recorder_itf_ = NULL;
403
henrike@webrtc.org6138c5c2013-09-11 18:50:06 +0000404 if (sles_recorder_) {
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000405 (*sles_recorder_)->Destroy(sles_recorder_);
406 sles_recorder_ = NULL;
407 }
408}
409
410bool OpenSlesInput::HandleOverrun(int event_id, int event_msg) {
411 if (!recording_) {
412 return false;
413 }
414 if (event_id == kNoOverrun) {
415 return false;
416 }
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000417 assert(event_id == kOverrun);
418 assert(event_msg > 0);
419 // Wait for all enqueued buffers be flushed.
420 if (event_msg != kNumOpenSlBuffers) {
421 return true;
422 }
423 // All buffers passed to OpenSL have been flushed. Restart the audio from
424 // scratch.
425 // No need to check sles_recorder_itf_ as recording_ would be false before it
426 // is set to NULL.
427 OPENSL_RETURN_ON_FAILURE(
428 (*sles_recorder_itf_)->SetRecordState(sles_recorder_itf_,
429 SL_RECORDSTATE_STOPPED),
430 true);
431 EnqueueAllBuffers();
432 OPENSL_RETURN_ON_FAILURE(
433 (*sles_recorder_itf_)->SetRecordState(sles_recorder_itf_,
434 SL_RECORDSTATE_RECORDING),
435 true);
436 return true;
437}
438
439void OpenSlesInput::RecorderSimpleBufferQueueCallback(
440 SLAndroidSimpleBufferQueueItf queue_itf,
441 void* context) {
442 OpenSlesInput* audio_device = reinterpret_cast<OpenSlesInput*>(context);
443 audio_device->RecorderSimpleBufferQueueCallbackHandler(queue_itf);
444}
445
446void OpenSlesInput::RecorderSimpleBufferQueueCallbackHandler(
447 SLAndroidSimpleBufferQueueItf queue_itf) {
448 if (fifo_->size() >= fifo_->capacity() || number_overruns_ > 0) {
449 ++number_overruns_;
450 event_.SignalEvent(kOverrun, number_overruns_);
451 return;
452 }
453 int8_t* audio = rec_buf_[active_queue_].get();
454 // There is at least one spot available in the fifo.
455 fifo_->Push(audio);
456 active_queue_ = (active_queue_ + 1) % TotalBuffersUsed();
457 event_.SignalEvent(kNoOverrun, 0);
458 // active_queue_ is indexing the next buffer to record to. Since the current
459 // buffer has been recorded it means that the buffer index
460 // kNumOpenSlBuffers - 1 past |active_queue_| contains the next free buffer.
461 // Since |fifo_| wasn't at capacity, at least one buffer is free to be used.
462 int next_free_buffer =
463 (active_queue_ + kNumOpenSlBuffers - 1) % TotalBuffersUsed();
464 OPENSL_RETURN_ON_FAILURE(
465 (*sles_recorder_sbq_itf_)->Enqueue(
466 sles_recorder_sbq_itf_,
467 reinterpret_cast<void*>(rec_buf_[next_free_buffer].get()),
henrike@webrtc.orgc8dea6a2013-09-17 18:44:51 +0000468 buffer_size_bytes()),
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000469 VOID_RETURN);
470}
471
472bool OpenSlesInput::StartCbThreads() {
tommi@webrtc.orgb6817d72015-03-20 15:51:39 +0000473 rec_thread_ = ThreadWrapper::CreateThread(CbThread, this,
tommi@webrtc.org361981f2015-03-19 14:44:18 +0000474 "opensl_rec_thread");
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000475 assert(rec_thread_.get());
pbos@webrtc.org86639732015-03-13 00:06:21 +0000476 if (!rec_thread_->Start()) {
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000477 assert(false);
478 return false;
479 }
tommi@webrtc.orgb6817d72015-03-20 15:51:39 +0000480 rec_thread_->SetPriority(kRealtimePriority);
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000481 OPENSL_RETURN_ON_FAILURE(
482 (*sles_recorder_itf_)->SetRecordState(sles_recorder_itf_,
483 SL_RECORDSTATE_RECORDING),
484 false);
485 return true;
486}
487
488void OpenSlesInput::StopCbThreads() {
489 {
490 CriticalSectionScoped lock(crit_sect_.get());
491 recording_ = false;
492 }
493 if (sles_recorder_itf_) {
494 OPENSL_RETURN_ON_FAILURE(
495 (*sles_recorder_itf_)->SetRecordState(sles_recorder_itf_,
496 SL_RECORDSTATE_STOPPED),
497 VOID_RETURN);
498 }
499 if (rec_thread_.get() == NULL) {
500 return;
501 }
502 event_.Stop();
503 if (rec_thread_->Stop()) {
504 rec_thread_.reset();
505 } else {
506 assert(false);
507 }
508}
509
510bool OpenSlesInput::CbThread(void* context) {
511 return reinterpret_cast<OpenSlesInput*>(context)->CbThreadImpl();
512}
513
514bool OpenSlesInput::CbThreadImpl() {
515 int event_id;
516 int event_msg;
517 // event_ must not be waited on while a lock has been taken.
518 event_.WaitOnEvent(&event_id, &event_msg);
519
520 CriticalSectionScoped lock(crit_sect_.get());
521 if (HandleOverrun(event_id, event_msg)) {
522 return recording_;
523 }
524 // If the fifo_ has audio data process it.
525 while (fifo_->size() > 0 && recording_) {
526 int8_t* audio = fifo_->Pop();
henrike@webrtc.orgc8dea6a2013-09-17 18:44:51 +0000527 audio_buffer_->SetRecordedBuffer(audio, buffer_size_samples());
henrika@webrtc.org962c6242015-02-23 11:54:05 +0000528 audio_buffer_->SetVQEData(delay_provider_->PlayoutDelayMs(),
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000529 recording_delay_, 0);
530 audio_buffer_->DeliverRecordedData();
531 }
532 return recording_;
533}
534
535} // namespace webrtc