static const JNINativeMethod gMethods[] = {
{"native_is_direct_output_supported", "(IIIIIII)Z",
(void *)android_media_AudioTrack_is_direct_output_supported},
{"native_start", "()V", (void *)android_media_AudioTrack_start},
{"native_stop", "()V", (void *)android_media_AudioTrack_stop},
{"native_pause", "()V", (void *)android_media_AudioTrack_pause},
{"native_flush", "()V", (void *)android_media_AudioTrack_flush},
{"native_setup",
"(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJZILjava/lang/Object;Ljava/lang/String;)I",
(void *)android_media_AudioTrack_setup},
{"native_finalize", "()V", (void *)android_media_AudioTrack_finalize},
{"native_release", "()V", (void *)android_media_AudioTrack_release},
{"native_write_byte", "([BIIIZ)I", (void *)android_media_AudioTrack_writeArray<jbyteArray>},
{"native_write_native_bytes", "(Ljava/nio/ByteBuffer;IIIZ)I",
(void *)android_media_AudioTrack_write_native_bytes},
{"native_write_short", "([SIIIZ)I",
(void *)android_media_AudioTrack_writeArray<jshortArray>},
{"native_write_float", "([FIIIZ)I",
(void *)android_media_AudioTrack_writeArray<jfloatArray>},
{"native_setVolume", "(FF)V", (void *)android_media_AudioTrack_set_volume},
{"native_get_buffer_size_frames", "()I",
(void *)android_media_AudioTrack_get_buffer_size_frames},
{"native_set_buffer_size_frames", "(I)I",
(void *)android_media_AudioTrack_set_buffer_size_frames},
{"native_get_buffer_capacity_frames", "()I",
(void *)android_media_AudioTrack_get_buffer_capacity_frames},
{"native_set_playback_rate", "(I)I", (void *)android_media_AudioTrack_set_playback_rate},
{"native_get_playback_rate", "()I", (void *)android_media_AudioTrack_get_playback_rate},
{"native_set_playback_params", "(Landroid/media/PlaybackParams;)V",
(void *)android_media_AudioTrack_set_playback_params},
{"native_get_playback_params", "()Landroid/media/PlaybackParams;",
(void *)android_media_AudioTrack_get_playback_params},
{"native_set_marker_pos", "(I)I", (void *)android_media_AudioTrack_set_marker_pos},
{"native_get_marker_pos", "()I", (void *)android_media_AudioTrack_get_marker_pos},
{"native_set_pos_update_period", "(I)I",
(void *)android_media_AudioTrack_set_pos_update_period},
{"native_get_pos_update_period", "()I",
(void *)android_media_AudioTrack_get_pos_update_period},
{"native_set_position", "(I)I", (void *)android_media_AudioTrack_set_position},
{"native_get_position", "()I", (void *)android_media_AudioTrack_get_position},
{"native_get_latency", "()I", (void *)android_media_AudioTrack_get_latency},
{"native_get_underrun_count", "()I", (void *)android_media_AudioTrack_get_underrun_count},
{"native_get_flags", "()I", (void *)android_media_AudioTrack_get_flags},
{"native_get_timestamp", "([J)I", (void *)android_media_AudioTrack_get_timestamp},
{"native_getMetrics", "()Landroid/os/PersistableBundle;",
(void *)android_media_AudioTrack_native_getMetrics},
{"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop},
{"native_reload_static", "()I", (void *)android_media_AudioTrack_reload},
{"native_get_output_sample_rate", "(I)I",
(void *)android_media_AudioTrack_get_output_sample_rate},
{"native_get_min_buff_size", "(III)I", (void *)android_media_AudioTrack_get_min_buff_size},
{"native_setAuxEffectSendLevel", "(F)I",
(void *)android_media_AudioTrack_setAuxEffectSendLevel},
{"native_attachAuxEffect", "(I)I", (void *)android_media_AudioTrack_attachAuxEffect},
{"native_setOutputDevice", "(I)Z", (void *)android_media_AudioTrack_setOutputDevice},
{"native_getRoutedDeviceId", "()I", (void *)android_media_AudioTrack_getRoutedDeviceId},
{"native_enableDeviceCallback", "()V",
(void *)android_media_AudioTrack_enableDeviceCallback},
{"native_disableDeviceCallback", "()V",
(void *)android_media_AudioTrack_disableDeviceCallback},
{"native_applyVolumeShaper",
"(Landroid/media/VolumeShaper$Configuration;Landroid/media/VolumeShaper$Operation;)I",
(void *)android_media_AudioTrack_apply_volume_shaper},
{"native_getVolumeShaperState", "(I)Landroid/media/VolumeShaper$State;",
(void *)android_media_AudioTrack_get_volume_shaper_state},
{"native_setPresentation", "(II)I", (void *)android_media_AudioTrack_setPresentation},
{"native_getPortId", "()I", (void *)android_media_AudioTrack_get_port_id},
{"native_set_delay_padding", "(II)V", (void *)android_media_AudioTrack_set_delay_padding},
{"native_set_audio_description_mix_level_db", "(F)I",
(void *)android_media_AudioTrack_setAudioDescriptionMixLeveldB},
{"native_get_audio_description_mix_level_db", "([F)I",
(void *)android_media_AudioTrack_getAudioDescriptionMixLeveldB},
{"native_set_dual_mono_mode", "(I)I", (void *)android_media_AudioTrack_setDualMonoMode},
{"native_get_dual_mono_mode", "([I)I", (void *)android_media_AudioTrack_getDualMonoMode},
{"native_setLogSessionId", "(Ljava/lang/String;)V",
(void *)android_media_AudioTrack_setLogSessionId},
{"native_setPlayerIId", "(I)V", (void *)android_media_AudioTrack_setPlayerIId},
{"native_setStartThresholdInFrames", "(I)I",
(void *)android_media_AudioTrack_setStartThresholdInFrames},
{"native_getStartThresholdInFrames", "()I",
(void *)android_media_AudioTrack_getStartThresholdInFrames},
};
int register_android_media_AudioTrack(JNIEnv *env)
{
int res = RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
javaAudioTrackFields.nativeTrackInJavaObj = NULL;
javaAudioTrackFields.postNativeEventInJava = NULL;
jclass audioTrackClass = FindClassOrDie(env, kClassPathName);
javaAudioTrackFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
audioTrackClass, JAVA_POSTEVENT_CALLBACK_NAME,
"(Ljava/lang/Object;IIILjava/lang/Object;)V");
javaAudioTrackFields.nativeTrackInJavaObj = GetFieldIDOrDie(env,
audioTrackClass, JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME, "J");
javaAudioTrackFields.jniData = GetFieldIDOrDie(env,
audioTrackClass, JAVA_JNIDATA_FIELD_NAME, "J");
javaAudioTrackFields.fieldStreamType = GetFieldIDOrDie(env,
audioTrackClass, JAVA_STREAMTYPE_FIELD_NAME, "I");
env->DeleteLocalRef(audioTrackClass);
gPlaybackParamsFields.init(env);
gVolumeShaperFields.init(env);
TunerConfigurationHelper::initCheckOrDie(env);
return res;
}
总结:为什么要搞得这么麻烦?
- 如果你在 C++ 里每次调用 Java 方法都临时去找一次 ID(FindClass -> GetMethodID),性能会非常差。
- 这个函数通过“预处理”完成了以下工作:
- 打通道路:让 Java native 关键字能点点点到 C++。
- 记住地址:把 Java 对象的成员变量地址记住,方便 C++ 存取数据(如存入 C++ 指针)。
- 高性能回调:把 Java 的回调方法地址(postEvent)预先存好,确保底层音频事件能以最快速度通知到 Java 层。