void sdl_audiotrack_flush(JNIEnv *env, SDL_AndroidAudioTrack *atrack) { SDLTRACE("sdl_audiotrack_flush"); (*env)->CallVoidMethod(env, atrack->thiz, g_clazz.flush); SDLTRACE("sdl_audiotrack_flush()=void"); if ((*env)->ExceptionCheck(env)) { ALOGE("sdl_audiotrack_flush: flush: Exception:"); (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); return; } }
int SDL_Android_AudioTrack_getAudioSessionId(JNIEnv *env, SDL_Android_AudioTrack *atrack) { SDLTRACE("%s", __func__); int audioSessionId = (*env)->CallIntMethod(env, atrack->thiz, g_clazz.getAudioSessionId); SDLTRACE("%s()=void", __func__); if ((*env)->ExceptionCheck(env)) { ALOGE("%s: Exception:", __func__); (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); return 0; } return audioSessionId; }
static void aout_close_audio(SDL_Aout *aout) { SDLTRACE("aout_close_audio()\n"); SDL_Aout_Opaque *opaque = aout->opaque; if (!opaque) return; SDL_LockMutex(opaque->wakeup_mutex); opaque->abort_request = true; SDL_CondSignal(opaque->wakeup_cond); SDL_UnlockMutex(opaque->wakeup_mutex); SDL_WaitThread(opaque->audio_tid, NULL); opaque->audio_tid = NULL; if (opaque->slPlayItf) (*opaque->slPlayItf)->SetPlayState(opaque->slPlayItf, SL_PLAYSTATE_STOPPED); if (opaque->slBufferQueueItf) (*opaque->slBufferQueueItf)->Clear(opaque->slBufferQueueItf); if (opaque->slBufferQueueItf) opaque->slBufferQueueItf = NULL; if (opaque->slVolumeItf) opaque->slVolumeItf = NULL; if (opaque->slPlayItf) opaque->slPlayItf = NULL; if (opaque->slPlayerObject) { (*opaque->slPlayerObject)->Destroy(opaque->slPlayerObject); opaque->slPlayerObject = NULL; } freep((void **)&opaque->buffer); }
static void aout_free_l(SDL_Aout *aout) { SDLTRACE("%s\n", __func__); if (!aout) return; aout_close_audio(aout); SDL_Aout_Opaque *opaque = aout->opaque; if (opaque->slOutputMixObject) { (*opaque->slOutputMixObject)->Destroy(opaque->slOutputMixObject); opaque->slOutputMixObject = NULL; } opaque->slEngine = NULL; if (opaque->slObject) { (*opaque->slObject)->Destroy(opaque->slObject); opaque->slObject = NULL; } SDL_DestroyCondP(&opaque->wakeup_cond); SDL_DestroyMutexP(&opaque->wakeup_mutex); SDL_Aout_FreeInternal(aout); }
int SDL_Android_AudioTrack_global_init(JNIEnv *env) { jclass clazz; jint sdk_int = SDL_Android_GetApiLevel(); clazz = (*env)->FindClass(env, "android/media/AudioTrack"); IJK_CHECK_RET(clazz, -1, "missing AudioTrack"); // FindClass returns LocalReference g_clazz.clazz = (*env)->NewGlobalRef(env, clazz); IJK_CHECK_RET(g_clazz.clazz, -1, "AudioTrack NewGlobalRef failed"); (*env)->DeleteLocalRef(env, clazz); g_clazz.constructor = (*env)->GetMethodID(env, g_clazz.clazz, "<init>", "(IIIIII)V"); IJK_CHECK_RET(g_clazz.constructor, -1, "missing AudioTrack.<init>"); g_clazz.getMinBufferSize = (*env)->GetStaticMethodID(env, g_clazz.clazz, "getMinBufferSize", "(III)I"); IJK_CHECK_RET(g_clazz.getMinBufferSize, -1, "missing AudioTrack.getMinBufferSize"); g_clazz.getMaxVolume = (*env)->GetStaticMethodID(env, g_clazz.clazz, "getMaxVolume", "()F"); IJK_CHECK_RET(g_clazz.getMaxVolume, -1, "missing AudioTrack.getMaxVolume"); g_clazz.getMinVolume = (*env)->GetStaticMethodID(env, g_clazz.clazz, "getMinVolume", "()F"); IJK_CHECK_RET(g_clazz.getMinVolume, -1, "missing AudioTrack.getMinVolume"); g_clazz.getNativeOutputSampleRate = (*env)->GetStaticMethodID(env, g_clazz.clazz, "getNativeOutputSampleRate", "(I)I"); IJK_CHECK_RET(g_clazz.getNativeOutputSampleRate, -1, "missing AudioTrack.getNativeOutputSampleRate"); g_clazz.play = (*env)->GetMethodID(env, g_clazz.clazz, "play", "()V"); IJK_CHECK_RET(g_clazz.play, -1, "missing AudioTrack.play"); g_clazz.pause = (*env)->GetMethodID(env, g_clazz.clazz, "pause", "()V"); IJK_CHECK_RET(g_clazz.pause, -1, "missing AudioTrack.pause"); g_clazz.flush = (*env)->GetMethodID(env, g_clazz.clazz, "flush", "()V"); IJK_CHECK_RET(g_clazz.flush, -1, "missing AudioTrack.flush"); g_clazz.stop = (*env)->GetMethodID(env, g_clazz.clazz, "stop", "()V"); IJK_CHECK_RET(g_clazz.stop, -1, "missing AudioTrack.stop"); g_clazz.release = (*env)->GetMethodID(env, g_clazz.clazz, "release", "()V"); IJK_CHECK_RET(g_clazz.release, -1, "missing AudioTrack.release"); g_clazz.write_byte = (*env)->GetMethodID(env, g_clazz.clazz, "write", "([BII)I"); IJK_CHECK_RET(g_clazz.write_byte, -1, "missing AudioTrack.write(byte[], ...)"); g_clazz.setStereoVolume = (*env)->GetMethodID(env, g_clazz.clazz, "setStereoVolume", "(FF)I"); IJK_CHECK_RET(g_clazz.setStereoVolume, -1, "missing AudioTrack.setStereoVolume"); g_clazz.getAudioSessionId = (*env)->GetMethodID(env, g_clazz.clazz, "getAudioSessionId", "()I"); IJK_CHECK_RET(g_clazz.getAudioSessionId, -1, "missing AudioTrack.getAudioSessionId"); if (sdk_int >= IJK_API_21_LOLLIPOP) { g_clazz.write_float = (*env)->GetMethodID(env, g_clazz.clazz, "write", "([FIII)I"); IJK_CHECK_RET(g_clazz.write_float, -1, "missing AudioTrack.write(float[], ...)"); } SDLTRACE("android.media.AudioTrack class loaded"); return 0; }
static sdl_amedia_status_t SDL_AMediaCodecJava_configure_surface( JNIEnv*env, SDL_AMediaCodec* acodec, const SDL_AMediaFormat* aformat, jobject android_surface, SDL_AMediaCrypto *crypto, uint32_t flags) { SDLTRACE("SDL_AMediaCodecJava_configure_surface"); // TODO: implement SDL_AMediaCrypto SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque; jobject android_media_format = SDL_AMediaFormatJava_getObject(env, aformat); jobject android_media_codec = SDL_AMediaCodecJava_getObject(env, acodec); ALOGE("configure acodec:%p format:%p: surface:%p", android_media_codec, android_media_format, android_surface); (*env)->CallVoidMethod(env, android_media_codec, g_clazz.jmid_configure, android_media_format, android_surface, crypto, flags); if (SDL_JNI_CatchException(env)) { return SDL_AMEDIA_ERROR_UNKNOWN; } opaque->is_input_buffer_valid = true; SDL_JNI_DeleteGlobalRefP(env, &opaque->input_buffer_array); SDL_JNI_DeleteGlobalRefP(env, &opaque->output_buffer_array); return SDL_AMEDIA_OK; }
static void aout_flush_audio(SDL_Aout *aout) { SDL_Aout_Opaque *opaque = aout->opaque; SDL_LockMutex(opaque->wakeup_mutex); SDLTRACE("aout_flush_audio()"); opaque->need_flush = 1; SDL_CondSignal(opaque->wakeup_cond); SDL_UnlockMutex(opaque->wakeup_mutex); }
int SDL_Android_AudioTrack_getAudioSessionId(JNIEnv *env, SDL_Android_AudioTrack *atrack) { SDLTRACE("%s", __func__); int audioSessionId = JJKC_AudioTrack__getAudioSessionId(env, atrack->thiz); if (JJK_ExceptionCheck__catchAll(env)) return 0; return audioSessionId; }
void SDL_Android_AudioTrack_stop(JNIEnv *env, SDL_Android_AudioTrack *atrack) { SDLTRACE("SDL_Android_AudioTrack_stop"); (*env)->CallVoidMethod(env, atrack->thiz, g_clazz.stop); if ((*env)->ExceptionCheck(env)) { ALOGE("SDL_Android_AudioTrack_stop: stop: Exception:"); (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); return; } }
static void aout_set_volume(SDL_Aout *aout, float left_volume, float right_volume) { SDL_Aout_Opaque *opaque = aout->opaque; SDL_LockMutex(opaque->wakeup_mutex); SDLTRACE("aout_flush_audio()"); opaque->left_volume = left_volume; opaque->right_volume = right_volume; opaque->need_set_volume = 1; SDL_CondSignal(opaque->wakeup_cond); SDL_UnlockMutex(opaque->wakeup_mutex); }
void sdl_audiotrack_release(JNIEnv *env, SDL_AndroidAudioTrack *atrack) { SDLTRACE("sdl_audiotrack_release"); (*env)->CallVoidMethod(env, atrack->thiz, g_clazz.release); if ((*env)->ExceptionCheck(env)) { ALOGE("sdl_audiotrack_release: release: Exception:"); (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); return; } }
static void aout_pause_audio(SDL_Aout *aout, int pause_on) { SDL_Aout_Opaque *opaque = aout->opaque; SDL_LockMutex(opaque->wakeup_mutex); SDLTRACE("aout_pause_audio(%d)", pause_on); opaque->pause_on = pause_on; if (!pause_on) SDL_CondSignal(opaque->wakeup_cond); SDL_UnlockMutex(opaque->wakeup_mutex); }
static void aout_opensles_callback(SLAndroidSimpleBufferQueueItf caller, void *pContext) { SDLTRACE("%s\n", __func__); SDL_Aout *aout = pContext; SDL_Aout_Opaque *opaque = aout->opaque; if (opaque) { SDL_LockMutex(opaque->wakeup_mutex); opaque->is_running = true; SDL_CondSignal(opaque->wakeup_cond); SDL_UnlockMutex(opaque->wakeup_mutex); } }
static float audiotrack_get_min_volume(JNIEnv *env) { SDLTRACE("audiotrack_get_min_volume"); float retval = (*env)->CallStaticFloatMethod(env, g_clazz.clazz, g_clazz.getMinVolume); if ((*env)->ExceptionCheck(env)) { ALOGE("audiotrack_get_min_volume: getMinVolume: Exception:"); (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); return -1; } return retval; }
static int audiotrack_get_native_output_sample_rate(JNIEnv *env) { SDLTRACE("audiotrack_get_native_output_sample_rate"); int retval = (*env)->CallStaticIntMethod(env, g_clazz.clazz, g_clazz.getNativeOutputSampleRate, STREAM_MUSIC); if ((*env)->ExceptionCheck(env)) { ALOGE("audiotrack_get_native_output_sample_rate: getMinVolume: Exception:"); (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); return -1; } return retval; }
static void func_set_playback_rate(SDL_Aout *aout, float speed) { if (!aout) return; SDL_Aout_Opaque *opaque = aout->opaque; SDL_LockMutex(opaque->wakeup_mutex); SDLTRACE("%s %f", __func__, (double)speed); opaque->speed = speed; opaque->speed_changed = 1; SDL_CondSignal(opaque->wakeup_cond); SDL_UnlockMutex(opaque->wakeup_mutex); }
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 aout_open_audio_n(JNIEnv *env, SDL_Aout *aout, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained) { assert(desired); SDL_Aout_Opaque *opaque = aout->opaque; opaque->spec = *desired; opaque->atrack = SDL_Android_AudioTrack_new_from_sdl_spec(env, desired); if (!opaque->atrack) { ALOGE("aout_open_audio_n: failed to new AudioTrcak()"); return -1; } opaque->buffer_size = SDL_Android_AudioTrack_get_min_buffer_size(opaque->atrack); if (opaque->buffer_size <= 0) { ALOGE("aout_open_audio_n: failed to getMinBufferSize()"); SDL_Android_AudioTrack_free(env, opaque->atrack); opaque->atrack = NULL; return -1; } opaque->buffer = malloc(opaque->buffer_size); if (!opaque->buffer) { ALOGE("aout_open_audio_n: failed to allocate buffer"); SDL_Android_AudioTrack_free(env, opaque->atrack); opaque->atrack = NULL; return -1; } if (obtained) { SDL_Android_AudioTrack_get_target_spec(opaque->atrack, obtained); SDLTRACE("audio target format fmt:0x%x, channel:0x%x", (int)obtained->format, (int)obtained->channels); } opaque->audio_session_id = SDL_Android_AudioTrack_getAudioSessionId(env, opaque->atrack); ALOGI("audio_session_id = %d\n", opaque->audio_session_id); opaque->pause_on = 1; opaque->abort_request = 0; opaque->audio_tid = SDL_CreateThreadEx(&opaque->_audio_tid, aout_thread, aout, "ff_aout_android"); if (!opaque->audio_tid) { ALOGE("aout_open_audio_n: failed to create audio thread"); SDL_Android_AudioTrack_free(env, opaque->atrack); opaque->atrack = NULL; return -1; } return 0; }
static int audiotrack_get_min_buffer_size(JNIEnv *env, SDL_AndroidAudioTrack_Spec *spec) { SDLTRACE("audiotrack_get_min_buffer_size"); int retval = (*env)->CallStaticIntMethod(env, g_clazz.clazz, g_clazz.getMinBufferSize, (int) spec->sample_rate_in_hz, (int) spec->channel_config, (int) spec->audio_format); if ((*env)->ExceptionCheck(env)) { ALOGE("audiotrack_get_min_buffer_size: getMinBufferSize: Exception:"); (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); return -1; } return retval; }
SDL_AMediaFormat *SDL_AMediaFormatJava_init(JNIEnv *env, jobject android_format) { SDLTRACE("%s", __func__); jobject global_android_media_format = (*env)->NewGlobalRef(env, android_format); if (J4A_ExceptionCheck__catchAll(env) || !global_android_media_format) { return NULL; } SDL_AMediaFormat *aformat = SDL_AMediaFormat_CreateInternal(sizeof(SDL_AMediaFormat_Opaque)); if (!aformat) { SDL_JNI_DeleteGlobalRefP(env, &global_android_media_format); return NULL; } setup_aformat(aformat, global_android_media_format); return aformat; }
static sdl_amedia_status_t SDL_AMediaCodecJava_flush(SDL_AMediaCodec* acodec) { SDLTRACE("%s", __func__); JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s: SetupThreadEnv failed", __func__); return SDL_AMEDIA_ERROR_UNKNOWN; } jobject android_media_codec = SDL_AMediaCodecJava_getObject(env, acodec); (*env)->CallVoidMethod(env, android_media_codec, g_clazz.jmid_flush, android_media_codec); if (SDL_JNI_CatchException(env)) { ALOGE("%s: flush", __func__); return SDL_AMEDIA_ERROR_UNKNOWN; } return SDL_AMEDIA_OK; }
SDL_AMediaFormat *SDL_AMediaFormatJava_createVideoFormat(JNIEnv *env, const char *mime, int width, int height) { SDLTRACE("%s", __func__); jobject android_media_format = J4AC_MediaFormat__createVideoFormat__withCString__asGlobalRef__catchAll(env, mime, width, height); if (J4A_ExceptionCheck__catchAll(env) || !android_media_format) { return NULL; } SDL_AMediaFormat *aformat = SDL_AMediaFormat_CreateInternal(sizeof(SDL_AMediaFormat_Opaque)); if (!aformat) { SDL_JNI_DeleteGlobalRefP(env, &android_media_format); return NULL; } setup_aformat(aformat, android_media_format); SDL_AMediaFormat_setInt32(aformat, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, 0); return aformat; }
SDL_AMediaCodec* SDL_AMediaCodecJava_createDecoderByType(JNIEnv *env, const char *mime_type) { SDLTRACE("%s", __func__); jstring jmime_type = (*env)->NewStringUTF(env, mime_type); if (SDL_JNI_CatchException(env) || !jmime_type) { return NULL; } jobject local_android_media_codec = (*env)->CallStaticObjectMethod(env, g_clazz.clazz, g_clazz.jmid_createDecoderByType, jmime_type); SDL_JNI_DeleteLocalRefP(env, &jmime_type); if (SDL_JNI_CatchException(env) || !local_android_media_codec) { return NULL; } SDL_AMediaCodec* acodec = SDL_AMediaCodecJava_init(env, local_android_media_codec); SDL_JNI_DeleteLocalRefP(env, &local_android_media_codec); return acodec; }
static SDL_AMediaCodec* SDL_AMediaCodecJava_init(JNIEnv *env, jobject android_media_codec) { SDLTRACE("%s", __func__); jobject global_android_media_codec = (*env)->NewGlobalRef(env, android_media_codec); if (SDL_JNI_CatchException(env) || !global_android_media_codec) { return NULL; } SDL_AMediaCodec *acodec = SDL_AMediaCodec_CreateInternal(sizeof(SDL_AMediaCodec_Opaque)); if (!acodec) { SDL_JNI_DeleteGlobalRefP(env, &global_android_media_codec); return NULL; } SDL_AMediaCodec_Opaque *opaque = acodec->opaque; opaque->android_media_codec = global_android_media_codec; acodec->opaque_class = &g_amediacodec_class; acodec->func_delete = SDL_AMediaCodecJava_delete; acodec->func_configure = NULL; acodec->func_configure_surface = SDL_AMediaCodecJava_configure_surface; acodec->func_start = SDL_AMediaCodecJava_start; acodec->func_stop = SDL_AMediaCodecJava_stop; acodec->func_flush = SDL_AMediaCodecJava_flush; acodec->func_getInputBuffer = SDL_AMediaCodecJava_getInputBuffer; acodec->func_getOutputBuffer = SDL_AMediaCodecJava_getOutputBuffer; acodec->func_dequeueInputBuffer = SDL_AMediaCodecJava_dequeueInputBuffer; acodec->func_queueInputBuffer = SDL_AMediaCodecJava_queueInputBuffer; acodec->func_dequeueOutputBuffer = SDL_AMediaCodecJava_dequeueOutputBuffer; acodec->func_getOutputFormat = SDL_AMediaCodecJava_getOutputFormat; acodec->func_releaseOutputBuffer = SDL_AMediaCodecJava_releaseOutputBuffer; acodec->func_isInputBuffersValid = SDL_AMediaCodecJava_isInputBuffersValid; SDL_AMediaCodec_increaseReference(acodec); return acodec; }
int audiotrack_get_native_output_sample_rate(JNIEnv *env) { if (!env) { if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s: SetupThreadEnv failed", __func__); return -1; } } SDLTRACE("audiotrack_get_native_output_sample_rate"); int retval = (*env)->CallStaticIntMethod(env, g_clazz.clazz, g_clazz.getNativeOutputSampleRate, STREAM_MUSIC); if ((*env)->ExceptionCheck(env)) { ALOGE("audiotrack_get_native_output_sample_rate: getMinVolume: Exception:"); (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); return -1; } return retval; }
SDL_AMediaCodec* SDL_AMediaCodecJava_createByCodecName(JNIEnv *env, const char *codec_name) { SDLTRACE("%s", __func__); jstring jcodec_name = (*env)->NewStringUTF(env, codec_name); if (SDL_JNI_CatchException(env) || !jcodec_name) { return NULL; } jobject local_android_media_codec = (*env)->CallStaticObjectMethod(env, g_clazz.clazz, g_clazz.jmid_createByCodecName, jcodec_name); SDL_JNI_DeleteLocalRefP(env, &jcodec_name); if (SDL_JNI_CatchException(env) || !local_android_media_codec) { return NULL; } SDL_AMediaCodec* acodec = SDL_AMediaCodecJava_init(env, local_android_media_codec); acodec->object_serial = SDL_AMediaCodec_create_object_serial(); SDL_JNI_DeleteLocalRefP(env, &local_android_media_codec); return acodec; }
static sdl_amedia_status_t SDL_AMediaCodecJava_start(SDL_AMediaCodec* acodec) { SDLTRACE("%s", __func__); JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s: SetupThreadEnv failed", __func__); return SDL_AMEDIA_ERROR_UNKNOWN; } SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque; jobject android_media_codec = opaque->android_media_codec; (*env)->CallVoidMethod(env, android_media_codec, g_clazz.jmid_start, android_media_codec); if (SDL_JNI_CatchException(env)) { ALOGE("%s: start failed", __func__); return SDL_AMEDIA_ERROR_UNKNOWN; } return SDL_AMEDIA_OK; }
SDL_VoutOverlay *SDL_VoutAMediaCodec_CreateOverlay(int width, int height, SDL_Vout *vout) { SDLTRACE("SDL_VoutAMediaCodec_CreateOverlay(w=%d, h=%d, fmt=_AMC vout=%p)\n", width, height, vout); SDL_VoutOverlay *overlay = SDL_VoutOverlay_CreateInternal(sizeof(SDL_VoutOverlay_Opaque)); if (!overlay) { ALOGE("overlay allocation failed"); return NULL; } SDL_VoutOverlay_Opaque *opaque = overlay->opaque; opaque->mutex = SDL_CreateMutex(); opaque->vout = vout; opaque->acodec = NULL; opaque->buffer_proxy = NULL; overlay->opaque_class = &g_vout_overlay_amediacodec_class; overlay->format = SDL_FCC__AMC; overlay->pitches = opaque->pitches; overlay->pixels = opaque->pixels; overlay->w = width; overlay->h = height; overlay->is_private = 1; overlay->free_l = overlay_free_l; overlay->lock = overlay_lock; overlay->unlock = overlay_unlock; overlay->unref = overlay_unref; overlay->func_fill_frame = func_fill_frame; if (!opaque->mutex) { ALOGE("SDL_CreateMutex failed"); goto fail; } return overlay; fail: overlay_free_l(overlay); return NULL; }
SDL_VoutOverlay *SDL_VoutAMediaCodec_CreateOverlay(int width, int height, Uint32 format, SDL_Vout *vout) { SDLTRACE("SDL_VoutFFmpeg_CreateOverlay(w=%d, h=%d, fmt=%.4s(0x%x, vout=%p)\n", width, height, (const char*) &format, format, vout); SDL_VoutOverlay *overlay = SDL_VoutOverlay_CreateInternal(sizeof(SDL_VoutOverlay_Opaque)); if (!overlay) { ALOGE("overlay allocation failed"); return NULL; } SDL_VoutOverlay_Opaque *opaque = overlay->opaque; opaque->mutex = SDL_CreateMutex(); overlay->opaque_class = &g_vout_overlay_amediacodec_class; overlay->format = format; overlay->pitches = NULL; overlay->pixels = NULL; overlay->w = width; overlay->h = height; overlay->free_l = overlay_free_l; overlay->lock = overlay_lock; overlay->unlock = overlay_unlock; overlay->unref = overlay_unref; switch (format) { case SDL_FCC__AMC: { break; } default: ALOGE("SDL_VoutAMediaCodec_CreateOverlay(...): unknown format %.4s(0x%x)\n", (char*)&format, format); goto fail; } return overlay; fail: overlay_free_l(overlay); return NULL; }
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; }