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