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