一. 底层背景初探
了解了AudioTrack的上层实现只是非常微小的一步。因为在Android的四层架构中,所有的AudioTrack.java以及其他的java类都是framework层中的元素,没有HAL层以及更下层的Linux Kernel是根本做不到播放功能的。可以简单理解为下图,Libraries依赖可以当作HAL层的主要工作。
二. 仍从AudioTrack类说起
之前所说的AudioTrack样例中的部分Java方法,其实都对应了在Hal层的native方法,直接上代码
... ...
public void play( ){
final int delay = getStartDelayMS( ); //AudioTrack继承父类计算播放时延方法
if(delay == 0){
startImpl();
}
else{
new Thread( ){
public void run( ){
Thread.sleep(delay); //播放器player启动,audioMedia还未输入,推迟启动
baseSetStartDelayMS(0);
startImpl();
}
}
}
}
private void startImpl( ){
synchronized(mPlayStateLock){
baseStart( );
native_start();
mPlayState = PLAYSTATE_PLAYING;
}
}
... ...
仔细搜索AudioTrack.java发现native_start其实是jni映射到Hal层的java本地方法。同理,你所看到的stop( ),realese( ),pause( )全都依靠C++的函数实现,AudioTrack中主要本地方法如下:
... ...
private native final void native_finalize();
public native final void native_release();private native final void native_start();
private native final void native_stop();
private native final void native_pause();
private native final void native_flush();
private native final int native_write_byte(byte[] audioData, int offsetInBytes, int sizeInBytes, int format, boolean isBlocking);
private native final int native_write_short(short[] audioData, int offsetInShorts, int sizeInShorts, int format, boolean isBlocking);
private native final int native_write_float(float[] audioData, int offsetInFloats, int sizeInFloats, int format, boolean isBlocking);
... ...
三. JNI方法生成(Tip)
Java当中一旦引入native方法,需要利用javah生成.h头文件,将.h中定义的函数在.c或.cpp中进行实现。
这个过程的实现首先需要将android.jar加入环境变量。对于Linux操作系统,主要办法为
# cp android.jar ./usr/bin //不可用mv,mv相当于剪切,这样Android Studio缺乏Library了
接下来主要过程可以描述为,例如我的Demo.java路径为android/app/src/main/java/sample/
(1)生成.class
package sample
public class Demo{ ... }
我利用java compiler生成.class
xzhan150@GOT120CND80941NN:/android/app/src/main/java/sample$ javac Demo.java
(2) 生成.h头文件
需要退到package的上层目录,(必须和(1)操作在同一个console中!否则会报Demo class not found错误) 如下:
xzhan150@GOT120CND80941NN:/android/app/src/main/java$ javah -jni sample.Demo
这样就会在/android/app/src/main/java路径下生成sample_Demo.h头文件了
四. JNI路径查找
言归正传,找到AudioTrack.java中的native方法,在整个源代码目录下查找。例如我想要寻找包含native_start的代码块,可以利用如下命令:
xzhan150@GOT120CND80941NN:/workspace/frameworks$ grep -rn 'native_start'
base/media/java/android/media/AudioTrack.java:2102: native_start();
base/media/java/android/media/AudioTrack.java:3192: private native final void native_start();
base/media/java/android/media/MediaCodec.java:2051: native_start();
base/media/java/android/media/MediaCodec.java:2057: private native final void native_start();
base/media/java/android/media/AudioRecord.java:989: if (native_start(MediaSyncEvent.SYNC_EVENT_NONE, 0) == SUCCESS) {
base/media/java/android/media/AudioRecord.java:1012: if (native_start(syncEvent.getType(), syncEvent.getAudioSessionId()) == SUCCESS) {
base/media/java/android/media/AudioRecord.java:1761: private native final int native_start(int syncEvent, int sessionId);
base/media/jni/android_media_MediaCodec.cpp:1965: { "native_start", "()V", (void *)android_media_MediaCodec_start },
base/core/java/com/android/internal/os/FuseAppLoop.java:81: native_start(mInstance);
base/core/java/com/android/internal/os/FuseAppLoop.java:311: native void native_start(long ptr);
base/core/jni/com_android_internal_os_FuseAppLoop.cpp:188: "native_start",
base/core/jni/android_media_AudioTrack.cpp:1281: {"native_start", "()V", (void *)android_media_AudioTrack_start},
base/core/jni/android_media_AudioRecord.cpp:839: {"native_start", "(II)I", (void *)android_media_AudioRecord_start},... ...
可以看到base/core/jni/android_media_AudioTrack.cpp是我们想要定位的native方法所在.cpp的C++函数实现。