int SDL_Android_AudioTrack_reserve_float_buffer(JNIEnv *env, SDL_Android_AudioTrack *atrack, int size_in_float) { if (atrack->float_buffer && size_in_float <= atrack->float_buffer_capacity) return size_in_float; if (atrack->float_buffer) { (*env)->DeleteGlobalRef(env, atrack->float_buffer); atrack->float_buffer = NULL; atrack->float_buffer_capacity = 0; } int capacity = IJKMAX(size_in_float, ((atrack->min_buffer_size + sizeof(jfloat) - 1) / sizeof(jfloat))); jbyteArray float_buffer = (*env)->NewFloatArray(env, capacity); if (!float_buffer || (*env)->ExceptionCheck(env)) { ALOGE("%s: NewFloatArray: Exception:\n", __func__); if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); } return -1; } atrack->float_buffer_capacity = capacity; atrack->float_buffer = (*env)->NewGlobalRef(env, float_buffer); (*env)->DeleteLocalRef(env, float_buffer); return capacity; }
int SDL_Android_AudioTrack_reserve_byte_buffer(JNIEnv *env, SDL_Android_AudioTrack *atrack, int size_in_byte) { if (atrack->byte_buffer && size_in_byte <= atrack->byte_buffer_capacity) return size_in_byte; if (atrack->byte_buffer) { (*env)->DeleteGlobalRef(env, atrack->byte_buffer); atrack->byte_buffer = NULL; atrack->byte_buffer_capacity = 0; } int capacity = IJKMAX(size_in_byte, atrack->min_buffer_size); jbyteArray byte_buffer = (*env)->NewByteArray(env, capacity); if (!byte_buffer || (*env)->ExceptionCheck(env)) { ALOGE("%s: NewByteArray: Exception:", __func__); if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); } return -1; } atrack->byte_buffer_capacity = capacity; atrack->byte_buffer = (*env)->NewGlobalRef(env, byte_buffer); (*env)->DeleteLocalRef(env, byte_buffer); return capacity; }
int SDL_Android_AudioTrack_reserve_byte_buffer(JNIEnv *env, SDL_Android_AudioTrack *atrack, int size_in_byte) { if (atrack->byte_buffer && size_in_byte <= atrack->byte_buffer_capacity) return size_in_byte; JJK_DeleteGlobalRef__p(env, &atrack->byte_buffer); atrack->byte_buffer_capacity = 0; int capacity = IJKMAX(size_in_byte, atrack->min_buffer_size); atrack->byte_buffer = JJK_NewByteArray__asGlobalRef__catchAll(env, capacity); if (!atrack->byte_buffer) return -1; atrack->byte_buffer_capacity = capacity; return capacity; }
SDL_Android_AudioTrack *SDL_Android_AudioTrack_new_from_spec(JNIEnv *env, SDL_Android_AudioTrack_Spec *spec) { assert(spec); jint sdk_int = SDL_Android_GetApiLevel(); switch (spec->channel_config) { case CHANNEL_OUT_MONO: ALOGI("SDL_Android_AudioTrack: %s", "CHANNEL_OUT_MONO"); break; case CHANNEL_OUT_STEREO: ALOGI("SDL_Android_AudioTrack: %s", "CHANNEL_OUT_STEREO"); break; default: ALOGE("SDL_Android_AudioTrack_new_from_spec: invalid channel %d", spec->channel_config); return NULL; } switch (spec->audio_format) { case ENCODING_PCM_16BIT: ALOGI("SDL_Android_AudioTrack: %s", "ENCODING_PCM_16BIT"); break; case ENCODING_PCM_8BIT: ALOGI("SDL_Android_AudioTrack: %s", "ENCODING_PCM_8BIT"); break; case ENCODING_PCM_FLOAT: ALOGI("SDL_Android_AudioTrack: %s", "ENCODING_PCM_FLOAT"); if (sdk_int < IJK_API_21_LOLLIPOP) { ALOGI("SDL_Android_AudioTrack: %s need API 21 or above", "ENCODING_PCM_FLOAT"); return NULL; } break; default: ALOGE("SDL_Android_AudioTrack_new_from_spec: invalid format %d", spec->audio_format); return NULL; } SDL_Android_AudioTrack *atrack = (SDL_Android_AudioTrack*) mallocz(sizeof(SDL_Android_AudioTrack)); if (!atrack) { (*env)->CallVoidMethod(env, atrack->thiz, g_clazz.release); return NULL; } atrack->spec = *spec; if (atrack->spec.sample_rate_in_hz < 4000 || atrack->spec.sample_rate_in_hz > 48000) { int native_sample_rate_in_hz = audiotrack_get_native_output_sample_rate(env); if (native_sample_rate_in_hz > 0) { ALOGE("SDL_Android_AudioTrack_new: cast sample rate %d to %d:", atrack->spec.sample_rate_in_hz, native_sample_rate_in_hz); atrack->spec.sample_rate_in_hz = native_sample_rate_in_hz; } } int min_buffer_size = audiotrack_get_min_buffer_size(env, &atrack->spec); if (min_buffer_size <= 0) { ALOGE("SDL_Android_AudioTrack_new: SDL_Android_AudioTrack_get_min_buffer_size: return %d:", min_buffer_size); free(atrack); return NULL; } jobject thiz = (*env)->NewObject(env, g_clazz.clazz, g_clazz.constructor, (int) atrack->spec.stream_type, (int) atrack->spec.sample_rate_in_hz, (int) atrack->spec.channel_config, (int) atrack->spec.audio_format, (int) min_buffer_size, (int) atrack->spec.mode); if (!thiz || (*env)->ExceptionCheck(env)) { ALOGE("SDL_Android_AudioTrack_new: NewObject: Exception:"); if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); } free(atrack); return NULL; } atrack->min_buffer_size = min_buffer_size; atrack->spec.buffer_size_in_bytes = min_buffer_size; atrack->max_volume = audiotrack_get_max_volume(env); atrack->min_volume = audiotrack_get_min_volume(env); atrack->thiz = (*env)->NewGlobalRef(env, thiz); (*env)->DeleteLocalRef(env, thiz); // extra init float init_volume = 1.0f; init_volume = IJKMIN(init_volume, atrack->max_volume); init_volume = IJKMAX(init_volume, atrack->min_volume); ALOGI("SDL_Android_AudioTrack_new: init volume as %f/(%f,%f)", init_volume, atrack->min_volume, atrack->max_volume); audiotrack_set_stereo_volume(env, atrack, init_volume, init_volume); return atrack; }
SDL_Android_AudioTrack *SDL_Android_AudioTrack_new_from_spec(JNIEnv *env, SDL_Android_AudioTrack_Spec *spec) { assert(spec); switch (spec->channel_config) { case CHANNEL_OUT_MONO: ALOGI("SDL_Android_AudioTrack: %s", "CHANNEL_OUT_MONO"); break; case CHANNEL_OUT_STEREO: ALOGI("SDL_Android_AudioTrack: %s", "CHANNEL_OUT_STEREO"); break; default: ALOGE("%s: invalid channel %d", __func__, spec->channel_config); return NULL; } switch (spec->audio_format) { case ENCODING_PCM_16BIT: ALOGI("SDL_Android_AudioTrack: %s", "ENCODING_PCM_16BIT"); break; case ENCODING_PCM_8BIT: ALOGI("SDL_Android_AudioTrack: %s", "ENCODING_PCM_8BIT"); break; #if 0 case ENCODING_PCM_FLOAT: ALOGI("SDL_Android_AudioTrack: %s", "ENCODING_PCM_FLOAT"); if (sdk_int < IJK_API_21_LOLLIPOP) { ALOGI("SDL_Android_AudioTrack: %s need API 21 or above", "ENCODING_PCM_FLOAT"); return NULL; } break; #endif default: ALOGE("%s: invalid format %d", __func__, spec->audio_format); return NULL; } if (spec->sample_rate_in_hz <= 0) { ALOGE("%s: invalid sample rate %d", __func__, spec->sample_rate_in_hz); return NULL; } SDL_Android_AudioTrack *atrack = (SDL_Android_AudioTrack*) mallocz(sizeof(SDL_Android_AudioTrack)); if (!atrack) { ALOGE("%s: mallocz faild.\n", __func__); return NULL; } atrack->spec = *spec; // libswresample is ugly, depending on native resampler while (atrack->spec.sample_rate_in_hz < 4000) { atrack->spec.sample_rate_in_hz *= 2; } while (atrack->spec.sample_rate_in_hz > 48000) { atrack->spec.sample_rate_in_hz /= 2; } int min_buffer_size = JJKC_AudioTrack__getMinBufferSize(env, atrack->spec.sample_rate_in_hz, atrack->spec.channel_config, atrack->spec.audio_format); if (JJK_ExceptionCheck__catchAll(env) || min_buffer_size <= 0) { ALOGE("%s: JJKC_AudioTrack__getMinBufferSize: return %d:", __func__, min_buffer_size); free(atrack); return NULL; } if (JJK_GetSystemAndroidApiLevel(env) >= 23) { // for fast playback min_buffer_size *= 2; } atrack->thiz = JJKC_AudioTrack__AudioTrack__asGlobalRef__catchAll(env, atrack->spec.stream_type, atrack->spec.sample_rate_in_hz, atrack->spec.channel_config, atrack->spec.audio_format, min_buffer_size, atrack->spec.mode); if (!atrack->thiz) { free(atrack); return NULL; } atrack->min_buffer_size = min_buffer_size; atrack->spec.buffer_size_in_bytes = min_buffer_size; // atrack->max_volume = JJKC_AudioTrack__getMaxVolume__catchAll(env); // atrack->min_volume = JJKC_AudioTrack__getMinVolume__catchAll(env); atrack->max_volume = 0.0f; atrack->min_volume = 1.0f; // extra init float init_volume = 1.0f; init_volume = IJKMIN(init_volume, atrack->max_volume); init_volume = IJKMAX(init_volume, atrack->min_volume); ALOGI("%s: init volume as %f/(%f,%f)", __func__, init_volume, atrack->min_volume, atrack->max_volume); JJKC_AudioTrack__setStereoVolume__catchAll(env, atrack->thiz, init_volume, init_volume); return atrack; }