在前面介绍创建AudioTrack的native实例后,会调用set,这里就在搭建进行native AudioTrack和java层进行通信的桥梁audioCallback,
android_media_AudioTrack.cpp
lpTrack = new AudioTrack();
case MODE_STREAM:
status = lpTrack->set( AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument) sampleRateInHertz, format,// word length, PCM nativeChannelMask, frameCount, AUDIO_OUTPUT_FLAG_NONE, audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user) 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack 0,// shared mem true,// thread can call Java sessionId,// audio session ID AudioTrack::TRANSFER_SYNC, NULL, // default offloadInfo -1, -1, // default uid, pid values paa);
|
1)先向下看
在AudioTrack里,cb被赋值给mCbf,并在set里根据cbf创建了一个AudioTrackThread线程,
status_t AudioTrack::set( audio_stream_type_t streamType, uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, size_t frameCount, audio_output_flags_t flags, callback_t cbf, void* user, … { mCbf = cbf;
if (cbf != NULL) { mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava); mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/); // thread begins in paused state, and will not reference us until start() } … } |
AudioTrackThread线程的threadLoop的调用AudioTrack自身处理音频缓冲,
AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava) : Thread(bCanCallJava), mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL), mIgnoreNextPausedInt(false) { }
bool AudioTrack::AudioTrackThread::threadLoop() { … nsecs_t ns = mReceiver.processAudioBuffer(); … } |
mCbf即audioCallback被调用,开始向上传递事件和数据,
nsecs_t AudioTrack::processAudioBuffer() { mCbf(EVENT_STREAM_END, mUserData, NULL); … } |
2)再向上看,
android_media_AudioTrack.cpp里,通过虚拟机调用和javaAudioTrackFields.postNativeEventInJava对应的java层函数,
static void audioCallback(int event, void* user, void *info) {
case AudioTrack::EVENT_NEW_POS: { JNIEnv *env = AndroidRuntime::getJNIEnv(); if (user != NULL && env != NULL) { env->CallStaticVoidMethod( callbackInfo->audioTrack_class, javaAudioTrackFields.postNativeEventInJava, callbackInfo->audioTrack_ref, event, 0,0, NULL); if (env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); } } } break; } |
javaAudioTrackFields.postNativeEventInJava初始的地方如下,即对应java的postEventFromNative,
#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
int register_android_media_AudioTrack(JNIEnv *env) {
javaAudioTrackFields.postNativeEventInJava = NULL;
// Get the AudioTrack class jclass audioTrackClass = FindClassOrDie(env, kClassPathName);
// Get the postEvent method javaAudioTrackFields.postNativeEventInJava = GetStaticMethodIDOrDie(env, audioTrackClass, JAVA_POSTEVENT_CALLBACK_NAME, "(Ljava/lang/Object;IIILjava/lang/Object;)V"); } |
在java层,通过handler转发事件,将事件通知给应用。 这其中又涉及到应用向java层注册监听器等操作,这个过程比较简单易懂,贴上代码示例。
private static void postEventFromNative(Object audiotrack_ref, int what, int arg1, int arg2, Object obj) { //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2); AudioTrack track = (AudioTrack)((WeakReference)audiotrack_ref).get(); if (track == null) { return; }
if (what == AudioSystem.NATIVE_EVENT_ROUTING_CHANGE) { track.broadcastRoutingChange(); return; } NativePositionEventHandlerDelegate delegate = track.mEventHandlerDelegate; if (delegate != null) { Handler handler = delegate.getHandler(); if (handler != null) { Message m = handler.obtainMessage(what, arg1, arg2, obj); handler.sendMessage(m); } } } |
private class NativePositionEventHandlerDelegate { private final Handler mHandler;
NativePositionEventHandlerDelegate(final AudioTrack track, final OnPlaybackPositionUpdateListener listener, Handler handler) { … mHandler = new Handler(looper) { @Override public void handleMessage(Message msg) { if (track == null) { return; } switch(msg.what) { case NATIVE_EVENT_MARKER: if (listener != null) { listener.onMarkerReached(track); } break; case NATIVE_EVENT_NEW_POS: if (listener != null) { listener.onPeriodicNotification(track); } break; … } |
public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener listener, Handler handler) { if (listener != null) { mEventHandlerDelegate = new NativePositionEventHandlerDelegate(this, listener, handler); } else { mEventHandlerDelegate = null; } } |