1 /*
2 * Copyright © 2012 Mozilla Foundation
3 *
4 * This program is made available under an ISC-style license. See the
5 * accompanying file LICENSE for details.
6 */
7 #undef NDEBUG
8 #include <assert.h>
9 #include <dlfcn.h>
10 #include <stdlib.h>
11 #include <pthread.h>
12 #include <SLES/OpenSLES.h>
13 #include <math.h>
14 #include <time.h>
15 #if defined(__ANDROID__)
16 #include <dlfcn.h>
17 #include <sys/system_properties.h>
18 #include "android/sles_definitions.h"
19 #include <SLES/OpenSLES_Android.h>
20 #include <android/log.h>
21 #include <android/api-level.h>
22 #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Cubeb_OpenSL" , ## args)
23 #define ANDROID_VERSION_GINGERBREAD_MR1 10
24 #define ANDROID_VERSION_LOLLIPOP 21
25 #define ANDROID_VERSION_MARSHMALLOW 23
26 #endif
27 #include "cubeb/cubeb.h"
28 #include "cubeb-internal.h"
29 #include "cubeb_resampler.h"
30 #include "cubeb-sles.h"
31
32 static struct cubeb_ops const opensl_ops;
33
34 struct cubeb {
35 struct cubeb_ops const * ops;
36 void * lib;
37 void * libmedia;
38 int32_t (* get_output_latency)(uint32_t * latency, int stream_type);
39 SLInterfaceID SL_IID_BUFFERQUEUE;
40 SLInterfaceID SL_IID_PLAY;
41 #if defined(__ANDROID__)
42 SLInterfaceID SL_IID_ANDROIDCONFIGURATION;
43 #endif
44 SLInterfaceID SL_IID_VOLUME;
45 SLObjectItf engObj;
46 SLEngineItf eng;
47 SLObjectItf outmixObj;
48 };
49
50 #define NELEMS(A) (sizeof(A) / sizeof A[0])
51 #define NBUFS 4
52 #define AUDIO_STREAM_TYPE_MUSIC 3
53
54 struct cubeb_stream {
55 cubeb * context;
56 pthread_mutex_t mutex;
57 SLObjectItf playerObj;
58 SLPlayItf play;
59 SLBufferQueueItf bufq;
60 SLVolumeItf volume;
61 uint8_t *queuebuf[NBUFS];
62 int queuebuf_idx;
63 long queuebuf_len;
64 long bytespersec;
65 long framesize;
66 long written;
67 int draining;
68 cubeb_stream_type stream_type;
69
70 cubeb_data_callback data_callback;
71 cubeb_state_callback state_callback;
72 void * user_ptr;
73
74 cubeb_resampler * resampler;
75 unsigned int inputrate;
76 unsigned int outputrate;
77 unsigned int latency;
78 int64_t lastPosition;
79 int64_t lastPositionTimeStamp;
80 int64_t lastCompensativePosition;
81 };
82
83 static void
play_callback(SLPlayItf caller,void * user_ptr,SLuint32 event)84 play_callback(SLPlayItf caller, void * user_ptr, SLuint32 event)
85 {
86 cubeb_stream * stm = user_ptr;
87 int draining;
88 assert(stm);
89 switch (event) {
90 case SL_PLAYEVENT_HEADATMARKER:
91 pthread_mutex_lock(&stm->mutex);
92 draining = stm->draining;
93 pthread_mutex_unlock(&stm->mutex);
94 if (draining) {
95 stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED);
96 (*stm->play)->SetPlayState(stm->play, SL_PLAYSTATE_PAUSED);
97 }
98 break;
99 default:
100 break;
101 }
102 }
103
104 static void
bufferqueue_callback(SLBufferQueueItf caller,void * user_ptr)105 bufferqueue_callback(SLBufferQueueItf caller, void * user_ptr)
106 {
107 cubeb_stream * stm = user_ptr;
108 assert(stm);
109 SLBufferQueueState state;
110 SLresult res;
111
112 res = (*stm->bufq)->GetState(stm->bufq, &state);
113 assert(res == SL_RESULT_SUCCESS);
114
115 if (state.count > 1)
116 return;
117
118 SLuint32 i;
119 for (i = state.count; i < NBUFS; i++) {
120 uint8_t *buf = stm->queuebuf[stm->queuebuf_idx];
121 long written = 0;
122 pthread_mutex_lock(&stm->mutex);
123 int draining = stm->draining;
124 pthread_mutex_unlock(&stm->mutex);
125
126 if (!draining) {
127 written = cubeb_resampler_fill(stm->resampler,
128 NULL, NULL,
129 buf, stm->queuebuf_len / stm->framesize);
130 if (written < 0 || written * stm->framesize > stm->queuebuf_len) {
131 (*stm->play)->SetPlayState(stm->play, SL_PLAYSTATE_PAUSED);
132 return;
133 }
134 }
135
136 // Keep sending silent data even in draining mode to prevent the audio
137 // back-end from being stopped automatically by OpenSL/ES.
138 memset(buf + written * stm->framesize, 0, stm->queuebuf_len - written * stm->framesize);
139 res = (*stm->bufq)->Enqueue(stm->bufq, buf, stm->queuebuf_len);
140 assert(res == SL_RESULT_SUCCESS);
141 stm->queuebuf_idx = (stm->queuebuf_idx + 1) % NBUFS;
142 if (written > 0) {
143 pthread_mutex_lock(&stm->mutex);
144 stm->written += written;
145 pthread_mutex_unlock(&stm->mutex);
146 }
147
148 if (!draining && written * stm->framesize < stm->queuebuf_len) {
149 pthread_mutex_lock(&stm->mutex);
150 int64_t written_duration = INT64_C(1000) * stm->written * stm->framesize / stm->bytespersec;
151 stm->draining = 1;
152 pthread_mutex_unlock(&stm->mutex);
153 // Use SL_PLAYEVENT_HEADATMARKER event from slPlayCallback of SLPlayItf
154 // to make sure all the data has been processed.
155 (*stm->play)->SetMarkerPosition(stm->play, (SLmillisecond)written_duration);
156 return;
157 }
158 }
159 }
160
161 #if defined(__ANDROID__)
162 static SLuint32
convert_stream_type_to_sl_stream(cubeb_stream_type stream_type)163 convert_stream_type_to_sl_stream(cubeb_stream_type stream_type)
164 {
165 switch(stream_type) {
166 case CUBEB_STREAM_TYPE_SYSTEM:
167 return SL_ANDROID_STREAM_SYSTEM;
168 case CUBEB_STREAM_TYPE_MUSIC:
169 return SL_ANDROID_STREAM_MEDIA;
170 case CUBEB_STREAM_TYPE_NOTIFICATION:
171 return SL_ANDROID_STREAM_NOTIFICATION;
172 case CUBEB_STREAM_TYPE_ALARM:
173 return SL_ANDROID_STREAM_ALARM;
174 case CUBEB_STREAM_TYPE_VOICE_CALL:
175 return SL_ANDROID_STREAM_VOICE;
176 case CUBEB_STREAM_TYPE_RING:
177 return SL_ANDROID_STREAM_RING;
178 case CUBEB_STREAM_TYPE_SYSTEM_ENFORCED:
179 return SL_ANDROID_STREAM_SYSTEM_ENFORCED;
180 default:
181 return 0xFFFFFFFF;
182 }
183 }
184 #endif
185
186 static void opensl_destroy(cubeb * ctx);
187
188 #if defined(__ANDROID__)
189
190 // The bionic header file on B2G contains the required
191 // declarations on all releases.
192 #ifndef MOZ_WIDGET_GONK
193
194 #if (__ANDROID_API__ >= ANDROID_VERSION_LOLLIPOP)
195 typedef int (system_property_get)(const char*, char*);
196
197 static int
__system_property_get(const char * name,char * value)198 __system_property_get(const char* name, char* value)
199 {
200 void* libc = dlopen("libc.so", RTLD_LAZY);
201 if (!libc) {
202 LOG("Failed to open libc.so");
203 return -1;
204 }
205 system_property_get* func = (system_property_get*)
206 dlsym(libc, "__system_property_get");
207 int ret = -1;
208 if (func) {
209 ret = func(name, value);
210 }
211 dlclose(libc);
212 return ret;
213 }
214 #endif
215 #endif
216
217 static int
get_android_version(void)218 get_android_version(void)
219 {
220 char version_string[PROP_VALUE_MAX];
221
222 memset(version_string, 0, PROP_VALUE_MAX);
223
224 int len = __system_property_get("ro.build.version.sdk", version_string);
225 if (len <= 0) {
226 LOG("Failed to get Android version!\n");
227 return len;
228 }
229
230 int version = (int)strtol(version_string, NULL, 10);
231 LOG("%d", version);
232 return version;
233 }
234 #endif
235
236 /*static*/ int
opensl_init(cubeb ** context,char const * context_name)237 opensl_init(cubeb ** context, char const * context_name)
238 {
239 cubeb * ctx;
240
241 #if defined(__ANDROID__)
242 int android_version = get_android_version();
243 if (android_version > 0 && android_version <= ANDROID_VERSION_GINGERBREAD_MR1) {
244 // Don't even attempt to run on Gingerbread and lower
245 return CUBEB_ERROR;
246 }
247 #endif
248
249 *context = NULL;
250
251 ctx = calloc(1, sizeof(*ctx));
252 assert(ctx);
253
254 ctx->ops = &opensl_ops;
255
256 ctx->lib = dlopen("libOpenSLES.so", RTLD_LAZY);
257 ctx->libmedia = dlopen("libmedia.so", RTLD_LAZY);
258 if (!ctx->lib || !ctx->libmedia) {
259 free(ctx);
260 return CUBEB_ERROR;
261 }
262
263 /* Get the latency, in ms, from AudioFlinger */
264 /* status_t AudioSystem::getOutputLatency(uint32_t* latency,
265 * audio_stream_type_t streamType) */
266 /* First, try the most recent signature. */
267 ctx->get_output_latency =
268 dlsym(ctx->libmedia, "_ZN7android11AudioSystem16getOutputLatencyEPj19audio_stream_type_t");
269 if (!ctx->get_output_latency) {
270 /* in case of failure, try the legacy version. */
271 /* status_t AudioSystem::getOutputLatency(uint32_t* latency,
272 * int streamType) */
273 ctx->get_output_latency =
274 dlsym(ctx->libmedia, "_ZN7android11AudioSystem16getOutputLatencyEPji");
275 if (!ctx->get_output_latency) {
276 opensl_destroy(ctx);
277 return CUBEB_ERROR;
278 }
279 }
280
281 typedef SLresult (*slCreateEngine_t)(SLObjectItf *,
282 SLuint32,
283 const SLEngineOption *,
284 SLuint32,
285 const SLInterfaceID *,
286 const SLboolean *);
287 slCreateEngine_t f_slCreateEngine =
288 (slCreateEngine_t)dlsym(ctx->lib, "slCreateEngine");
289 SLInterfaceID SL_IID_ENGINE = *(SLInterfaceID *)dlsym(ctx->lib, "SL_IID_ENGINE");
290 SLInterfaceID SL_IID_OUTPUTMIX = *(SLInterfaceID *)dlsym(ctx->lib, "SL_IID_OUTPUTMIX");
291 ctx->SL_IID_VOLUME = *(SLInterfaceID *)dlsym(ctx->lib, "SL_IID_VOLUME");
292 ctx->SL_IID_BUFFERQUEUE = *(SLInterfaceID *)dlsym(ctx->lib, "SL_IID_BUFFERQUEUE");
293 #if defined(__ANDROID__)
294 ctx->SL_IID_ANDROIDCONFIGURATION = *(SLInterfaceID *)dlsym(ctx->lib, "SL_IID_ANDROIDCONFIGURATION");
295 #endif
296 ctx->SL_IID_PLAY = *(SLInterfaceID *)dlsym(ctx->lib, "SL_IID_PLAY");
297 if (!f_slCreateEngine ||
298 !SL_IID_ENGINE ||
299 !SL_IID_OUTPUTMIX ||
300 !ctx->SL_IID_BUFFERQUEUE ||
301 #if defined(__ANDROID__)
302 !ctx->SL_IID_ANDROIDCONFIGURATION ||
303 #endif
304 !ctx->SL_IID_PLAY) {
305 opensl_destroy(ctx);
306 return CUBEB_ERROR;
307 }
308
309 const SLEngineOption opt[] = {{SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE}};
310
311 SLresult res;
312 res = cubeb_get_sles_engine(&ctx->engObj, 1, opt, 0, NULL, NULL);
313
314 if (res != SL_RESULT_SUCCESS) {
315 opensl_destroy(ctx);
316 return CUBEB_ERROR;
317 }
318
319 res = cubeb_realize_sles_engine(ctx->engObj);
320 if (res != SL_RESULT_SUCCESS) {
321 opensl_destroy(ctx);
322 return CUBEB_ERROR;
323 }
324
325 res = (*ctx->engObj)->GetInterface(ctx->engObj, SL_IID_ENGINE, &ctx->eng);
326 if (res != SL_RESULT_SUCCESS) {
327 opensl_destroy(ctx);
328 return CUBEB_ERROR;
329 }
330
331 const SLInterfaceID idsom[] = {SL_IID_OUTPUTMIX};
332 const SLboolean reqom[] = {SL_BOOLEAN_TRUE};
333 res = (*ctx->eng)->CreateOutputMix(ctx->eng, &ctx->outmixObj, 1, idsom, reqom);
334 if (res != SL_RESULT_SUCCESS) {
335 opensl_destroy(ctx);
336 return CUBEB_ERROR;
337 }
338
339 res = (*ctx->outmixObj)->Realize(ctx->outmixObj, SL_BOOLEAN_FALSE);
340 if (res != SL_RESULT_SUCCESS) {
341 opensl_destroy(ctx);
342 return CUBEB_ERROR;
343 }
344
345 *context = ctx;
346
347 return CUBEB_OK;
348 }
349
350 static char const *
opensl_get_backend_id(cubeb * ctx)351 opensl_get_backend_id(cubeb * ctx)
352 {
353 return "opensl";
354 }
355
356 static int
opensl_get_max_channel_count(cubeb * ctx,uint32_t * max_channels)357 opensl_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
358 {
359 assert(ctx && max_channels);
360 /* The android mixer handles up to two channels, see
361 http://androidxref.com/4.2.2_r1/xref/frameworks/av/services/audioflinger/AudioFlinger.h#67 */
362 *max_channels = 2;
363
364 return CUBEB_OK;
365 }
366
367 static int
opensl_get_preferred_sample_rate(cubeb * ctx,uint32_t * rate)368 opensl_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
369 {
370 /* https://android.googlesource.com/platform/ndk.git/+/master/docs/opensles/index.html
371 * We don't want to deal with JNI here (and we don't have Java on b2g anyways),
372 * so we just dlopen the library and get the two symbols we need. */
373 int r;
374 void * libmedia;
375 uint32_t (*get_primary_output_samplingrate)();
376 uint32_t (*get_output_samplingrate)(int * samplingRate, int streamType);
377
378 libmedia = dlopen("libmedia.so", RTLD_LAZY);
379 if (!libmedia) {
380 return CUBEB_ERROR;
381 }
382
383 /* uint32_t AudioSystem::getPrimaryOutputSamplingRate(void) */
384 get_primary_output_samplingrate =
385 dlsym(libmedia, "_ZN7android11AudioSystem28getPrimaryOutputSamplingRateEv");
386 if (!get_primary_output_samplingrate) {
387 /* fallback to
388 * status_t AudioSystem::getOutputSamplingRate(int* samplingRate, int streamType)
389 * if we cannot find getPrimaryOutputSamplingRate. */
390 get_output_samplingrate =
391 dlsym(libmedia, "_ZN7android11AudioSystem21getOutputSamplingRateEPj19audio_stream_type_t");
392 if (!get_output_samplingrate) {
393 /* Another signature exists, with a int instead of an audio_stream_type_t */
394 get_output_samplingrate =
395 dlsym(libmedia, "_ZN7android11AudioSystem21getOutputSamplingRateEPii");
396 if (!get_output_samplingrate) {
397 dlclose(libmedia);
398 return CUBEB_ERROR;
399 }
400 }
401 }
402
403 if (get_primary_output_samplingrate) {
404 *rate = get_primary_output_samplingrate();
405 } else {
406 /* We don't really know about the type, here, so we just pass music. */
407 r = get_output_samplingrate((int *) rate, AUDIO_STREAM_TYPE_MUSIC);
408 if (r) {
409 dlclose(libmedia);
410 return CUBEB_ERROR;
411 }
412 }
413
414 dlclose(libmedia);
415
416 /* Depending on which method we called above, we can get a zero back, yet have
417 * a non-error return value, especially if the audio system is not
418 * ready/shutting down (i.e. when we can't get our hand on the AudioFlinger
419 * thread). */
420 if (*rate == 0) {
421 return CUBEB_ERROR;
422 }
423
424 return CUBEB_OK;
425 }
426
427 static int
opensl_get_min_latency(cubeb * ctx,cubeb_stream_params params,uint32_t * latency_frames)428 opensl_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_frames)
429 {
430 /* https://android.googlesource.com/platform/ndk.git/+/master/docs/opensles/index.html
431 * We don't want to deal with JNI here (and we don't have Java on b2g anyways),
432 * so we just dlopen the library and get the two symbols we need. */
433
434 int r;
435 void * libmedia;
436 size_t (*get_primary_output_frame_count)(void);
437 int (*get_output_frame_count)(size_t * frameCount, int streamType);
438 uint32_t primary_sampling_rate;
439 size_t primary_buffer_size;
440
441 r = opensl_get_preferred_sample_rate(ctx, &primary_sampling_rate);
442
443 if (r) {
444 return CUBEB_ERROR;
445 }
446
447 libmedia = dlopen("libmedia.so", RTLD_LAZY);
448 if (!libmedia) {
449 return CUBEB_ERROR;
450 }
451
452 /* JB variant */
453 /* size_t AudioSystem::getPrimaryOutputFrameCount(void) */
454 get_primary_output_frame_count =
455 dlsym(libmedia, "_ZN7android11AudioSystem26getPrimaryOutputFrameCountEv");
456 if (!get_primary_output_frame_count) {
457 /* ICS variant */
458 /* status_t AudioSystem::getOutputFrameCount(int* frameCount, int streamType) */
459 get_output_frame_count =
460 dlsym(libmedia, "_ZN7android11AudioSystem19getOutputFrameCountEPii");
461 if (!get_output_frame_count) {
462 dlclose(libmedia);
463 return CUBEB_ERROR;
464 }
465 }
466
467 if (get_primary_output_frame_count) {
468 primary_buffer_size = get_primary_output_frame_count();
469 } else {
470 if (get_output_frame_count(&primary_buffer_size, params.stream_type) != 0) {
471 return CUBEB_ERROR;
472 }
473 }
474
475 /* To get a fast track in Android's mixer, we need to be at the native
476 * samplerate, which is device dependant. Some devices might be able to
477 * resample when playing a fast track, but it's pretty rare. */
478 *latency_frames = NBUFS * primary_buffer_size;
479
480 dlclose(libmedia);
481
482 return CUBEB_OK;
483 }
484
485 static void
opensl_destroy(cubeb * ctx)486 opensl_destroy(cubeb * ctx)
487 {
488 if (ctx->outmixObj)
489 (*ctx->outmixObj)->Destroy(ctx->outmixObj);
490 if (ctx->engObj)
491 cubeb_destroy_sles_engine(&ctx->engObj);
492 dlclose(ctx->lib);
493 dlclose(ctx->libmedia);
494 free(ctx);
495 }
496
497 static void opensl_stream_destroy(cubeb_stream * stm);
498
499 static int
opensl_stream_init(cubeb * ctx,cubeb_stream ** stream,char const * stream_name,cubeb_devid input_device,cubeb_stream_params * input_stream_params,cubeb_devid output_device,cubeb_stream_params * output_stream_params,unsigned int latency_frames,cubeb_data_callback data_callback,cubeb_state_callback state_callback,void * user_ptr)500 opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
501 cubeb_devid input_device,
502 cubeb_stream_params * input_stream_params,
503 cubeb_devid output_device,
504 cubeb_stream_params * output_stream_params,
505 unsigned int latency_frames,
506 cubeb_data_callback data_callback, cubeb_state_callback state_callback,
507 void * user_ptr)
508 {
509 cubeb_stream * stm;
510
511 assert(ctx);
512 assert(!input_stream_params && "not supported");
513 if (input_device || output_device) {
514 /* Device selection not yet implemented. */
515 return CUBEB_ERROR_DEVICE_UNAVAILABLE;
516 }
517
518 *stream = NULL;
519
520 SLDataFormat_PCM format;
521
522 format.formatType = SL_DATAFORMAT_PCM;
523 format.numChannels = output_stream_params->channels;
524 // samplesPerSec is in milliHertz
525 format.samplesPerSec = output_stream_params->rate * 1000;
526 format.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
527 format.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16;
528 format.channelMask = output_stream_params->channels == 1 ?
529 SL_SPEAKER_FRONT_CENTER :
530 SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
531
532 switch (output_stream_params->format) {
533 case CUBEB_SAMPLE_S16LE:
534 format.endianness = SL_BYTEORDER_LITTLEENDIAN;
535 break;
536 case CUBEB_SAMPLE_S16BE:
537 format.endianness = SL_BYTEORDER_BIGENDIAN;
538 break;
539 default:
540 return CUBEB_ERROR_INVALID_FORMAT;
541 }
542
543 stm = calloc(1, sizeof(*stm));
544 assert(stm);
545
546 stm->context = ctx;
547 stm->data_callback = data_callback;
548 stm->state_callback = state_callback;
549 stm->user_ptr = user_ptr;
550
551 stm->inputrate = output_stream_params->rate;
552 stm->latency = latency_frames;
553 stm->stream_type = output_stream_params->stream_type;
554 stm->framesize = output_stream_params->channels * sizeof(int16_t);
555 stm->lastPosition = -1;
556 stm->lastPositionTimeStamp = 0;
557 stm->lastCompensativePosition = -1;
558
559 int r = pthread_mutex_init(&stm->mutex, NULL);
560 assert(r == 0);
561
562 SLDataLocator_BufferQueue loc_bufq;
563 loc_bufq.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
564 loc_bufq.numBuffers = NBUFS;
565 SLDataSource source;
566 source.pLocator = &loc_bufq;
567 source.pFormat = &format;
568
569 SLDataLocator_OutputMix loc_outmix;
570 loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
571 loc_outmix.outputMix = ctx->outmixObj;
572 SLDataSink sink;
573 sink.pLocator = &loc_outmix;
574 sink.pFormat = NULL;
575
576 #if defined(__ANDROID__)
577 const SLInterfaceID ids[] = {ctx->SL_IID_BUFFERQUEUE,
578 ctx->SL_IID_VOLUME,
579 ctx->SL_IID_ANDROIDCONFIGURATION};
580 const SLboolean req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
581 #else
582 const SLInterfaceID ids[] = {ctx->SL_IID_BUFFERQUEUE, ctx->SL_IID_VOLUME};
583 const SLboolean req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
584 #endif
585 assert(NELEMS(ids) == NELEMS(req));
586
587 uint32_t preferred_sampling_rate = stm->inputrate;
588 #if defined(__ANDROID__)
589 if (get_android_version() >= ANDROID_VERSION_MARSHMALLOW) {
590 // Reset preferred samping rate to trigger fallback to native sampling rate.
591 preferred_sampling_rate = 0;
592 if (opensl_get_min_latency(ctx, *output_stream_params, &latency_frames) != CUBEB_OK) {
593 // Default to AudioFlinger's advertised fast track latency of 10ms.
594 latency_frames = 440;
595 }
596 stm->latency = latency_frames;
597 }
598 #endif
599
600 SLresult res = SL_RESULT_CONTENT_UNSUPPORTED;
601 if (preferred_sampling_rate) {
602 res = (*ctx->eng)->CreateAudioPlayer(ctx->eng, &stm->playerObj, &source,
603 &sink, NELEMS(ids), ids, req);
604 }
605
606 // Sample rate not supported? Try again with primary sample rate!
607 if (res == SL_RESULT_CONTENT_UNSUPPORTED) {
608 if (opensl_get_preferred_sample_rate(ctx, &preferred_sampling_rate)) {
609 opensl_stream_destroy(stm);
610 return CUBEB_ERROR;
611 }
612
613 format.samplesPerSec = preferred_sampling_rate * 1000;
614 res = (*ctx->eng)->CreateAudioPlayer(ctx->eng, &stm->playerObj,
615 &source, &sink, NELEMS(ids), ids, req);
616 }
617
618 if (res != SL_RESULT_SUCCESS) {
619 opensl_stream_destroy(stm);
620 return CUBEB_ERROR;
621 }
622
623 stm->outputrate = preferred_sampling_rate;
624 stm->bytespersec = stm->outputrate * stm->framesize;
625 stm->queuebuf_len = stm->framesize * latency_frames / NBUFS;
626 // round up to the next multiple of stm->framesize, if needed.
627 if (stm->queuebuf_len % stm->framesize) {
628 stm->queuebuf_len += stm->framesize - (stm->queuebuf_len % stm->framesize);
629 }
630
631 cubeb_stream_params params = *output_stream_params;
632 params.rate = preferred_sampling_rate;
633
634 stm->resampler = cubeb_resampler_create(stm, NULL, ¶ms,
635 output_stream_params->rate,
636 data_callback,
637 user_ptr,
638 CUBEB_RESAMPLER_QUALITY_DEFAULT);
639
640 if (!stm->resampler) {
641 opensl_stream_destroy(stm);
642 return CUBEB_ERROR;
643 }
644
645 int i;
646 for (i = 0; i < NBUFS; i++) {
647 stm->queuebuf[i] = malloc(stm->queuebuf_len);
648 assert(stm->queuebuf[i]);
649 }
650
651 #if defined(__ANDROID__)
652 SLuint32 stream_type = convert_stream_type_to_sl_stream(output_stream_params->stream_type);
653 if (stream_type != 0xFFFFFFFF) {
654 SLAndroidConfigurationItf playerConfig;
655 res = (*stm->playerObj)->GetInterface(stm->playerObj,
656 ctx->SL_IID_ANDROIDCONFIGURATION, &playerConfig);
657 res = (*playerConfig)->SetConfiguration(playerConfig,
658 SL_ANDROID_KEY_STREAM_TYPE, &stream_type, sizeof(SLint32));
659 if (res != SL_RESULT_SUCCESS) {
660 opensl_stream_destroy(stm);
661 return CUBEB_ERROR;
662 }
663 }
664 #endif
665
666 res = (*stm->playerObj)->Realize(stm->playerObj, SL_BOOLEAN_FALSE);
667 if (res != SL_RESULT_SUCCESS) {
668 opensl_stream_destroy(stm);
669 return CUBEB_ERROR;
670 }
671
672 res = (*stm->playerObj)->GetInterface(stm->playerObj, ctx->SL_IID_PLAY, &stm->play);
673 if (res != SL_RESULT_SUCCESS) {
674 opensl_stream_destroy(stm);
675 return CUBEB_ERROR;
676 }
677
678 res = (*stm->playerObj)->GetInterface(stm->playerObj, ctx->SL_IID_BUFFERQUEUE,
679 &stm->bufq);
680 if (res != SL_RESULT_SUCCESS) {
681 opensl_stream_destroy(stm);
682 return CUBEB_ERROR;
683 }
684
685 res = (*stm->playerObj)->GetInterface(stm->playerObj, ctx->SL_IID_VOLUME,
686 &stm->volume);
687
688 if (res != SL_RESULT_SUCCESS) {
689 opensl_stream_destroy(stm);
690 return CUBEB_ERROR;
691 }
692
693 res = (*stm->play)->RegisterCallback(stm->play, play_callback, stm);
694 if (res != SL_RESULT_SUCCESS) {
695 opensl_stream_destroy(stm);
696 return CUBEB_ERROR;
697 }
698
699 // Work around wilhelm/AudioTrack badness, bug 1221228
700 (*stm->play)->SetMarkerPosition(stm->play, (SLmillisecond)0);
701
702 res = (*stm->play)->SetCallbackEventsMask(stm->play, (SLuint32)SL_PLAYEVENT_HEADATMARKER);
703 if (res != SL_RESULT_SUCCESS) {
704 opensl_stream_destroy(stm);
705 return CUBEB_ERROR;
706 }
707
708 res = (*stm->bufq)->RegisterCallback(stm->bufq, bufferqueue_callback, stm);
709 if (res != SL_RESULT_SUCCESS) {
710 opensl_stream_destroy(stm);
711 return CUBEB_ERROR;
712 }
713
714 {
715 // Enqueue a silent frame so once the player becomes playing, the frame
716 // will be consumed and kick off the buffer queue callback.
717 // Note the duration of a single frame is less than 1ms. We don't bother
718 // adjusting the playback position.
719 uint8_t *buf = stm->queuebuf[stm->queuebuf_idx++];
720 memset(buf, 0, stm->framesize);
721 res = (*stm->bufq)->Enqueue(stm->bufq, buf, stm->framesize);
722 assert(res == SL_RESULT_SUCCESS);
723 }
724
725 *stream = stm;
726 return CUBEB_OK;
727 }
728
729 static void
opensl_stream_destroy(cubeb_stream * stm)730 opensl_stream_destroy(cubeb_stream * stm)
731 {
732 if (stm->playerObj)
733 (*stm->playerObj)->Destroy(stm->playerObj);
734 int i;
735 for (i = 0; i < NBUFS; i++) {
736 free(stm->queuebuf[i]);
737 }
738 pthread_mutex_destroy(&stm->mutex);
739
740 cubeb_resampler_destroy(stm->resampler);
741
742 free(stm);
743 }
744
745 static int
opensl_stream_start(cubeb_stream * stm)746 opensl_stream_start(cubeb_stream * stm)
747 {
748 SLresult res = (*stm->play)->SetPlayState(stm->play, SL_PLAYSTATE_PLAYING);
749 if (res != SL_RESULT_SUCCESS)
750 return CUBEB_ERROR;
751 stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STARTED);
752 return CUBEB_OK;
753 }
754
755 static int
opensl_stream_stop(cubeb_stream * stm)756 opensl_stream_stop(cubeb_stream * stm)
757 {
758 SLresult res = (*stm->play)->SetPlayState(stm->play, SL_PLAYSTATE_PAUSED);
759 if (res != SL_RESULT_SUCCESS)
760 return CUBEB_ERROR;
761 stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED);
762 return CUBEB_OK;
763 }
764
765 static int
opensl_stream_get_position(cubeb_stream * stm,uint64_t * position)766 opensl_stream_get_position(cubeb_stream * stm, uint64_t * position)
767 {
768 SLmillisecond msec;
769 uint64_t samplerate;
770 SLresult res;
771 int r;
772 uint32_t mixer_latency;
773 uint32_t compensation_msec = 0;
774
775 res = (*stm->play)->GetPosition(stm->play, &msec);
776 if (res != SL_RESULT_SUCCESS)
777 return CUBEB_ERROR;
778
779 struct timespec t;
780 clock_gettime(CLOCK_MONOTONIC, &t);
781 if(stm->lastPosition == msec) {
782 compensation_msec =
783 (t.tv_sec*1000000000LL + t.tv_nsec - stm->lastPositionTimeStamp) / 1000000;
784 } else {
785 stm->lastPositionTimeStamp = t.tv_sec*1000000000LL + t.tv_nsec;
786 stm->lastPosition = msec;
787 }
788
789 samplerate = stm->inputrate;
790
791 r = stm->context->get_output_latency(&mixer_latency, stm->stream_type);
792 if (r) {
793 return CUBEB_ERROR;
794 }
795
796 pthread_mutex_lock(&stm->mutex);
797 int64_t maximum_position = stm->written * (int64_t)stm->inputrate / stm->outputrate;
798 pthread_mutex_unlock(&stm->mutex);
799 assert(maximum_position >= 0);
800
801 if (msec > mixer_latency) {
802 int64_t unadjusted_position;
803 if (stm->lastCompensativePosition > msec + compensation_msec) {
804 // Over compensation, use lastCompensativePosition.
805 unadjusted_position =
806 samplerate * (stm->lastCompensativePosition - mixer_latency) / 1000;
807 } else {
808 unadjusted_position =
809 samplerate * (msec - mixer_latency + compensation_msec) / 1000;
810 stm->lastCompensativePosition = msec + compensation_msec;
811 }
812 *position = unadjusted_position < maximum_position ?
813 unadjusted_position : maximum_position;
814 } else {
815 *position = 0;
816 }
817 return CUBEB_OK;
818 }
819
820 int
opensl_stream_get_latency(cubeb_stream * stm,uint32_t * latency)821 opensl_stream_get_latency(cubeb_stream * stm, uint32_t * latency)
822 {
823 int r;
824 uint32_t mixer_latency; // The latency returned by AudioFlinger is in ms.
825
826 /* audio_stream_type_t is an int, so this is okay. */
827 r = stm->context->get_output_latency(&mixer_latency, stm->stream_type);
828 if (r) {
829 return CUBEB_ERROR;
830 }
831
832 *latency = stm->latency * stm->inputrate / 1000 + // OpenSL latency
833 mixer_latency * stm->inputrate / 1000; // AudioFlinger latency
834
835 return CUBEB_OK;
836 }
837
838 int
opensl_stream_set_volume(cubeb_stream * stm,float volume)839 opensl_stream_set_volume(cubeb_stream * stm, float volume)
840 {
841 SLresult res;
842 SLmillibel max_level, millibels;
843 float unclamped_millibels;
844
845 res = (*stm->volume)->GetMaxVolumeLevel(stm->volume, &max_level);
846
847 if (res != SL_RESULT_SUCCESS) {
848 return CUBEB_ERROR;
849 }
850
851 /* millibels are 100*dB, so the conversion from the volume's linear amplitude
852 * is 100 * 20 * log(volume). However we clamp the resulting value before
853 * passing it to lroundf() in order to prevent it from silently returning an
854 * erroneous value when the unclamped value exceeds the size of a long. */
855 unclamped_millibels = 100.0f * 20.0f * log10f(fmaxf(volume, 0.0f));
856 unclamped_millibels = fmaxf(unclamped_millibels, SL_MILLIBEL_MIN);
857 unclamped_millibels = fminf(unclamped_millibels, max_level);
858
859 millibels = lroundf(unclamped_millibels);
860
861 res = (*stm->volume)->SetVolumeLevel(stm->volume, millibels);
862
863 if (res != SL_RESULT_SUCCESS) {
864 return CUBEB_ERROR;
865 }
866 return CUBEB_OK;
867 }
868
869 static struct cubeb_ops const opensl_ops = {
870 .init = opensl_init,
871 .get_backend_id = opensl_get_backend_id,
872 .get_max_channel_count = opensl_get_max_channel_count,
873 .get_min_latency = opensl_get_min_latency,
874 .get_preferred_sample_rate = opensl_get_preferred_sample_rate,
875 .enumerate_devices = NULL,
876 .destroy = opensl_destroy,
877 .stream_init = opensl_stream_init,
878 .stream_destroy = opensl_stream_destroy,
879 .stream_start = opensl_stream_start,
880 .stream_stop = opensl_stream_stop,
881 .stream_get_position = opensl_stream_get_position,
882 .stream_get_latency = opensl_stream_get_latency,
883 .stream_set_volume = opensl_stream_set_volume,
884 .stream_set_panning = NULL,
885 .stream_get_current_device = NULL,
886 .stream_device_destroy = NULL,
887 .stream_register_device_changed_callback = NULL,
888 .register_device_collection_changed = NULL
889 };
890