SDL_Aout *SDL_AoutAndroid_CreateForOpenSLES() { SDLTRACE("%s\n", __func__); SDL_Aout *aout = SDL_Aout_CreateInternal(sizeof(SDL_Aout_Opaque)); if (!aout) return NULL; SDL_Aout_Opaque *opaque = aout->opaque; opaque->wakeup_cond = SDL_CreateCond(); opaque->wakeup_mutex = SDL_CreateMutex(); int ret = 0; SLObjectItf slObject = NULL; ret = slCreateEngine(&slObject, 0, NULL, 0, NULL, NULL); CHECK_OPENSL_ERROR(ret, "%s: slCreateEngine() failed", __func__); opaque->slObject = slObject; ret = (*slObject)->Realize(slObject, SL_BOOLEAN_FALSE); CHECK_OPENSL_ERROR(ret, "%s: slObject->Realize() failed", __func__); SLEngineItf slEngine = NULL; ret = (*slObject)->GetInterface(slObject, SL_IID_ENGINE, &slEngine); CHECK_OPENSL_ERROR(ret, "%s: slObject->GetInterface() failed", __func__); opaque->slEngine = slEngine; SLObjectItf slOutputMixObject = NULL; const SLInterfaceID ids1[] = {SL_IID_VOLUME}; const SLboolean req1[] = {SL_BOOLEAN_FALSE}; ret = (*slEngine)->CreateOutputMix(slEngine, &slOutputMixObject, 1, ids1, req1); CHECK_OPENSL_ERROR(ret, "%s: slEngine->CreateOutputMix() failed", __func__); opaque->slOutputMixObject = slOutputMixObject; ret = (*slOutputMixObject)->Realize(slOutputMixObject, SL_BOOLEAN_FALSE); CHECK_OPENSL_ERROR(ret, "%s: slOutputMixObject->Realize() failed", __func__); aout->free_l = aout_free_l; aout->opaque_class = &g_opensles_class; aout->open_audio = aout_open_audio; aout->pause_audio = aout_pause_audio; aout->flush_audio = aout_flush_audio; aout->close_audio = aout_close_audio; aout->set_volume = aout_set_volume; aout->func_get_latency_seconds = aout_get_latency_seconds; return aout; fail: aout_free_l(aout); return NULL; }
static int Open(dtaudio_output_t *aout) { aout_sys_t *sys; SLresult result; dtaudio_para_t *para = &aout->para; sys = (aout_sys_t *) malloc(sizeof(*sys)); if (unlikely(sys == NULL)) return -1; sys->p_so_handle = dlopen("libOpenSLES.so", RTLD_NOW); if (sys->p_so_handle == NULL) { goto error; } sys->slCreateEnginePtr = dlsym(sys->p_so_handle, "slCreateEngine"); if (unlikely(sys->slCreateEnginePtr == NULL)) { goto error; } #define OPENSL_DLSYM(dest, name) \ do { \ const SLInterfaceID *sym = dlsym(sys->p_so_handle, "SL_IID_"name); \ if (unlikely(sym == NULL)) \ { \ goto error; \ } \ sys->dest = *sym; \ } while(0) OPENSL_DLSYM(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, "ANDROIDSIMPLEBUFFERQUEUE"); OPENSL_DLSYM(SL_IID_ENGINE, "ENGINE"); OPENSL_DLSYM(SL_IID_PLAY, "PLAY"); OPENSL_DLSYM(SL_IID_VOLUME, "VOLUME"); #undef OPENSL_DLSYM // create engine result = sys->slCreateEnginePtr(&sys->engineObject, 0, NULL, 0, NULL, NULL); CHECK_OPENSL_ERROR("Failed to create engine"); // realize the engine in synchronous mode result = Realize(sys->engineObject, SL_BOOLEAN_FALSE); CHECK_OPENSL_ERROR("Failed to realize engine"); // get the engine interface, needed to create other objects result = GetInterface(sys->engineObject, sys->SL_IID_ENGINE, &sys->engineEngine); CHECK_OPENSL_ERROR("Failed to get the engine interface"); // create output mix, with environmental reverb specified as a non-required interface const SLInterfaceID ids1[] = {sys->SL_IID_VOLUME}; const SLboolean req1[] = {SL_BOOLEAN_FALSE}; result = CreateOutputMix(sys->engineEngine, &sys->outputMixObject, 1, ids1, req1); CHECK_OPENSL_ERROR("Failed to create output mix"); // realize the output mix in synchronous mode result = Realize(sys->outputMixObject, SL_BOOLEAN_FALSE); CHECK_OPENSL_ERROR("Failed to realize output mix"); dt_lock_init(&sys->lock, NULL); if (buf_init(&sys->dbt, para->dst_samplerate * 4 / 10) < 0) // 100ms return -1; aout->ao_priv = (void *) sys; return 0; error: if (sys->outputMixObject) Destroy(sys->outputMixObject); if (sys->engineObject) Destroy(sys->engineObject); if (sys->p_so_handle) dlclose(sys->p_so_handle); free(sys); return -1; }
static int Start(dtaudio_output_t *aout) { SLresult result; aout_sys_t *sys = (aout_sys_t *) aout->ao_priv; dtaudio_para_t *para = &aout->para; // configure audio source - this defines the number of samples you can enqueue. SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, OPENSLES_BUFFERS }; int mask; if (para->dst_channels > 1) mask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; else mask = SL_SPEAKER_FRONT_CENTER; SLDataFormat_PCM format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM; format_pcm.numChannels = para->dst_channels; //format_pcm.samplesPerSec = ((SLuint32) para->dst_samplerate * 1000) ; format_pcm.samplesPerSec = ((SLuint32) convertSampleRate(para->dst_samplerate)); format_pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; format_pcm.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16; format_pcm.channelMask = mask; format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN; SLDataSource audioSrc = {&loc_bufq, &format_pcm}; // configure audio sink SLDataLocator_OutputMix loc_outmix = { SL_DATALOCATOR_OUTPUTMIX, sys->outputMixObject }; SLDataSink audioSnk = {&loc_outmix, NULL}; //create audio player const SLInterfaceID ids2[] = {sys->SL_IID_ANDROIDSIMPLEBUFFERQUEUE, sys->SL_IID_VOLUME}; static const SLboolean req2[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; result = CreateAudioPlayer(sys->engineEngine, &sys->playerObject, &audioSrc, &audioSnk, sizeof(ids2) / sizeof(*ids2), ids2, req2); if (unlikely(result != SL_RESULT_SUCCESS)) { // error return -1; /* Try again with a more sensible samplerate */ #if 0 fmt->i_rate = 44100; format_pcm.samplesPerSec = ((SLuint32) 44100 * 1000) ; result = CreateAudioPlayer(sys->engineEngine, &sys->playerObject, &audioSrc, &audioSnk, sizeof(ids2) / sizeof(*ids2), ids2, req2); #endif } CHECK_OPENSL_ERROR("Failed to create audio player"); result = Realize(sys->playerObject, SL_BOOLEAN_FALSE); CHECK_OPENSL_ERROR("Failed to realize player object."); result = GetInterface(sys->playerObject, sys->SL_IID_PLAY, &sys->playerPlay); CHECK_OPENSL_ERROR("Failed to get player interface."); result = GetInterface(sys->playerObject, sys->SL_IID_VOLUME, &sys->volumeItf); CHECK_OPENSL_ERROR("failed to get volume interface."); result = GetInterface(sys->playerObject, sys->SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &sys->playerBufferQueue); CHECK_OPENSL_ERROR("Failed to get buff queue interface"); result = RegisterCallback(sys->playerBufferQueue, PlayedCallback, (void *) aout); CHECK_OPENSL_ERROR("Failed to register buff queue callback."); // set the player's state to playing result = SetPlayState(sys->playerPlay, SL_PLAYSTATE_PLAYING); CHECK_OPENSL_ERROR("Failed to switch to playing state"); /* XXX: rounding shouldn't affect us at normal sampling rate */ sys->rate = para->dst_samplerate; sys->samples_per_buf = OPENSLES_BUFLEN * para->dst_samplerate / 1000; sys->buf = malloc(OPENSLES_BUFFERS * sys->samples_per_buf * bytesPerSample(aout)); if (!sys->buf) goto error; sys->started = 0; sys->next_buf = 0; sys->samples = 0; SetPositionUpdatePeriod(sys->playerPlay, AOUT_MIN_PREPARE_TIME * 1000 / CLOCK_FREQ); return 0; error: if (sys->playerObject) { Destroy(sys->playerObject); sys->playerObject = NULL; } return -1; }
static int aout_open_audio(SDL_Aout *aout, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained) { SDLTRACE("%s\n", __func__); assert(desired); SDLTRACE("aout_open_audio()\n"); SDL_Aout_Opaque *opaque = aout->opaque; SLEngineItf slEngine = opaque->slEngine; SLDataFormat_PCM *format_pcm = &opaque->format_pcm; int ret = 0; opaque->spec = *desired; // config audio src SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, OPENSLES_BUFFERS }; int native_sample_rate = audiotrack_get_native_output_sample_rate(NULL); ALOGI("OpenSL-ES: native sample rate %d Hz\n", native_sample_rate); CHECK_COND_ERROR((desired->format == AUDIO_S16SYS), "%s: not AUDIO_S16SYS", __func__); CHECK_COND_ERROR((desired->channels == 2 || desired->channels == 1), "%s: not 1,2 channel", __func__); CHECK_COND_ERROR((desired->freq >= 8000 && desired->freq <= 48000), "%s: unsupport freq %d Hz", __func__, desired->freq); if (SDL_Android_GetApiLevel() < IJK_API_21_LOLLIPOP && native_sample_rate > 0 && desired->freq < native_sample_rate) { // Don't try to play back a sample rate higher than the native one, // since OpenSL ES will try to use the fast path, which AudioFlinger // will reject (fast path can't do resampling), and will end up with // too small buffers for the resampling. See http://b.android.com/59453 // for details. This bug is still present in 4.4. If it is fixed later // this workaround could be made conditional. // // by VLC/android_opensles.c ALOGW("OpenSL-ES: force resample %lu to native sample rate %d\n", (unsigned long) format_pcm->samplesPerSec / 1000, (int) native_sample_rate); format_pcm->samplesPerSec = native_sample_rate * 1000; } format_pcm->formatType = SL_DATAFORMAT_PCM; format_pcm->numChannels = desired->channels; format_pcm->samplesPerSec = desired->freq * 1000; // milli Hz // format_pcm->numChannels = 2; // format_pcm->samplesPerSec = SL_SAMPLINGRATE_44_1; format_pcm->bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; format_pcm->containerSize = SL_PCMSAMPLEFORMAT_FIXED_16; switch (desired->channels) { case 2: format_pcm->channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; break; case 1: format_pcm->channelMask = SL_SPEAKER_FRONT_CENTER; break; default: ALOGE("%s, invalid channel %d", __func__, desired->channels); goto fail; } format_pcm->endianness = SL_BYTEORDER_LITTLEENDIAN; SLDataSource audio_source = {&loc_bufq, format_pcm}; // config audio sink SLDataLocator_OutputMix loc_outmix = { SL_DATALOCATOR_OUTPUTMIX, opaque->slOutputMixObject }; SLDataSink audio_sink = {&loc_outmix, NULL}; SLObjectItf slPlayerObject = NULL; const SLInterfaceID ids2[] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_VOLUME, SL_IID_PLAY }; static const SLboolean req2[] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE }; ret = (*slEngine)->CreateAudioPlayer(slEngine, &slPlayerObject, &audio_source, &audio_sink, sizeof(ids2) / sizeof(*ids2), ids2, req2); CHECK_OPENSL_ERROR(ret, "%s: slEngine->CreateAudioPlayer() failed", __func__); opaque->slPlayerObject = slPlayerObject; ret = (*slPlayerObject)->Realize(slPlayerObject, SL_BOOLEAN_FALSE); CHECK_OPENSL_ERROR(ret, "%s: slPlayerObject->Realize() failed", __func__); ret = (*slPlayerObject)->GetInterface(slPlayerObject, SL_IID_PLAY, &opaque->slPlayItf); CHECK_OPENSL_ERROR(ret, "%s: slPlayerObject->GetInterface(SL_IID_PLAY) failed", __func__); ret = (*slPlayerObject)->GetInterface(slPlayerObject, SL_IID_VOLUME, &opaque->slVolumeItf); CHECK_OPENSL_ERROR(ret, "%s: slPlayerObject->GetInterface(SL_IID_VOLUME) failed", __func__); ret = (*slPlayerObject)->GetInterface(slPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &opaque->slBufferQueueItf); CHECK_OPENSL_ERROR(ret, "%s: slPlayerObject->GetInterface(SL_IID_ANDROIDSIMPLEBUFFERQUEUE) failed", __func__); ret = (*opaque->slBufferQueueItf)->RegisterCallback(opaque->slBufferQueueItf, aout_opensles_callback, (void*)aout); CHECK_OPENSL_ERROR(ret, "%s: slBufferQueueItf->RegisterCallback() failed", __func__); // set the player's state to playing // ret = (*opaque->slPlayItf)->SetPlayState(opaque->slPlayItf, SL_PLAYSTATE_PLAYING); // CHECK_OPENSL_ERROR(ret, "%s: slBufferQueueItf->slPlayItf() failed", __func__); opaque->bytes_per_frame = format_pcm->numChannels * format_pcm->bitsPerSample / 8; opaque->milli_per_buffer = OPENSLES_BUFLEN; opaque->frames_per_buffer = opaque->milli_per_buffer * format_pcm->samplesPerSec / 1000000; // samplesPerSec is in milli opaque->bytes_per_buffer = opaque->bytes_per_frame * opaque->frames_per_buffer; opaque->buffer_capacity = OPENSLES_BUFFERS * opaque->bytes_per_buffer; ALOGI("OpenSL-ES: bytes_per_frame = %d bytes\n", (int)opaque->bytes_per_frame); ALOGI("OpenSL-ES: milli_per_buffer = %d ms\n", (int)opaque->milli_per_buffer); ALOGI("OpenSL-ES: frame_per_buffer = %d frames\n", (int)opaque->frames_per_buffer); ALOGI("OpenSL-ES: bytes_per_buffer = %d bytes\n", (int)opaque->bytes_per_buffer); ALOGI("OpenSL-ES: buffer_capacity = %d bytes\n", (int)opaque->buffer_capacity); opaque->buffer = malloc(opaque->buffer_capacity); CHECK_COND_ERROR(opaque->buffer, "%s: failed to alloc buffer %d\n", __func__, (int)opaque->buffer_capacity); // (*opaque->slPlayItf)->SetPositionUpdatePeriod(opaque->slPlayItf, 1000); // enqueue empty buffer to start play memset(opaque->buffer, 0, opaque->buffer_capacity); for(int i = 0; i < OPENSLES_BUFFERS; ++i) { ret = (*opaque->slBufferQueueItf)->Enqueue(opaque->slBufferQueueItf, opaque->buffer + i * opaque->bytes_per_buffer, opaque->bytes_per_buffer); CHECK_OPENSL_ERROR(ret, "%s: slBufferQueueItf->Enqueue(000...) failed", __func__); } opaque->pause_on = 1; opaque->abort_request = 0; opaque->audio_tid = SDL_CreateThreadEx(&opaque->_audio_tid, aout_thread, aout, "ff_aout_opensles"); CHECK_COND_ERROR(opaque->audio_tid, "%s: failed to SDL_CreateThreadEx", __func__); if (obtained) { *obtained = *desired; obtained->size = opaque->buffer_capacity; obtained->freq = format_pcm->samplesPerSec / 1000; } return opaque->buffer_capacity; fail: aout_close_audio(aout); return -1; }