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