blob: c46aa8489921f7444f7d0bec259d3bbed0c4dc76 [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_output.h"
12
13#include <assert.h>
14
henrike@webrtc.org9ee75e92013-12-11 21:42:44 +000015#include "webrtc/modules/audio_device/android/opensles_common.h"
henrike@webrtc.org82f014a2013-09-10 18:24:07 +000016#include "webrtc/modules/audio_device/android/fine_audio_buffer.h"
17#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 kNoUnderrun,
39 kUnderrun,
40};
41
42namespace webrtc {
43
henrika@webrtc.org962c6242015-02-23 11:54:05 +000044OpenSlesOutput::OpenSlesOutput()
45 : initialized_(false),
henrike@webrtc.org82f014a2013-09-10 18:24:07 +000046 speaker_initialized_(false),
47 play_initialized_(false),
48 crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
49 playing_(false),
50 num_fifo_buffers_needed_(0),
51 number_underruns_(0),
52 sles_engine_(NULL),
53 sles_engine_itf_(NULL),
54 sles_player_(NULL),
55 sles_player_itf_(NULL),
56 sles_player_sbq_itf_(NULL),
57 sles_output_mixer_(NULL),
58 audio_buffer_(NULL),
59 active_queue_(0),
60 speaker_sampling_rate_(kDefaultSampleRate),
61 buffer_size_samples_(0),
62 buffer_size_bytes_(0),
63 playout_delay_(0) {
64}
65
66OpenSlesOutput::~OpenSlesOutput() {
67}
68
henrike@webrtc.org9ee75e92013-12-11 21:42:44 +000069int32_t OpenSlesOutput::SetAndroidAudioDeviceObjects(void* javaVM,
henrike@webrtc.org9ee75e92013-12-11 21:42:44 +000070 void* context) {
henrika@webrtc.org474d1eb2015-03-09 12:39:53 +000071 AudioManagerJni::SetAndroidAudioDeviceObjects(javaVM, context);
henrike@webrtc.org9ee75e92013-12-11 21:42:44 +000072 return 0;
73}
74
henrike@webrtc.org573a1b42014-01-10 22:58:06 +000075void OpenSlesOutput::ClearAndroidAudioDeviceObjects() {
76 AudioManagerJni::ClearAndroidAudioDeviceObjects();
77}
78
henrike@webrtc.org82f014a2013-09-10 18:24:07 +000079int32_t OpenSlesOutput::Init() {
80 assert(!initialized_);
81
82 // Set up OpenSl engine.
83 OPENSL_RETURN_ON_FAILURE(slCreateEngine(&sles_engine_, 1, kOption, 0,
84 NULL, NULL),
85 -1);
86 OPENSL_RETURN_ON_FAILURE((*sles_engine_)->Realize(sles_engine_,
87 SL_BOOLEAN_FALSE),
88 -1);
89 OPENSL_RETURN_ON_FAILURE((*sles_engine_)->GetInterface(sles_engine_,
90 SL_IID_ENGINE,
91 &sles_engine_itf_),
92 -1);
93 // Set up OpenSl output mix.
94 OPENSL_RETURN_ON_FAILURE(
95 (*sles_engine_itf_)->CreateOutputMix(sles_engine_itf_,
96 &sles_output_mixer_,
97 0,
98 NULL,
99 NULL),
100 -1);
101 OPENSL_RETURN_ON_FAILURE(
102 (*sles_output_mixer_)->Realize(sles_output_mixer_,
103 SL_BOOLEAN_FALSE),
104 -1);
105
106 if (!InitSampleRate()) {
107 return -1;
108 }
109 AllocateBuffers();
110 initialized_ = true;
111 return 0;
112}
113
114int32_t OpenSlesOutput::Terminate() {
115 // It is assumed that the caller has stopped recording before terminating.
116 assert(!playing_);
henrike@webrtc.org6138c5c2013-09-11 18:50:06 +0000117 (*sles_output_mixer_)->Destroy(sles_output_mixer_);
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000118 (*sles_engine_)->Destroy(sles_engine_);
119 initialized_ = false;
120 speaker_initialized_ = false;
121 play_initialized_ = false;
122 return 0;
123}
124
125int32_t OpenSlesOutput::PlayoutDeviceName(uint16_t index,
126 char name[kAdmMaxDeviceNameSize],
127 char guid[kAdmMaxGuidSize]) {
128 assert(index == 0);
129 // Empty strings.
130 name[0] = '\0';
131 guid[0] = '\0';
132 return 0;
133}
134
135int32_t OpenSlesOutput::SetPlayoutDevice(uint16_t index) {
136 assert(index == 0);
137 return 0;
138}
139
140int32_t OpenSlesOutput::PlayoutIsAvailable(bool& available) { // NOLINT
141 available = true;
142 return 0;
143}
144
145int32_t OpenSlesOutput::InitPlayout() {
146 assert(initialized_);
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000147 play_initialized_ = true;
148 return 0;
149}
150
151int32_t OpenSlesOutput::StartPlayout() {
152 assert(play_initialized_);
153 assert(!playing_);
154 if (!CreateAudioPlayer()) {
155 return -1;
156 }
157
158 // Register callback to receive enqueued buffers.
159 OPENSL_RETURN_ON_FAILURE(
160 (*sles_player_sbq_itf_)->RegisterCallback(sles_player_sbq_itf_,
161 PlayerSimpleBufferQueueCallback,
162 this),
163 -1);
164 if (!EnqueueAllBuffers()) {
165 return -1;
166 }
167
168 {
169 // To prevent the compiler from e.g. optimizing the code to
170 // playing_ = StartCbThreads() which wouldn't have been thread safe.
171 CriticalSectionScoped lock(crit_sect_.get());
172 playing_ = true;
173 }
174 if (!StartCbThreads()) {
175 playing_ = false;
176 }
177 return 0;
178}
179
180int32_t OpenSlesOutput::StopPlayout() {
181 StopCbThreads();
182 DestroyAudioPlayer();
henrike@webrtc.orga7500442013-11-20 22:32:12 +0000183 playing_ = false;
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000184 return 0;
185}
186
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000187int32_t OpenSlesOutput::InitSpeaker() {
188 assert(!playing_);
189 speaker_initialized_ = true;
190 return 0;
191}
192
193int32_t OpenSlesOutput::SpeakerVolumeIsAvailable(bool& available) { // NOLINT
194 available = true;
195 return 0;
196}
197
198int32_t OpenSlesOutput::SetSpeakerVolume(uint32_t volume) {
199 assert(speaker_initialized_);
200 assert(initialized_);
201 // TODO(hellner): implement.
202 return 0;
203}
204
205int32_t OpenSlesOutput::MaxSpeakerVolume(uint32_t& maxVolume) const { // NOLINT
206 assert(speaker_initialized_);
207 assert(initialized_);
208 // TODO(hellner): implement.
209 maxVolume = 0;
210 return 0;
211}
212
213int32_t OpenSlesOutput::MinSpeakerVolume(uint32_t& minVolume) const { // NOLINT
214 assert(speaker_initialized_);
215 assert(initialized_);
216 // TODO(hellner): implement.
217 minVolume = 0;
218 return 0;
219}
220
221int32_t OpenSlesOutput::SpeakerVolumeStepSize(
222 uint16_t& stepSize) const { // NOLINT
223 assert(speaker_initialized_);
224 stepSize = 1;
225 return 0;
226}
227
228int32_t OpenSlesOutput::SpeakerMuteIsAvailable(bool& available) { // NOLINT
229 available = false;
230 return 0;
231}
232
233int32_t OpenSlesOutput::StereoPlayoutIsAvailable(bool& available) { // NOLINT
234 available = false;
235 return 0;
236}
237
238int32_t OpenSlesOutput::SetStereoPlayout(bool enable) {
239 if (enable) {
240 assert(false);
241 return -1;
242 }
243 return 0;
244}
245
246int32_t OpenSlesOutput::StereoPlayout(bool& enabled) const { // NOLINT
247 enabled = kNumChannels == 2;
248 return 0;
249}
250
251int32_t OpenSlesOutput::PlayoutBuffer(
252 AudioDeviceModule::BufferType& type, // NOLINT
253 uint16_t& sizeMS) const { // NOLINT
254 type = AudioDeviceModule::kAdaptiveBufferSize;
255 sizeMS = playout_delay_;
256 return 0;
257}
258
259int32_t OpenSlesOutput::PlayoutDelay(uint16_t& delayMS) const { // NOLINT
260 delayMS = playout_delay_;
261 return 0;
262}
263
264void OpenSlesOutput::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
265 audio_buffer_ = audioBuffer;
266}
267
268int32_t OpenSlesOutput::SetLoudspeakerStatus(bool enable) {
269 return 0;
270}
271
272int32_t OpenSlesOutput::GetLoudspeakerStatus(bool& enabled) const { // NOLINT
273 enabled = true;
274 return 0;
275}
276
277int OpenSlesOutput::PlayoutDelayMs() {
278 return playout_delay_;
279}
280
281bool OpenSlesOutput::InitSampleRate() {
282 if (!SetLowLatency()) {
283 speaker_sampling_rate_ = kDefaultSampleRate;
284 // Default is to use 10ms buffers.
285 buffer_size_samples_ = speaker_sampling_rate_ * 10 / 1000;
286 }
287 if (audio_buffer_->SetPlayoutSampleRate(speaker_sampling_rate_) < 0) {
288 return false;
289 }
290 if (audio_buffer_->SetPlayoutChannels(kNumChannels) < 0) {
291 return false;
292 }
293 UpdatePlayoutDelay();
294 return true;
295}
296
297void OpenSlesOutput::UpdatePlayoutDelay() {
298 // TODO(hellner): Add accurate delay estimate.
299 // On average half the current buffer will have been played out.
300 int outstanding_samples = (TotalBuffersUsed() - 0.5) * buffer_size_samples_;
301 playout_delay_ = outstanding_samples / (speaker_sampling_rate_ / 1000);
302}
303
304bool OpenSlesOutput::SetLowLatency() {
305 if (!audio_manager_.low_latency_supported()) {
306 return false;
307 }
308 buffer_size_samples_ = audio_manager_.native_buffer_size();
309 assert(buffer_size_samples_ > 0);
310 speaker_sampling_rate_ = audio_manager_.native_output_sample_rate();
311 assert(speaker_sampling_rate_ > 0);
312 return true;
313}
314
315void OpenSlesOutput::CalculateNumFifoBuffersNeeded() {
316 int number_of_bytes_needed =
317 (speaker_sampling_rate_ * kNumChannels * sizeof(int16_t)) * 10 / 1000;
318
319 // Ceiling of integer division: 1 + ((x - 1) / y)
320 int buffers_per_10_ms =
321 1 + ((number_of_bytes_needed - 1) / buffer_size_bytes_);
322 // |num_fifo_buffers_needed_| is a multiple of 10ms of buffered up audio.
323 num_fifo_buffers_needed_ = kNum10MsToBuffer * buffers_per_10_ms;
324}
325
326void OpenSlesOutput::AllocateBuffers() {
327 // Allocate fine buffer to provide frames of the desired size.
328 buffer_size_bytes_ = buffer_size_samples_ * kNumChannels * sizeof(int16_t);
329 fine_buffer_.reset(new FineAudioBuffer(audio_buffer_, buffer_size_bytes_,
330 speaker_sampling_rate_));
331
332 // Allocate FIFO to handle passing buffers between processing and OpenSl
333 // threads.
334 CalculateNumFifoBuffersNeeded(); // Needs |buffer_size_bytes_| to be known
335 assert(num_fifo_buffers_needed_ > 0);
336 fifo_.reset(new SingleRwFifo(num_fifo_buffers_needed_));
337
338 // Allocate the memory area to be used.
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000339 play_buf_.reset(new rtc::scoped_ptr<int8_t[]>[TotalBuffersUsed()]);
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000340 int required_buffer_size = fine_buffer_->RequiredBufferSizeBytes();
341 for (int i = 0; i < TotalBuffersUsed(); ++i) {
342 play_buf_[i].reset(new int8_t[required_buffer_size]);
343 }
344}
345
346int OpenSlesOutput::TotalBuffersUsed() const {
347 return num_fifo_buffers_needed_ + kNumOpenSlBuffers;
348}
349
350bool OpenSlesOutput::EnqueueAllBuffers() {
351 active_queue_ = 0;
352 number_underruns_ = 0;
353 for (int i = 0; i < kNumOpenSlBuffers; ++i) {
354 memset(play_buf_[i].get(), 0, buffer_size_bytes_);
355 OPENSL_RETURN_ON_FAILURE(
356 (*sles_player_sbq_itf_)->Enqueue(
357 sles_player_sbq_itf_,
358 reinterpret_cast<void*>(play_buf_[i].get()),
359 buffer_size_bytes_),
360 false);
361 }
362 // OpenSL playing has been stopped. I.e. only this thread is touching
363 // |fifo_|.
364 while (fifo_->size() != 0) {
365 // Underrun might have happened when pushing new buffers to the FIFO.
366 fifo_->Pop();
367 }
368 for (int i = kNumOpenSlBuffers; i < TotalBuffersUsed(); ++i) {
369 memset(play_buf_[i].get(), 0, buffer_size_bytes_);
370 fifo_->Push(play_buf_[i].get());
371 }
372 return true;
373}
374
375bool OpenSlesOutput::CreateAudioPlayer() {
376 if (!event_.Start()) {
377 assert(false);
378 return false;
379 }
380 SLDataLocator_AndroidSimpleBufferQueue simple_buf_queue = {
381 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
382 static_cast<SLuint32>(kNumOpenSlBuffers)
383 };
384 SLDataFormat_PCM configuration =
385 webrtc_opensl::CreatePcmConfiguration(speaker_sampling_rate_);
386 SLDataSource audio_source = { &simple_buf_queue, &configuration };
387
388 SLDataLocator_OutputMix locator_outputmix;
389 // Setup the data sink structure.
390 locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
391 locator_outputmix.outputMix = sles_output_mixer_;
392 SLDataSink audio_sink = { &locator_outputmix, NULL };
393
394 // Interfaces for streaming audio data, setting volume and Android are needed.
395 // Note the interfaces still need to be initialized. This only tells OpenSl
396 // that the interfaces will be needed at some point.
397 SLInterfaceID ids[kNumInterfaces] = {
398 SL_IID_BUFFERQUEUE, SL_IID_VOLUME, SL_IID_ANDROIDCONFIGURATION };
399 SLboolean req[kNumInterfaces] = {
400 SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
401 OPENSL_RETURN_ON_FAILURE(
402 (*sles_engine_itf_)->CreateAudioPlayer(sles_engine_itf_, &sles_player_,
403 &audio_source, &audio_sink,
404 kNumInterfaces, ids, req),
405 false);
henrika@webrtc.orgdd43bbe2014-11-06 15:48:05 +0000406
407 SLAndroidConfigurationItf player_config;
408 OPENSL_RETURN_ON_FAILURE(
409 (*sles_player_)->GetInterface(sles_player_,
410 SL_IID_ANDROIDCONFIGURATION,
411 &player_config),
412 false);
413
414 // Set audio player configuration to SL_ANDROID_STREAM_VOICE which corresponds
415 // to android.media.AudioManager.STREAM_VOICE_CALL.
416 SLint32 stream_type = SL_ANDROID_STREAM_VOICE;
417 OPENSL_RETURN_ON_FAILURE(
418 (*player_config)->SetConfiguration(player_config,
419 SL_ANDROID_KEY_STREAM_TYPE,
420 &stream_type,
421 sizeof(SLint32)),
422 false);
423
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000424 // Realize the player in synchronous mode.
425 OPENSL_RETURN_ON_FAILURE((*sles_player_)->Realize(sles_player_,
426 SL_BOOLEAN_FALSE),
427 false);
428 OPENSL_RETURN_ON_FAILURE(
429 (*sles_player_)->GetInterface(sles_player_, SL_IID_PLAY,
430 &sles_player_itf_),
431 false);
432 OPENSL_RETURN_ON_FAILURE(
433 (*sles_player_)->GetInterface(sles_player_, SL_IID_BUFFERQUEUE,
434 &sles_player_sbq_itf_),
435 false);
436 return true;
437}
438
439void OpenSlesOutput::DestroyAudioPlayer() {
440 SLAndroidSimpleBufferQueueItf sles_player_sbq_itf = sles_player_sbq_itf_;
441 {
442 CriticalSectionScoped lock(crit_sect_.get());
443 sles_player_sbq_itf_ = NULL;
444 sles_player_itf_ = NULL;
445 }
446 event_.Stop();
447 if (sles_player_sbq_itf) {
448 // Release all buffers currently queued up.
449 OPENSL_RETURN_ON_FAILURE(
450 (*sles_player_sbq_itf)->Clear(sles_player_sbq_itf),
451 VOID_RETURN);
452 }
453
454 if (sles_player_) {
455 (*sles_player_)->Destroy(sles_player_);
456 sles_player_ = NULL;
457 }
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000458}
459
460bool OpenSlesOutput::HandleUnderrun(int event_id, int event_msg) {
461 if (!playing_) {
462 return false;
463 }
464 if (event_id == kNoUnderrun) {
465 return false;
466 }
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000467 assert(event_id == kUnderrun);
468 assert(event_msg > 0);
469 // Wait for all enqueued buffers to be flushed.
470 if (event_msg != kNumOpenSlBuffers) {
471 return true;
472 }
473 // All buffers have been flushed. Restart the audio from scratch.
474 // No need to check sles_player_itf_ as playing_ would be false before it is
475 // set to NULL.
476 OPENSL_RETURN_ON_FAILURE(
477 (*sles_player_itf_)->SetPlayState(sles_player_itf_,
478 SL_PLAYSTATE_STOPPED),
479 true);
480 EnqueueAllBuffers();
481 OPENSL_RETURN_ON_FAILURE(
482 (*sles_player_itf_)->SetPlayState(sles_player_itf_,
483 SL_PLAYSTATE_PLAYING),
484 true);
485 return true;
486}
487
488void OpenSlesOutput::PlayerSimpleBufferQueueCallback(
489 SLAndroidSimpleBufferQueueItf sles_player_sbq_itf,
490 void* p_context) {
491 OpenSlesOutput* audio_device = reinterpret_cast<OpenSlesOutput*>(p_context);
492 audio_device->PlayerSimpleBufferQueueCallbackHandler(sles_player_sbq_itf);
493}
494
495void OpenSlesOutput::PlayerSimpleBufferQueueCallbackHandler(
496 SLAndroidSimpleBufferQueueItf sles_player_sbq_itf) {
497 if (fifo_->size() <= 0 || number_underruns_ > 0) {
498 ++number_underruns_;
499 event_.SignalEvent(kUnderrun, number_underruns_);
500 return;
501 }
502 int8_t* audio = fifo_->Pop();
503 if (audio)
504 OPENSL_RETURN_ON_FAILURE(
505 (*sles_player_sbq_itf)->Enqueue(sles_player_sbq_itf,
506 audio,
507 buffer_size_bytes_),
508 VOID_RETURN);
509 event_.SignalEvent(kNoUnderrun, 0);
510}
511
512bool OpenSlesOutput::StartCbThreads() {
513 play_thread_.reset(ThreadWrapper::CreateThread(CbThread,
514 this,
515 kRealtimePriority,
516 "opensl_play_thread"));
517 assert(play_thread_.get());
518 OPENSL_RETURN_ON_FAILURE(
519 (*sles_player_itf_)->SetPlayState(sles_player_itf_,
520 SL_PLAYSTATE_PLAYING),
521 false);
522
pbos@webrtc.org86639732015-03-13 00:06:21 +0000523 if (!play_thread_->Start()) {
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000524 assert(false);
525 return false;
526 }
527 return true;
528}
529
530void OpenSlesOutput::StopCbThreads() {
531 {
532 CriticalSectionScoped lock(crit_sect_.get());
533 playing_ = false;
534 }
535 if (sles_player_itf_) {
536 OPENSL_RETURN_ON_FAILURE(
537 (*sles_player_itf_)->SetPlayState(sles_player_itf_,
538 SL_PLAYSTATE_STOPPED),
539 VOID_RETURN);
540 }
541 if (play_thread_.get() == NULL) {
542 return;
543 }
544 event_.Stop();
545 if (play_thread_->Stop()) {
546 play_thread_.reset();
547 } else {
548 assert(false);
549 }
550}
551
552bool OpenSlesOutput::CbThread(void* context) {
553 return reinterpret_cast<OpenSlesOutput*>(context)->CbThreadImpl();
554}
555
556bool OpenSlesOutput::CbThreadImpl() {
557 assert(fine_buffer_.get() != NULL);
558 int event_id;
559 int event_msg;
560 // event_ must not be waited on while a lock has been taken.
561 event_.WaitOnEvent(&event_id, &event_msg);
562
563 CriticalSectionScoped lock(crit_sect_.get());
564 if (HandleUnderrun(event_id, event_msg)) {
565 return playing_;
566 }
567 // if fifo_ is not full it means next item in memory must be free.
568 while (fifo_->size() < num_fifo_buffers_needed_ && playing_) {
569 int8_t* audio = play_buf_[active_queue_].get();
570 fine_buffer_->GetBufferData(audio);
571 fifo_->Push(audio);
572 active_queue_ = (active_queue_ + 1) % TotalBuffersUsed();
573 }
574 return playing_;
575}
576
577} // namespace webrtc