Android Audio代码分析5

在我们学习AudioTrack对象的创建过程时,了解到,创建一个AudioTrack对象,必须指定一个SessionId,并与其他使用该SessionId的AudioTrack和MediaPlayer共享AudioEffect。如果不指定SessionId,,将会自动生成一个SessionId,AudioEffect会将该SessionId与新创建的AudioTrack对象关联起来。别人可以通过getAudioSessionId函数取得该SessionId。今天我们就看看getAudioSessionId函数。

在frameworks的代码中搜了一下,发现有两个地方实现了该函数,分别来说一下。

先说说在类MediaPlayer中的实现。*****************************************源码*************************************************int MediaPlayer::getAudioSessionId(){Mutex::Autolock _l(mLock);return mAudioSessionId;}**********************************************************************************************源码路径:frameworks\base\media\libmedia\mediaplayer.cpp

###########################################说明################################################代码很简单,只是将成员变量返回,没啥好说的。那我们看看该成员变量是何时被赋值的。

找了下代码,发现有两个地方对该成员变量进行了赋值。

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++一个在构造函数中。MediaPlayer::MediaPlayer(){LOGV("constructor");mListener = NULL;mCookie = NULL;mDuration = -1;mStreamType = AudioSystem::MUSIC;mCurrentPosition = -1;mSeekPosition = -1;mCurrentState = MEDIA_PLAYER_IDLE;mPrepareSync = false;mPrepareStatus = NO_ERROR;mLoop = false;mLeftVolume = mRightVolume = 1.0;mVideoWidth = mVideoHeight = 0;mLockThreadId = 0;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++int AudioSystem::newAudioSessionId() {const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();if (af == 0) return 0;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++int AudioFlinger::newAudioSessionId(){// 看到了函数nextUniqueId,我们感觉到有点熟悉。// 不错,在我们看函数AudioSystem::getOutputSamplingRate的时候,看到,在函数AudioFlinger::openOutput中有调过函数nextUniqueId++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++int AudioFlinger::nextUniqueId(){// 这是一个自增的操作// 可见,SessionId最终是在AudioFlinger中维护的。// 关于函数android_atomic_inc,可参考以下链接:// return android_atomic_inc(&mNextUniqueId);}—————————————————————-return nextUniqueId();}—————————————————————-return af->newAudioSessionId();}—————————————————————-mAudioSessionId = AudioSystem::newAudioSessionId();mSendLevel = 0;}—————————————————————-

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++另一个给成员变量mAudioSessionId赋值的地方是在函数MediaPlayer::setAudioSessionId中。status_t MediaPlayer::setAudioSessionId(int sessionId){LOGV("MediaPlayer::setAudioSessionId(%d)", sessionId);Mutex::Autolock _l(mLock);if (!(mCurrentState & MEDIA_PLAYER_IDLE)) {LOGE("setAudioSessionId called in state %d", mCurrentState);return INVALID_OPERATION;}if (sessionId < 0) {return BAD_VALUE;}mAudioSessionId = sessionId;return NO_ERROR;}

函数MediaPlayer::setAudioSessionId在函数android_media_MediaPlayer_set_audio_session_id中被调用。++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env, jobject thiz, jint sessionId) {LOGV("set_session_id(): %d", sessionId);++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz){Mutex::Autolock l(sLock);MediaPlayer* const p = (MediaPlayer*)env->GetIntField(thiz, fields.context);return sp<MediaPlayer>(p);}// 以前见到过类似的函数,肯定有某个地方把它set进去。++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player){Mutex::Autolock l(sLock);sp<MediaPlayer> old = (MediaPlayer*)env->GetIntField(thiz, fields.context);if (player.get()) {player->incStrong(thiz);}if (old != 0) {old->decStrong(thiz);}env->SetIntField(thiz, fields.context, (int)player.get());return old;}函数setMediaPlayer在函数android_media_MediaPlayer_native_setup中被调用。函数android_media_MediaPlayer_native_setup也是供java调用的。对应的接口,在下面的一个列表中可以看到。//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++static voidandroid_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this){LOGV("native_setup"); // 在上面的代码中,SessionId的一个赋值的地方就是MediaPlayer的构造函数中。 // MediaPlayer对象就是在这儿被构造的。sp<MediaPlayer> mp = new MediaPlayer();if (mp == NULL) {jniThrowException(env, "java/lang/RuntimeException", "Out of memory");return;}// create new listener and give it to MediaPlayer // JNIMediaPlayerListener是一个代码量不多的类,其声明和实现如下://++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// ref-counted object for callbacksclass JNIMediaPlayerListener: public MediaPlayerListener{public:JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz);~JNIMediaPlayerListener();void notify(int msg, int ext1, int ext2);private:JNIMediaPlayerListener();jclassmClass;// Reference to MediaPlayer classjobjectmObject; // Weak ref to MediaPlayer Java object to call on};JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz){// Hold onto the MediaPlayer class for use in calling the static method// that posts events to the application thread.jclass clazz = env->GetObjectClass(thiz);if (clazz == NULL) {LOGE("Can’t find android/media/MediaPlayer");jniThrowException(env, "java/lang/Exception", NULL);return;}mClass = (jclass)env->NewGlobalRef(clazz);// We use a weak reference so the MediaPlayer object can be garbage collected.// The reference is only used as a proxy for callbacks.mObject = env->NewGlobalRef(weak_thiz);}JNIMediaPlayerListener::~JNIMediaPlayerListener(){// remove global referencesJNIEnv *env = AndroidRuntime::getJNIEnv();env->DeleteGlobalRef(mObject);env->DeleteGlobalRef(mClass);}void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2){JNIEnv *env = AndroidRuntime::getJNIEnv();env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, 0);}//—————————————————————-sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);mp->setListener(listener);// Stow our new C++ MediaPlayer in an opaque field in the Java object.setMediaPlayer(env, thiz, mp);}//—————————————————————-//—————————————————————-//—————————————————————-sp<MediaPlayer> mp = getMediaPlayer(env, thiz);if (mp == NULL ) {jniThrowException(env, "java/lang/IllegalStateException", NULL);return;}//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// If exception is NULL and opStatus is not OK, this method sends an error// event to the client application; otherwise, if exception is not NULL and// opStatus is not OK, this method throws the given exception to the client// application.static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message){if (exception == NULL) { // Don’t throw exception. Instead, send an event.if (opStatus != (status_t) OK) {sp<MediaPlayer> mp = getMediaPlayer(env, thiz);if (mp != 0) mp->notify(MEDIA_ERROR, opStatus, 0);}} else { // Throw exception!if ( opStatus == (status_t) INVALID_OPERATION ) {jniThrowException(env, "java/lang/IllegalStateException", NULL);} else if ( opStatus != (status_t) OK ) {if (strlen(message) > 230) {// if the message is too long, don’t bother displaying the status codejniThrowException( env, exception, message);} else {char msg[256];// append the status code to the messagesprintf(msg, "%s: status=0x%X", message, opStatus);jniThrowException( env, exception, msg);}}}}//—————————————————————-process_media_player_call( env, thiz, mp->setAudioSessionId(sessionId), NULL, NULL );}

只做第一个我,不做第二个谁。

Android Audio代码分析5

相关文章:

你感兴趣的文章:

标签云: