blob: 3823305532d4bf67cf4fc05f5b91ef7ea3a62d34 [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.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
187int32_t OpenSlesOutput::SpeakerIsAvailable(bool& available) { // NOLINT
188 available = true;
189 return 0;
190}
191
192int32_t OpenSlesOutput::InitSpeaker() {
193 assert(!playing_);
194 speaker_initialized_ = true;
195 return 0;
196}
197
198int32_t OpenSlesOutput::SpeakerVolumeIsAvailable(bool& available) { // NOLINT
199 available = true;
200 return 0;
201}
202
203int32_t OpenSlesOutput::SetSpeakerVolume(uint32_t volume) {
204 assert(speaker_initialized_);
205 assert(initialized_);
206 // TODO(hellner): implement.
207 return 0;
208}
209
210int32_t OpenSlesOutput::MaxSpeakerVolume(uint32_t& maxVolume) const { // NOLINT
211 assert(speaker_initialized_);
212 assert(initialized_);
213 // TODO(hellner): implement.
214 maxVolume = 0;
215 return 0;
216}
217
218int32_t OpenSlesOutput::MinSpeakerVolume(uint32_t& minVolume) const { // NOLINT
219 assert(speaker_initialized_);
220 assert(initialized_);
221 // TODO(hellner): implement.
222 minVolume = 0;
223 return 0;
224}
225
226int32_t OpenSlesOutput::SpeakerVolumeStepSize(
227 uint16_t& stepSize) const { // NOLINT
228 assert(speaker_initialized_);
229 stepSize = 1;
230 return 0;
231}
232
233int32_t OpenSlesOutput::SpeakerMuteIsAvailable(bool& available) { // NOLINT
234 available = false;
235 return 0;
236}
237
238int32_t OpenSlesOutput::StereoPlayoutIsAvailable(bool& available) { // NOLINT
239 available = false;
240 return 0;
241}
242
243int32_t OpenSlesOutput::SetStereoPlayout(bool enable) {
244 if (enable) {
245 assert(false);
246 return -1;
247 }
248 return 0;
249}
250
251int32_t OpenSlesOutput::StereoPlayout(bool& enabled) const { // NOLINT
252 enabled = kNumChannels == 2;
253 return 0;
254}
255
256int32_t OpenSlesOutput::PlayoutBuffer(
257 AudioDeviceModule::BufferType& type, // NOLINT
258 uint16_t& sizeMS) const { // NOLINT
259 type = AudioDeviceModule::kAdaptiveBufferSize;
260 sizeMS = playout_delay_;
261 return 0;
262}
263
264int32_t OpenSlesOutput::PlayoutDelay(uint16_t& delayMS) const { // NOLINT
265 delayMS = playout_delay_;
266 return 0;
267}
268
269void OpenSlesOutput::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
270 audio_buffer_ = audioBuffer;
271}
272
273int32_t OpenSlesOutput::SetLoudspeakerStatus(bool enable) {
274 return 0;
275}
276
277int32_t OpenSlesOutput::GetLoudspeakerStatus(bool& enabled) const { // NOLINT
278 enabled = true;
279 return 0;
280}
281
282int OpenSlesOutput::PlayoutDelayMs() {
283 return playout_delay_;
284}
285
286bool OpenSlesOutput::InitSampleRate() {
287 if (!SetLowLatency()) {
288 speaker_sampling_rate_ = kDefaultSampleRate;
289 // Default is to use 10ms buffers.
290 buffer_size_samples_ = speaker_sampling_rate_ * 10 / 1000;
291 }
292 if (audio_buffer_->SetPlayoutSampleRate(speaker_sampling_rate_) < 0) {
293 return false;
294 }
295 if (audio_buffer_->SetPlayoutChannels(kNumChannels) < 0) {
296 return false;
297 }
298 UpdatePlayoutDelay();
299 return true;
300}
301
302void OpenSlesOutput::UpdatePlayoutDelay() {
303 // TODO(hellner): Add accurate delay estimate.
304 // On average half the current buffer will have been played out.
305 int outstanding_samples = (TotalBuffersUsed() - 0.5) * buffer_size_samples_;
306 playout_delay_ = outstanding_samples / (speaker_sampling_rate_ / 1000);
307}
308
309bool OpenSlesOutput::SetLowLatency() {
310 if (!audio_manager_.low_latency_supported()) {
311 return false;
312 }
313 buffer_size_samples_ = audio_manager_.native_buffer_size();
314 assert(buffer_size_samples_ > 0);
315 speaker_sampling_rate_ = audio_manager_.native_output_sample_rate();
316 assert(speaker_sampling_rate_ > 0);
317 return true;
318}
319
320void OpenSlesOutput::CalculateNumFifoBuffersNeeded() {
321 int number_of_bytes_needed =
322 (speaker_sampling_rate_ * kNumChannels * sizeof(int16_t)) * 10 / 1000;
323
324 // Ceiling of integer division: 1 + ((x - 1) / y)
325 int buffers_per_10_ms =
326 1 + ((number_of_bytes_needed - 1) / buffer_size_bytes_);
327 // |num_fifo_buffers_needed_| is a multiple of 10ms of buffered up audio.
328 num_fifo_buffers_needed_ = kNum10MsToBuffer * buffers_per_10_ms;
329}
330
331void OpenSlesOutput::AllocateBuffers() {
332 // Allocate fine buffer to provide frames of the desired size.
333 buffer_size_bytes_ = buffer_size_samples_ * kNumChannels * sizeof(int16_t);
334 fine_buffer_.reset(new FineAudioBuffer(audio_buffer_, buffer_size_bytes_,
335 speaker_sampling_rate_));
336
337 // Allocate FIFO to handle passing buffers between processing and OpenSl
338 // threads.
339 CalculateNumFifoBuffersNeeded(); // Needs |buffer_size_bytes_| to be known
340 assert(num_fifo_buffers_needed_ > 0);
341 fifo_.reset(new SingleRwFifo(num_fifo_buffers_needed_));
342
343 // Allocate the memory area to be used.
344 play_buf_.reset(new scoped_array<int8_t>[TotalBuffersUsed()]);
345 int required_buffer_size = fine_buffer_->RequiredBufferSizeBytes();
346 for (int i = 0; i < TotalBuffersUsed(); ++i) {
347 play_buf_[i].reset(new int8_t[required_buffer_size]);
348 }
349}
350
351int OpenSlesOutput::TotalBuffersUsed() const {
352 return num_fifo_buffers_needed_ + kNumOpenSlBuffers;
353}
354
355bool OpenSlesOutput::EnqueueAllBuffers() {
356 active_queue_ = 0;
357 number_underruns_ = 0;
358 for (int i = 0; i < kNumOpenSlBuffers; ++i) {
359 memset(play_buf_[i].get(), 0, buffer_size_bytes_);
360 OPENSL_RETURN_ON_FAILURE(
361 (*sles_player_sbq_itf_)->Enqueue(
362 sles_player_sbq_itf_,
363 reinterpret_cast<void*>(play_buf_[i].get()),
364 buffer_size_bytes_),
365 false);
366 }
367 // OpenSL playing has been stopped. I.e. only this thread is touching
368 // |fifo_|.
369 while (fifo_->size() != 0) {
370 // Underrun might have happened when pushing new buffers to the FIFO.
371 fifo_->Pop();
372 }
373 for (int i = kNumOpenSlBuffers; i < TotalBuffersUsed(); ++i) {
374 memset(play_buf_[i].get(), 0, buffer_size_bytes_);
375 fifo_->Push(play_buf_[i].get());
376 }
377 return true;
378}
379
380bool OpenSlesOutput::CreateAudioPlayer() {
381 if (!event_.Start()) {
382 assert(false);
383 return false;
384 }
385 SLDataLocator_AndroidSimpleBufferQueue simple_buf_queue = {
386 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
387 static_cast<SLuint32>(kNumOpenSlBuffers)
388 };
389 SLDataFormat_PCM configuration =
390 webrtc_opensl::CreatePcmConfiguration(speaker_sampling_rate_);
391 SLDataSource audio_source = { &simple_buf_queue, &configuration };
392
393 SLDataLocator_OutputMix locator_outputmix;
394 // Setup the data sink structure.
395 locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
396 locator_outputmix.outputMix = sles_output_mixer_;
397 SLDataSink audio_sink = { &locator_outputmix, NULL };
398
399 // Interfaces for streaming audio data, setting volume and Android are needed.
400 // Note the interfaces still need to be initialized. This only tells OpenSl
401 // that the interfaces will be needed at some point.
402 SLInterfaceID ids[kNumInterfaces] = {
403 SL_IID_BUFFERQUEUE, SL_IID_VOLUME, SL_IID_ANDROIDCONFIGURATION };
404 SLboolean req[kNumInterfaces] = {
405 SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
406 OPENSL_RETURN_ON_FAILURE(
407 (*sles_engine_itf_)->CreateAudioPlayer(sles_engine_itf_, &sles_player_,
408 &audio_source, &audio_sink,
409 kNumInterfaces, ids, req),
410 false);
411 // Realize the player in synchronous mode.
412 OPENSL_RETURN_ON_FAILURE((*sles_player_)->Realize(sles_player_,
413 SL_BOOLEAN_FALSE),
414 false);
415 OPENSL_RETURN_ON_FAILURE(
416 (*sles_player_)->GetInterface(sles_player_, SL_IID_PLAY,
417 &sles_player_itf_),
418 false);
419 OPENSL_RETURN_ON_FAILURE(
420 (*sles_player_)->GetInterface(sles_player_, SL_IID_BUFFERQUEUE,
421 &sles_player_sbq_itf_),
422 false);
423 return true;
424}
425
426void OpenSlesOutput::DestroyAudioPlayer() {
427 SLAndroidSimpleBufferQueueItf sles_player_sbq_itf = sles_player_sbq_itf_;
428 {
429 CriticalSectionScoped lock(crit_sect_.get());
430 sles_player_sbq_itf_ = NULL;
431 sles_player_itf_ = NULL;
432 }
433 event_.Stop();
434 if (sles_player_sbq_itf) {
435 // Release all buffers currently queued up.
436 OPENSL_RETURN_ON_FAILURE(
437 (*sles_player_sbq_itf)->Clear(sles_player_sbq_itf),
438 VOID_RETURN);
439 }
440
441 if (sles_player_) {
442 (*sles_player_)->Destroy(sles_player_);
443 sles_player_ = NULL;
444 }
henrike@webrtc.org82f014a2013-09-10 18:24:07 +0000445}
446
447bool OpenSlesOutput::HandleUnderrun(int event_id, int event_msg) {
448 if (!playing_) {
449 return false;
450 }
451 if (event_id == kNoUnderrun) {
452 return false;
453 }
454 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, id_, "Audio underrun");
455 assert(event_id == kUnderrun);
456 assert(event_msg > 0);
457 // Wait for all enqueued buffers to be flushed.
458 if (event_msg != kNumOpenSlBuffers) {
459 return true;
460 }
461 // All buffers have been flushed. Restart the audio from scratch.
462 // No need to check sles_player_itf_ as playing_ would be false before it is
463 // set to NULL.
464 OPENSL_RETURN_ON_FAILURE(
465 (*sles_player_itf_)->SetPlayState(sles_player_itf_,
466 SL_PLAYSTATE_STOPPED),
467 true);
468 EnqueueAllBuffers();
469 OPENSL_RETURN_ON_FAILURE(
470 (*sles_player_itf_)->SetPlayState(sles_player_itf_,
471 SL_PLAYSTATE_PLAYING),
472 true);
473 return true;
474}
475
476void OpenSlesOutput::PlayerSimpleBufferQueueCallback(
477 SLAndroidSimpleBufferQueueItf sles_player_sbq_itf,
478 void* p_context) {
479 OpenSlesOutput* audio_device = reinterpret_cast<OpenSlesOutput*>(p_context);
480 audio_device->PlayerSimpleBufferQueueCallbackHandler(sles_player_sbq_itf);
481}
482
483void OpenSlesOutput::PlayerSimpleBufferQueueCallbackHandler(
484 SLAndroidSimpleBufferQueueItf sles_player_sbq_itf) {
485 if (fifo_->size() <= 0 || number_underruns_ > 0) {
486 ++number_underruns_;
487 event_.SignalEvent(kUnderrun, number_underruns_);
488 return;
489 }
490 int8_t* audio = fifo_->Pop();
491 if (audio)
492 OPENSL_RETURN_ON_FAILURE(
493 (*sles_player_sbq_itf)->Enqueue(sles_player_sbq_itf,
494 audio,
495 buffer_size_bytes_),
496 VOID_RETURN);
497 event_.SignalEvent(kNoUnderrun, 0);
498}
499
500bool OpenSlesOutput::StartCbThreads() {
501 play_thread_.reset(ThreadWrapper::CreateThread(CbThread,
502 this,
503 kRealtimePriority,
504 "opensl_play_thread"));
505 assert(play_thread_.get());
506 OPENSL_RETURN_ON_FAILURE(
507 (*sles_player_itf_)->SetPlayState(sles_player_itf_,
508 SL_PLAYSTATE_PLAYING),
509 false);
510
511 unsigned int thread_id = 0;
512 if (!play_thread_->Start(thread_id)) {
513 assert(false);
514 return false;
515 }
516 return true;
517}
518
519void OpenSlesOutput::StopCbThreads() {
520 {
521 CriticalSectionScoped lock(crit_sect_.get());
522 playing_ = false;
523 }
524 if (sles_player_itf_) {
525 OPENSL_RETURN_ON_FAILURE(
526 (*sles_player_itf_)->SetPlayState(sles_player_itf_,
527 SL_PLAYSTATE_STOPPED),
528 VOID_RETURN);
529 }
530 if (play_thread_.get() == NULL) {
531 return;
532 }
533 event_.Stop();
534 if (play_thread_->Stop()) {
535 play_thread_.reset();
536 } else {
537 assert(false);
538 }
539}
540
541bool OpenSlesOutput::CbThread(void* context) {
542 return reinterpret_cast<OpenSlesOutput*>(context)->CbThreadImpl();
543}
544
545bool OpenSlesOutput::CbThreadImpl() {
546 assert(fine_buffer_.get() != NULL);
547 int event_id;
548 int event_msg;
549 // event_ must not be waited on while a lock has been taken.
550 event_.WaitOnEvent(&event_id, &event_msg);
551
552 CriticalSectionScoped lock(crit_sect_.get());
553 if (HandleUnderrun(event_id, event_msg)) {
554 return playing_;
555 }
556 // if fifo_ is not full it means next item in memory must be free.
557 while (fifo_->size() < num_fifo_buffers_needed_ && playing_) {
558 int8_t* audio = play_buf_[active_queue_].get();
559 fine_buffer_->GetBufferData(audio);
560 fifo_->Push(audio);
561 active_queue_ = (active_queue_ + 1) % TotalBuffersUsed();
562 }
563 return playing_;
564}
565
566} // namespace webrtc