zoukankan      html  css  js  c++  java
  • Android -- 多媒体播放之MediaPlayer使用内部实现简析

    Android -- MediaPlayer内部实现简析


    在之前的博客中,已经介绍了使用MediaPlayer时要注意的内容。如今,这里就通过一个MediaPlayer代码实例,来进一步分析MediaPlayer内部是怎样运作、实现的;当然这里的分析仅仅截止究竟层调用播放器之前,由于播放器这块实在是没搞懂。

    我们使用的样例来源于之前MediaPlayer Playback译文中的官方实例:

    String url = "http://........"; // your URL here
    MediaPlayer mediaPlayer = new MediaPlayer();
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    mediaPlayer.setDataSource(url);
    mediaPlayer.prepare(); // might take long! (for buffering, etc)
    mediaPlayer.start();

    代码中主要通过5个步骤实现了媒体的播放过程,我们一步步来分析。


    一、创建MediaPlayer


    从MediaPlayer模块的实现层次来说,它事实上仅仅是一个暴露给外部调用的工具类;真正的媒体操作都通过JNI调用究竟层Media服务,由它们真正实现。

    MediaPlayer类要使用一个libmedia_jni.so库,它的载入步骤例如以下:

       static {
            System.loadLibrary("media_jni");
            native_init();
        }
    libmedia_jni.so提供了MediaPlayer须要调用的各个JNI函数,它相应的文件是android_media_MediaPlayer.cpp。load该so库的同一时候。会调用native_init()函数进行一些前期的初始化工作:
    // This function gets some field IDs, which in turn causes class initialization.
    // It is called from a static block in MediaPlayer, which won't run until the
    // first time an instance of this class is used.
    static void
    android_media_MediaPlayer_native_init(JNIEnv *env)//初始化一些Field和Method域ID
    {
        jclass clazz;
    
        clazz = env->FindClass("android/media/MediaPlayer");
        if (clazz == NULL) {
            return;
        }
    
        fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
        if (fields.context == NULL) {
            return;
        }
    
        fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
                                                   "(Ljava/lang/Object;IIILjava/lang/Object;)V");
        if (fields.post_event == NULL) {
            return;
        }
    
        fields.surface_texture = env->GetFieldID(clazz, "mNativeSurfaceTexture", "J");
        if (fields.surface_texture == NULL) {
            return;
        }
    
        env->DeleteLocalRef(clazz);
    
        clazz = env->FindClass("android/net/ProxyInfo");
        if (clazz == NULL) {
            return;
        }
    
        fields.proxyConfigGetHost =
            env->GetMethodID(clazz, "getHost", "()Ljava/lang/String;");
    
        fields.proxyConfigGetPort =
            env->GetMethodID(clazz, "getPort", "()I");
    
        fields.proxyConfigGetExclusionList =
            env->GetMethodID(clazz, "getExclusionListAsString", "()Ljava/lang/String;");
    
        env->DeleteLocalRef(clazz);
    
        gPlaybackParamsFields.init(env);
        gSyncParamsFields.init(env);
    }
    
    struct fields_t {
        jfieldID    context;
        jfieldID    surface_texture;
    
        jmethodID   post_event;
    
        jmethodID   proxyConfigGetHost;
        jmethodID   proxyConfigGetPort;
        jmethodID   proxyConfigGetExclusionList;
    };
    static fields_t fields;
    从代码可知,native_init()函数主要保存了一些MediaPlayer.java中定义的一些字段或方法的ID;当中获取的mNativeContext字段,用于将初始化的本地MediaPlayer对象的地址保存到该变量中,这也就给每个MediaPlayer.java实例绑定了一个Native层的MediaPlayer;另外,post_event保存了MediaPlayer::postEventFromNative()函数的ID值,它会被用来在Native层中向上层抛出事件或异常。


    载入完要使用的动态库,我们就能够開始创建MediaPlayer实例了。首先看它的默认构造函数:

        /**
         * Default constructor. Consider using one of the create() methods for
         * synchronously instantiating a MediaPlayer from a Uri or resource.
         * <p>When done with the MediaPlayer, you should call  {@link #release()},
         * to free the resources. If not released, too many MediaPlayer instances may
         * result in an exception.</p>
         */
        public MediaPlayer() {
    
            Looper looper;
            if ((looper = Looper.myLooper()) != null) {
                mEventHandler = new EventHandler(this, looper);
            } else if ((looper = Looper.getMainLooper()) != null) {
                mEventHandler = new EventHandler(this, looper);
            } else {
                mEventHandler = null;
            }
    
            mTimeProvider = new TimeProvider(this);
            mOpenSubtitleSources = new Vector<InputStream>();
            IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
            mAppOps = IAppOpsService.Stub.asInterface(b);
    
            /* Native setup requires a weak reference to our object.
             * It's easier to create it here than in C++.
             */
            native_setup(new WeakReference<MediaPlayer>(this));//继续调用了native_setup()函数
        }
    我们的MediaPlayer须要运行在消息循环中,EventHandler是MediaPlayer的一个内部类。它专门处理来自Native层的事件,这些事件一般都表明了MediaPlayer如今转移到了某个状态,我们能够在该状态处理什么回调操作。EventHandler的功能较为单一,就是依据底层上抛的事件,进行相应的回调或事件处理。这里就不再细看。

    接着。调用了native_setup()函数,并传入了一个MediaPlayer类型的弱引用实例,我们看该函数的实现:

    static void
    android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
    {
        ALOGV("native_setup");
        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类继承自MediaPlayer.h中声明的MediaPlayerListener,并实现了notify()方法
        sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
        mp->setListener(listener);//在Native MediaPlayer实例中保存这个JNIMediaPlayerListener监听对象
    
        // Stow our new C++ MediaPlayer in an opaque field in the Java object.
        setMediaPlayer(env, thiz, mp);//将创建的Native MediaPlayer对象转化成Long型值(地址),保存到MediaPlayer.java::mNativeContext变量中
    }
    该函数中主要做了三个操作:

    • 创建了一个Native MediaPlayer对象
    • 创建了一个JNIMediaPlayerListener对象,它主要用于向上层MediaPlayer(.java)对象通知事件或抛出异常
    • 将创建的Native MediaPlayer实例保存到MediaPlayer.java::mNativeContext字段中
    Native MediaPlayer类继承自BnMediaPlayerClient,它是IMediaPlayerClient业务的服务端。IMediaPlayerClient业务的整个框架如图所看到的:

    Native MediaPlayer的构造函数较为简单,就是一些字段的初始化操作,重要的是设置了默认的音频流类型,并将MediaPlayer的状态初始化为Idle:
    MediaPlayer::MediaPlayer()
    {
        ALOGV("constructor");
        mListener = NULL;
        mCookie = NULL;
        mStreamType = AUDIO_STREAM_MUSIC;//默认音频流类型
        mAudioAttributesParcel = NULL;
        mCurrentPosition = -1;
        mSeekPosition = -1;
        mCurrentState = MEDIA_PLAYER_IDLE;//MediaPlayer的初始状态
        mPrepareSync = false;
        mPrepareStatus = NO_ERROR;
        mLoop = false;//是否循环播放
        mLeftVolume = mRightVolume = 1.0;
        mVideoWidth = mVideoHeight = 0;
        mLockThreadId = 0;
        mAudioSessionId = AudioSystem::newAudioUniqueId();
        AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);
        mSendLevel = 0;
        mRetransmitEndpointValid = false;
    }
    
    另外,还有默认同步状态的设置等等。

    JNIMediaPlayerListener类继承自MediaPlayerListener,它声明了一个notify()函数。该函数主要用来向上层抛出事件或其它异常:
    class JNIMediaPlayerListener: public MediaPlayerListener
    {
    public:
        JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
        ~JNIMediaPlayerListener();
        virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
    private:
        JNIMediaPlayerListener();
        jclass      mClass;     // Reference to MediaPlayer class
        jobject     mObject;    // Weak ref to MediaPlayer Java object to call on
    };
    JNIMediaPlayerListener的构造函数中用之前传入的MediaPlayer弱引用实例构造了一个Native层全局的变量mObject。而且也保存了一份MediaPlayer.java的类型实例:
    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) {
            ALOGE("Can't find android/media/MediaPlayer");
            jniThrowException(env, "java/lang/Exception", NULL);
            return;
        }
    	
        mClass = (jclass)env->NewGlobalRef(clazz);//代表MediaPlayer.java类型的实例
    
        // 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);//weak_thiz是MediaPlayer.java实例的一个弱引用
    }
    JNIMediaPlayerListener::notify()函数用来向上层抛出事件或异常:
    //回调MediaPlayer.java中的postEventFromNative()方法,反馈Native层发生的事件;postEventFromNative()会EventHandler(运行在MediaPalyer的线程中)
    //发送附带msg參数的消息,EventHandler推断当前的事件类型,如MEDIA_PREPARED等,最后调用应用程序设置的相关回调处理相应的事件信息
    void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj)
    {
        JNIEnv *env = AndroidRuntime::getJNIEnv();
        if (obj && obj->dataSize() > 0) {
            jobject jParcel = createJavaParcelObject(env);
            if (jParcel != NULL) {
                Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
                nativeParcel->setData(obj->data(), obj->dataSize());
                env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
                        msg, ext1, ext2, jParcel);
                env->DeleteLocalRef(jParcel);
            }
        } else {
            env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
                    msg, ext1, ext2, NULL);
        }
        if (env->ExceptionCheck()) {
            ALOGW("An exception occurred while notifying an event.");
            LOGW_EX(env);
            env->ExceptionClear();
        }
    }
    JNIMediaPlayerListener实例创建后,会将它保存到Native MediaPlayer::mListener字段中。最后掉setMediaPlayer()方法将mp对象转换成地址值的形式保存到上层MediaPlayer中:
    static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)
    {
        Mutex::Autolock l(sLock);
        sp<MediaPlayer> old = (MediaPlayer*)env->GetLongField(thiz, fields.context);
        if (player.get()) {
            player->incStrong((void*)setMediaPlayer);
        }
        if (old != 0) {
            old->decStrong((void*)setMediaPlayer);
        }
        env->SetLongField(thiz, fields.context, (jlong)player.get());
        return old;
    }

    二、设置音频类型


    分析到这里。我们能够推測:上层MediaPlayer和Native MediaPlayer之间的关系就相当于Client - Server结构。前者是Client,后者是Server;前者向后者发送服务请求。接着。我们调用了MediaPlayer::setAudioStreamType()函数设置了当前的音频流类型:
        /**
         * Sets the audio stream type for this MediaPlayer. See {@link AudioManager}
         * for a list of stream types. Must call this method before prepare() or
         * prepareAsync() in order for the target stream type to become effective
         * thereafter.
         *
         * @param streamtype the audio stream type
         * @see android.media.AudioManager
         */
        public void setAudioStreamType(int streamtype) {
            _setAudioStreamType(streamtype);
            mStreamType = streamtype;
        }
    
        private native void _setAudioStreamType(int streamtype);
    从函数凝视能够。这里设置的音频流类型必须是AudioManager中定义过的,当前版本号中所支持的类型有:
        /** The audio stream for phone calls */
        public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
        /** The audio stream for system sounds */
        public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM;
        /** The audio stream for the phone ring */
        public static final int STREAM_RING = AudioSystem.STREAM_RING;
        /** The audio stream for music playback */
        public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC;
        /** The audio stream for alarms */
        public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM;
        /** The audio stream for notifications */
        public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION;
        /** @hide The audio stream for phone calls when connected to bluetooth */
        public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO;
        /** @hide The audio stream for enforced system sounds in certain countries (e.g camera in Japan) */
        public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED;
        /** The audio stream for DTMF Tones */
        public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF;
        /** @hide The audio stream for text to speech (TTS) */
        public static final int STREAM_TTS = AudioSystem.STREAM_TTS;
    最后调用native函数_setAudioStreamType()将类型值设置下去,看它的实现:
    static void
    android_media_MediaPlayer_setAudioStreamType(JNIEnv *env, jobject thiz, jint streamtype)
    {
        ALOGV("setAudioStreamType: %d", streamtype);
        sp<MediaPlayer> mp = getMediaPlayer(env, thiz);//获取创建时设置到MediaPlayer.java实例中的Native MediaPlayer实例
        if (mp == NULL ) {
            jniThrowException(env, "java/lang/IllegalStateException", NULL);
            return;
        }
        process_media_player_call( env, thiz, mp->setAudioStreamType((audio_stream_type_t) streamtype) , NULL, NULL );
    }
    首先获取到之前保存到MediaPlayer.java::mNativeContext字段中的Native MediaPlayer对象;最后调用process_media_player_call()函数,当中包括了通过mp实例设置音频类型的调用:MediaPlayer::setAudioStreamType()。
    我们分解来分析,process_media_player_call()函数会依据函数的运行结果opStatus,以及附带的exception和message信息;推断是否须要向上反馈状态事件或抛出异常信息:
    // 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.
    //依据函数的运行结果opStatus,以及附带的exception和message信息;推断是否须要反馈操作失败事件或抛出异常信息
    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) BAD_VALUE ) {
                jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
            } else if ( opStatus == (status_t) PERMISSION_DENIED ) {
                jniThrowException(env, "java/lang/SecurityException", NULL);
            } else if ( opStatus != (status_t) OK ) {
                if (strlen(message) > 230) {
                   // if the message is too long, don't bother displaying the status code
                   jniThrowException( env, exception, message);
                } else {
                   char msg[256];
                    // append the status code to the message
                   sprintf(msg, "%s: status=0x%X", message, opStatus);
                   jniThrowException( env, exception, msg);
                }
            }
        }
    }
    假设我们的操作无需抛出异常,而且当前的函数调用有错误,就须要通过Native MediaPlayer调用notify()向上层抛出错误:
    //向应用程序反馈当前状态变化的回调事件,设置当前MediaPlayer的状态
    void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
    {
        ALOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
        bool send = true;
        bool locked = false;
    
        // TODO: In the future, we might be on the same thread if the app is
        // running in the same process as the media server. In that case,
        // this will deadlock.
        //
        // The threadId hack below works around this for the care of prepare,
        // seekTo and start within the same process.
        // FIXME: Remember, this is a hack, it's not even a hack that is applied
        // consistently for all use-cases, this needs to be revisited.
        if (mLockThreadId != getThreadId()) {
            mLock.lock();
            locked = true;
        }
    
        // Allows calls from JNI in idle state to notify errors
        if (!(msg == MEDIA_ERROR && mCurrentState == MEDIA_PLAYER_IDLE) && mPlayer == 0) {
            ALOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
            if (locked) mLock.unlock();   // release the lock when done.
            return;
        }
    
        switch (msg) {
        case MEDIA_NOP: // interface test message
            break;
        case MEDIA_PREPARED:
            ALOGV("prepared");
            mCurrentState = MEDIA_PLAYER_PREPARED;
            if (mPrepareSync) {
                ALOGV("signal application thread");
                mPrepareSync = false;
                mPrepareStatus = NO_ERROR;
                mSignal.signal();
            }
            break;
        case MEDIA_PLAYBACK_COMPLETE:
            ALOGV("playback complete");
            if (mCurrentState == MEDIA_PLAYER_IDLE) {
                ALOGE("playback complete in idle state");
            }
            if (!mLoop) {
                mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
            }
            break;
        case MEDIA_ERROR://假设是有函数处理错误发生
            // Always log errors.
            // ext1: Media framework error code.
            // ext2: Implementation dependant error code.
            ALOGE("error (%d, %d)", ext1, ext2);
            mCurrentState = MEDIA_PLAYER_STATE_ERROR;//则将当前状态设置为ERROR
            if (mPrepareSync)
            {
                ALOGV("signal application thread");
                mPrepareSync = false;
                mPrepareStatus = ext1;
                mSignal.signal();
                send = false;
            }
            break;
        case MEDIA_INFO:
            // ext1: Media framework error code.
            // ext2: Implementation dependant error code.
            if (ext1 != MEDIA_INFO_VIDEO_TRACK_LAGGING) {
                ALOGW("info/warning (%d, %d)", ext1, ext2);
            }
            break;
        case MEDIA_SEEK_COMPLETE:
            ALOGV("Received seek complete");
            if (mSeekPosition != mCurrentPosition) {
                ALOGV("Executing queued seekTo(%d)", mSeekPosition);
                mSeekPosition = -1;
                seekTo_l(mCurrentPosition);
            }
            else {
                ALOGV("All seeks complete - return to regularly scheduled program");
                mCurrentPosition = mSeekPosition = -1;
            }
            break;
        case MEDIA_BUFFERING_UPDATE:
            ALOGV("buffering %d", ext1);
            break;
        case MEDIA_SET_VIDEO_SIZE:
            ALOGV("New video size %d x %d", ext1, ext2);
            mVideoWidth = ext1;
            mVideoHeight = ext2;
            break;
        case MEDIA_TIMED_TEXT:
            ALOGV("Received timed text message");
            break;
        case MEDIA_SUBTITLE_DATA:
            ALOGV("Received subtitle data message");
            break;
        case MEDIA_META_DATA:
            ALOGV("Received timed metadata message");
            break;
        default:
            ALOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
            break;
        }
    
    	//JNIMediaPlayerListener继承自MediaPlayerListener,并实现了notify()方法;声明实如今android_media_MediaPlayer.cpp中
        sp<MediaPlayerListener> listener = mListener;//mListener保存了MediaPlayer实例创建时初始化的JNIMediaPlayerListener监听对象
        if (locked) mLock.unlock();
    
        // this prevents re-entrant calls into client code
        if ((listener != 0) && send) {
            Mutex::Autolock _l(mNotifyLock);
            ALOGV("callback application");
            listener->notify(msg, ext1, ext2, obj);//调用JNIMediaPlayerListener类实例的notify()方法
            ALOGV("back from callback");
        }
    }
    notify()函数使用的msg推断值定义在MediaPlayer.h中:
    enum media_event_type {
        MEDIA_NOP               = 0, // interface test message
        MEDIA_PREPARED          = 1,
        MEDIA_PLAYBACK_COMPLETE = 2,
        MEDIA_BUFFERING_UPDATE  = 3,
        MEDIA_SEEK_COMPLETE     = 4,
        MEDIA_SET_VIDEO_SIZE    = 5,
        MEDIA_STARTED           = 6,
        MEDIA_PAUSED            = 7,
        MEDIA_STOPPED           = 8,
        MEDIA_SKIPPED           = 9,
        MEDIA_TIMED_TEXT        = 99,
        MEDIA_ERROR             = 100,
        MEDIA_INFO              = 200,
        MEDIA_SUBTITLE_DATA     = 201,
        MEDIA_META_DATA         = 202,
    };
    通过观察notify()函数的实现,我们发现正如文档介绍的那样。MediaPlayer确实有自己的内部状态;首先会依据传入的msg值更新当前的MediaPlayer状态,最后通过mListener调用它的notify()函数将状态的变化信息反馈上层MediaPlayer中。

    假设须要抛出异常,则直接在JNI层抛出异常就可以。假设即没有错误,也没有异常须要抛出,则什么都不做。


    process_media_player_call()方法的功能非常明显,就是向上抛出函数处理错误事件或者异常信息。它的运行又依赖某些操作的运行结果。我们接着看这部分的音频流类型设置操作:
    status_t MediaPlayer::setAudioStreamType(audio_stream_type_t type)
    {
        ALOGV("MediaPlayer::setAudioStreamType");
        Mutex::Autolock _l(mLock);
        if (mStreamType == type) return NO_ERROR;
        if (mCurrentState & ( MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED |
                    MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) {
            // Can't change the stream type after prepare
            ALOGE("setAudioStream called in state %d", mCurrentState);
            return INVALID_OPERATION;
        }
        // cache
        mStreamType = type;
        return OK;
    }
    mStreamType保存当前设置的流类型,初始值是AUDIO_STREAM_MUSIC;假设要设置的类型和当前类型一致,则直接无错误返回;否则。推断MediaPlayer的当前状态能否够进行当前操作,假设能够。则更新mStreamType的值并返回。音频流类型设置的操作就结束了,该部分实现比較简单。到此能够看到的结果。就是将须要设置的类型值保存到了Native MediaPlayer中。另外。从这个简单调用的处理过程来看,也证实了我们前面关于Client/Server的推測。

    最后。JNI中最外层的process_media_player_call()会依据setAudioStreamType()的运行结果,推断是否须要抛出函数处理错误或异常信息。

    三、为MediaPlayer设置资源


    要为MediaPlayer设置资源项。我们要调用MediaPlayer::setDataSource()方法。MediaPlayer中提供了非常多重载版本号的setDataSource()方法。这是由于MediaPlayer同意我们使用多种不同类型的资源。关于这部分内容,在之前的翻译文档中有具体的介绍。可是在setDataSource()中,终于基本的处理过程是获取到当前资源的文件描写叙述符。并调用native方法向下设置资源;可是。假设当前设置的是网络资源或者其它,则处理方式略有不同,我们不讨论这部分,但也可能会提及一些。看对资源文件描写叙述符设置的操作:
    private native void _setDataSource(FileDescriptor fd, long offset, long length)
                throws IOException, IllegalArgumentException, IllegalStateException;
    
    static void
    android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
    {
        sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
        if (mp == NULL ) {
            jniThrowException(env, "java/lang/IllegalStateException", NULL);
            return;
        }
    
        if (fileDescriptor == NULL) {
            jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
            return;
        }
        int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
        ALOGV("setDataSourceFD: fd %d", fd);
        process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
    }
    
    与第二部分音频流类型设置的处理操作相似,我们直接看调用MediaPlayer::setDataSource()处理的过程,process_media_player_call()函数的处理跟之前一致,兴许不再赘述。

     MediaPlayer::setDataSource函数处理:
    status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
    {
        ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
        status_t err = UNKNOWN_ERROR;
    
    	//getMediaPlayerService()会通过ServiceManager找到MediaPlayerService服务的Client端实例,初始化service对象
        const sp<IMediaPlayerService>& service(getMediaPlayerService());
        if (service != 0) {
    		//player实例实际是一个MediaPlayerServcie::Client实例,该内部类继承自IMediaPlayer,负责向外提供其定义的业务服务
            sp<IMediaPlayer> player(service->create(this, mAudioSessionId));//通过Binder机制向MediaPlayerService请求创建IMediaPlayer对象
            if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
                (NO_ERROR != player->setDataSource(fd, offset, length))) {
                player.clear();
            }
            err = attachNewPlayer(player);
        }
        return err;
    }
    首先。获取一个MediaPlayerService服务的代理实例。MediaPlayerService在媒体播放框架中是一个非常重要的服务,它运行在mediaserver进程中。

    MediaPlayerService服务的注冊过程在mediaserver进程创建时发生。main_mediaserver.cpp中:

     InitializeIcuOrDie();
            sp<ProcessState> proc(ProcessState::self());
            sp<IServiceManager> sm = defaultServiceManager();
            ALOGI("ServiceManager: %p", sm.get());
            AudioFlinger::instantiate();
            MediaPlayerService::instantiate();//启动MediaPlayerService服务
            ResourceManagerService::instantiate();
            CameraService::instantiate();
            AudioPolicyService::instantiate();
            SoundTriggerHwService::instantiate();
            RadioService::instantiate();
            registerExtensions();
            ProcessState::self()->startThreadPool();
            IPCThreadState::self()->joinThreadPool();
    MediaPlayerService是IMediaPlayerService业务架构中的服务端。该业务架构的图演示样例如以下:
    我们再看MediaPlayerService::instantiate()的处理:
    void MediaPlayerService::instantiate() {
        defaultServiceManager()->addService(
                String16("media.player"), new MediaPlayerService());
    }
    非常easy地创建MediaPlayerService服务实例。并注冊进系统的实现(要注意。注冊的服务名称是“media.player”)。接着看它的构造函数实现:
    //创建MediaPlayerService实例时,会初始化MediaPlayerService::sFactoryMap成员,注冊各Player工厂对象
    MediaPlayerService::MediaPlayerService()
    {
        ALOGV("MediaPlayerService created");
        mNextConnId = 1;
    
        mBatteryAudio.refCount = 0;
        for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
            mBatteryAudio.deviceOn[i] = 0;
            mBatteryAudio.lastTime[i] = 0;
            mBatteryAudio.totalTime[i] = 0;
        }
        // speaker is on by default
        mBatteryAudio.deviceOn[SPEAKER] = 1;
    
        // reset battery stats
        // if the mediaserver has crashed, battery stats could be left
        // in bad state, reset the state upon service start.
        BatteryNotifier& notifier(BatteryNotifier::getInstance());
        notifier.noteResetVideo();
        notifier.noteResetAudio();
    
        MediaPlayerFactory::registerBuiltinFactories();//初始化MediaPlayerService::sFactoryMap集合对象
    }
    最后一步调用了MediaPlayerFactory::registerBuildinFactories()函数注冊系统中提供的各个播放器实例:
    enum player_type {
        STAGEFRIGHT_PLAYER = 3,
        NU_PLAYER = 4,
        // Test players are available only in the 'test' and 'eng' builds.
        // The shared library with the test player is passed passed as an
        // argument to the 'test:' url in the setDataSource call.
        TEST_PLAYER = 5,
    };
    
    void MediaPlayerFactory::registerBuiltinFactories() {
        Mutex::Autolock lock_(&sLock);
    
        if (sInitComplete)
            return;
    
        registerFactory_l(new StagefrightPlayerFactory(), STAGEFRIGHT_PLAYER);
        registerFactory_l(new NuPlayerFactory(), NU_PLAYER);
        registerFactory_l(new TestPlayerFactory(), TEST_PLAYER);
    
        sInitComplete = true;
    }
    registerFactory_l()函数会推断实例的有效性,并将它们保存到集合变量中:
    MediaPlayerFactory::tFactoryMap MediaPlayerFactory::sFactoryMap;
    bool MediaPlayerFactory::sInitComplete = false;
    
    status_t MediaPlayerFactory::registerFactory_l(IFactory* factory,
                                                   player_type type) {
        if (NULL == factory) {
            ALOGE("Failed to register MediaPlayerFactory of type %d, factory is"
                  " NULL.", type);
            return BAD_VALUE;
        }
    
        if (sFactoryMap.indexOfKey(type) >= 0) {
            ALOGE("Failed to register MediaPlayerFactory of type %d, type is"
                  " already registered.", type);
            return ALREADY_EXISTS;
        }
    
        if (sFactoryMap.add(type, factory) < 0) {
            ALOGE("Failed to register MediaPlayerFactory of type %d, failed to add"
                  " to map.", type);
            return UNKNOWN_ERROR;
        }
    
        return OK;
    }
    MediaPlayerFactory中主要涉及了三个类型的播放器:
    MediaPlayerFactory提供的播放器类型
    NuPlayer 用于播放网络、本地视频。或者RTSP协议的视频流等
    TestPlayer 測试用途
    StagefrightPlayer 提供的默认播放器,其它播放器不能播放的资源都会让它播放

    当中,NuPlayer和StagefrightPlayer等Player类的继承关系如图所看到的:

    介绍了有关MediaPlayerService有关的内容后,我们再返回到指定内容。在得到MediaPlayerService服务的代理service后,会去调用create()函数创建一个IMediaPlayer服务的代理对象player。IMediaPlayer业务是真正跟播放器相关的,该业务的结构如图所看到的:

    它的服务端实现类是MediaPlayerService::Client这个内部类。

    我们直接看MediaPlayerService::create()函数是怎样创建Player的:

    sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,
            int audioSessionId)
    {
        pid_t pid = IPCThreadState::self()->getCallingPid();
        int32_t connId = android_atomic_inc(&mNextConnId);
    
    	//创建Client实例
    	//Clinet是MediaPlayerService的内部类;它集成自BnMediaPlayer,是IMediaPlayer服务的Service组件,对外提供MediaPlayer的各种服务
        sp<Client> c = new Client(
                this, pid, connId, client, audioSessionId,
                IPCThreadState::self()->getCallingUid());
    
        ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,
             IPCThreadState::self()->getCallingUid());
    
        wp<Client> w = c;
        {
            Mutex::Autolock lock(mLock);
            mClients.add(w);//mClients变量维护了MediaPlayerService中的Client实例集合
        }
        return c;
    }
    MediaPlayerService::Client类是IMediaPlayer业务的服务端,也就能够把它看成是提供MediaPlayer服务的提供者。

    这里创建了一个Client实例,并将它保存到了mClients集合中,我们能够理解为mClients中保存了当前全部存在的Player对象。分析Client的构造函数:

    MediaPlayerService::Client::Client(
            const sp<MediaPlayerService>& service, pid_t pid,
            int32_t connId, const sp<IMediaPlayerClient>& client,
            int audioSessionId, uid_t uid)
    {
        ALOGV("Client(%d) constructor", connId);
        mPid = pid;
        mConnId = connId;
        mService = service;//保存当前的IMediaPlayerService实例
        mClient = client;//保存的是Native MediaPlayer(MediaPlayer.cpp)实例
        mLoop = false;
        mStatus = NO_INIT;
        mAudioSessionId = audioSessionId;
        mUID = uid;
        mRetransmitEndpointValid = false;
        mAudioAttributes = NULL;
    
    #if CALLBACK_ANTAGONIZER
        ALOGD("create Antagonizer");
        mAntagonizer = new Antagonizer(notify, this);
    #endif
    }
    再返回到MediaPlayer::setDataSource()中。创建为IMediaPlayer实例后,主要会调用它的setDataSource()函数:
    //MediaPlayerFactory是播放器创建的工厂,提供打分功能,以让系统在当前视频源下找到合适类型的播放器进行播放
    status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
    {
        ALOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
        struct stat sb;
        int ret = fstat(fd, &sb);
        if (ret != 0) {
            ALOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
            return UNKNOWN_ERROR;
        }
    
        ALOGV("st_dev  = %llu", static_cast<uint64_t>(sb.st_dev));
        ALOGV("st_mode = %u", sb.st_mode);
        ALOGV("st_uid  = %lu", static_cast<unsigned long>(sb.st_uid));
        ALOGV("st_gid  = %lu", static_cast<unsigned long>(sb.st_gid));
        ALOGV("st_size = %llu", sb.st_size);
    
        if (offset >= sb.st_size) {
            ALOGE("offset error");
            ::close(fd);
            return UNKNOWN_ERROR;
        }
        if (offset + length > sb.st_size) {
            length = sb.st_size - offset;
            ALOGV("calculated length = %lld", length);
        }
    
        player_type playerType = MediaPlayerFactory::getPlayerType(this,
                                                                   fd,
                                                                   offset,
                                                                   length);//获取到当前适合播放该视频源的播放器类型
        sp<MediaPlayerBase> p = setDataSource_pre(playerType);//setDataSource_pre()创建一个合适的Player播放器实例
        if (p == NULL) {
            return NO_INIT;
        }
    
        // now set data source
        setDataSource_post(p, p->setDataSource(fd, offset, length));//先调用播放器实例的setDataSource()方法,为它设置资源;再调用setDataSource_post()完毕收尾工作
        return mStatus;
    }
    这里有四个重要调用:
    • MediaPlayerFactory::getPlayerType():为当前资源选择合适的播放器类型
    • setDataSource_pre():创建合适的播放器对象
    • MediaPlayerBase::setDataSource():调用播放器的setDataSource()方法,真正去设置资源
    • setDataSource_post():运行收尾工作
    如今一步步看。

    MediaPlayerFactory::getPlayerType()用于得到合适的播放器类型,它内部主要调用宏定义函数GET_PLAYER_TYPE_IMPL():
    #define GET_PLAYER_TYPE_IMPL(a...)                      
        Mutex::Autolock lock_(&sLock);                      
                                                            
        player_type ret = STAGEFRIGHT_PLAYER;//默认播放器类型               
        float bestScore = 0.0;                              
    
    	//依据当前传入的视频源,对各个播放器进行比較打分,找到合适的播放器;否则使用默认播放器StagefightPlayer 
        for (size_t i = 0; i < sFactoryMap.size(); ++i) {   
                                                            
            IFactory* v = sFactoryMap.valueAt(i);           
            float thisScore;                                
            CHECK(v != NULL);                               
            thisScore = v->scoreFactory(a, bestScore);      
            if (thisScore > bestScore) {                    
                ret = sFactoryMap.keyAt(i);                 
                bestScore = thisScore;                      
            }                                               
        }                                                   
                                                            
        if (0.0 == bestScore) {                             
            ret = getDefaultPlayerType();//依据"media.stagefright.use-awesome"属性配置,选择当前默认的播放器                   
        }                                                   
                                                            
        return ret;                                         
    该函数的实现就是遍历MediaPlayerFactory创建时注冊的各个播放器工厂对象的scoreFactory()方法。对当前设置的资源进行评估,得到最符合该资源的播放器工厂类型并返回。各个播放器的scoreFactory()方法,这里不做具体介绍。

    setDataSource_pre()函数会依据得到的播放器类型去创建相应的播放器实例:
    //调用createPlayer()创建播放器实例对象
    sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(
            player_type playerType)
    {
        ALOGV("player type = %d", playerType);
    
        // create the right type of player
        sp<MediaPlayerBase> p = createPlayer(playerType);
        if (p == NULL) {
            return p;
        }
    
        if (!p->hardwareOutput()) {//以StagefrightPlayer为例,它没有重写父类的MediaPlayerInterface::hardwareOutput()方法;返回false,表示音频不直接输出到硬件上.
            Mutex::Autolock l(mLock);
            mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(),
                    mPid, mAudioAttributes);
            static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);//调用父类MediaPlayerInterface::setAudioSink()方法
        }
    
        return p;
    }
    当中MediaPlayerFactory::createPlayer运行播放器创建工作:
    //假设当前持有了播放器实例对象,则要推断它是否与我们须要的播放器类型相符;
    //假设不相符,则删除它;再又一次创建该类型的播放器实例
    sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
    {
        // determine if we have the right player type
        sp<MediaPlayerBase> p = mPlayer;
        if ((p != NULL) && (p->playerType() != playerType)) {
            ALOGV("delete player");
            p.clear();//重置该sp<>指针
        }
        if (p == NULL) {
            p = MediaPlayerFactory::createPlayer(playerType, this, notify, mPid);//创建播放器对象;重要:createPlayer()里面setNotifyCallback()函数调用
        }
    
        if (p != NULL) {
            p->setUID(mUID);
        }
    
        return p;
    }
    假设当前持有的播放器类型与须要的不符,则会先销毁掉它,并按类型又一次创建一个新播放器对象。MediaPlayerFactory::createPlayer()运行播放器对象的创建操作:
    //找到相应视频源类型的播放器工厂实例,并创建Player对象;最后给该Player对象设置传递消息的notifyFunc回调函数
    sp<MediaPlayerBase> MediaPlayerFactory::createPlayer(
            player_type playerType,
            void* cookie,
            notify_callback_f notifyFunc,
            pid_t pid) {
        sp<MediaPlayerBase> p;
        IFactory* factory;
        status_t init_result;
        Mutex::Autolock lock_(&sLock);
    
        if (sFactoryMap.indexOfKey(playerType) < 0) {
            ALOGE("Failed to create player object of type %d, no registered"
                  " factory", playerType);
            return p;
        }
    
        factory = sFactoryMap.valueFor(playerType);//从sFactoryMap中获取到类型相应的Player工厂对象
        CHECK(NULL != factory);
        p = factory->createPlayer(pid);//创建相应类型的播放器实例,直接new实例对象;如创建StagefrightPlayer,期间会实例化StagefrightPlayer::(AwesomePlayer *mPlayer)成员
    
        if (p == NULL) {
            ALOGE("Failed to create player object of type %d, create failed",
                   playerType);
            return p;
        }
    
        init_result = p->initCheck();//实现直接return OK;
        if (init_result == NO_ERROR) {
            p->setNotifyCallback(cookie, notifyFunc);//调用父类MediaPlayerBase::setNotifyCallback();cookie是当前调用MediaPlayerService::Client::createPlayer()的Client实例,notifyFunc这里是MediaPlayerService::Client::notify()函数指针.
        } else {
            ALOGE("Failed to create player object of type %d, initCheck failed"
                  " (res = %d)", playerType, init_result);
            p.clear();
        }
    
        return p;
    }
    依据须要创建的播放器类型。在sFactoryMap集合中找到相应的播放器工厂对象,并调用的createPlayer()方法真正创建实例,这里以StagefrightPlayer为例:
    //StagefrightPlayer是默认播放器
    class StagefrightPlayerFactory :
        public MediaPlayerFactory::IFactory {
      public:
        virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
                                   int fd,
                                   int64_t offset,
                                   int64_t length,
                                   float /*curScore*/) {
            if (legacyDrm()) {
                sp<DataSource> source = new FileSource(dup(fd), offset, length);
                String8 mimeType;
                float confidence;
                if (SniffWVM(source, &mimeType, &confidence, NULL /* format */)) {
                    return 1.0;
                }
            }
    
            if (getDefaultPlayerType() == STAGEFRIGHT_PLAYER) {
                char buf[20];
                lseek(fd, offset, SEEK_SET);
                read(fd, buf, sizeof(buf));
                lseek(fd, offset, SEEK_SET);
    
                uint32_t ident = *((uint32_t*)buf);
    
                // Ogg vorbis?

    if (ident == 0x5367674f) // 'OggS' return 1.0; } return 0.0; } virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/, const char* url, float /*curScore*/) { if (legacyDrm() && !strncasecmp("widevine://", url, 11)) { return 1.0; } return 0.0; } virtual sp<MediaPlayerBase> createPlayer(pid_t /* pid */) { ALOGV(" create StagefrightPlayer"); return new StagefrightPlayer();//实例化StagefrightPlayer对象,并初始化AwesomePlayer *mPlayer成员 } private: bool legacyDrm() { char value[PROPERTY_VALUE_MAX]; if (property_get("persist.sys.media.legacy-drm", value, NULL) && (!strcmp("1", value) || !strcasecmp("true", value))) { return true; } return false; } };

    创建为StagefrightPlayer对象后,会为该对象设置回调对象和函数指针,它调用的是父类MediaPlayerBase::setNotifyCallback()函数;这一步是非常重要的:
    init_result = p->initCheck();//实现直接return OK;
        if (init_result == NO_ERROR) {
            p->setNotifyCallback(cookie, notifyFunc);//调用父类MediaPlayerBase::setNotifyCallback();cookie是当前调用MediaPlayerService::Client::createPlayer()的Client实例,notifyFunc这里是MediaPlayerService::Client::notify()函数指针.
        } else {
            ALOGE("Failed to create player object of type %d, initCheck failed"
                  " (res = %d)", playerType, init_result);
            p.clear();
        }
    MediaPlayerBase::setNotifyCallback()函数的定义是:
       void        setNotifyCallback(
                void* cookie, notify_callback_f notifyFunc) {
            Mutex::Autolock autoLock(mNotifyLock);
            mCookie = cookie; mNotify = notifyFunc;
        }
    它有两个參数:第一个參数类型是void *,这里一般指向某个对象;第二个參数类型是notify_callback_f。

    notify_callback_f事实上是一个类型别名。它的定义是:

    // callback mechanism for passing messages to MediaPlayer object
    typedef void (*notify_callback_f)(void* cookie,
            int msg, int ext1, int ext2, const Parcel *obj);
    能够看出它实际是一个特定结构的函数指针,用于向MediaPlayer抛出事件。

    MediaPlayerService::Client::setDataSource_pre()在创建播放器实例结束后。还有处理:
    if (!p->hardwareOutput()) {//以StagefrightPlayer为例,它没有重写父类的MediaPlayerInterface::hardwareOutput()方法;返回false,表示音频不直接输出到硬件上.
            Mutex::Autolock l(mLock);
            mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(),
                    mPid, mAudioAttributes);
            static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);//调用父类MediaPlayerInterface::setAudioSink()方法
        }
    假设当前播放器不把音频直接输出到硬件上,还会去调用它的setAudioSink()方法。

    setDataSource_pre()方法处理完后,会调用播放器实例的setDataSource()方法将资源对象设置给播放器,这里是以StagefrightPlayer为例:
    // Warning: The filedescriptor passed into this method will only be valid until
    // the method returns, if you want to keep it, dup it!
    //实际调用AwesomePlayer实例的setDataSource()方法
    status_t StagefrightPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
        ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
        return mPlayer->setDataSource(dup(fd), offset, length);
    }
    实际是调用AwesomePlayer的同名方法,StagefrightPlayer::mPlayer在StagefrightPlayer构造时被创建:
    StagefrightPlayer::StagefrightPlayer()
        : mPlayer(new AwesomePlayer) {
        ALOGV("StagefrightPlayer");
    
        mPlayer->setListener(this);
    }
    除了创建了AwesomePlayer实例外。将当前的StagefrightPlayer实例作为监听器保存到了AwesomePlayer::mListener字段中,它的作用是当AwesomePlayer完毕了一些操作 时。 如准备完毕、seek完毕,通知上层当前的MediaPlayer状态变化。AwesomePlayer实例负责将数据设置下去。它的实现这里不做分析。

    最后调用setDataSource_post()函数进行一些扫尾工作:
    //p指向创建的播放器实例, status是p->setDataSource()调用结果;setDataSource()调用过程的收尾阶段
    void MediaPlayerService::Client::setDataSource_post(
            const sp<MediaPlayerBase>& p,
            status_t status)
    {
        ALOGV(" setDataSource");
        mStatus = status;
        if (mStatus != OK) {
            ALOGE("  error: %d", mStatus);
            return;
        }
    
        // Set the re-transmission endpoint if one was chosen.
        if (mRetransmitEndpointValid) {//设置再次传输时的终端
            mStatus = p->setRetransmitEndpoint(&mRetransmitEndpoint);
            if (mStatus != NO_ERROR) {
                ALOGE("setRetransmitEndpoint error: %d", mStatus);
            }
        }
    
        if (mStatus == OK) {
            mPlayer = p;//将播放器实例保存到mPlayer字段中
        }
    }
    须要注意的是。最后一步。会将此时创建的播放器实例保存到MediaPlayerService::Client mPlayer字段中。


    我们在回到外层MediaPlayer::setDataSource(),之后会调用attachNewPlayer()函数关联对象:
    //将新的IMediaPlayer对象保存到mPlayer中,并清理之前的MediaPlayer实例
    status_t MediaPlayer::attachNewPlayer(const sp<IMediaPlayer>& player)
    {
        status_t err = UNKNOWN_ERROR;
        sp<IMediaPlayer> p;
        { // scope for the lock
            Mutex::Autolock _l(mLock);
    
            if ( !( (mCurrentState & MEDIA_PLAYER_IDLE) ||
                    (mCurrentState == MEDIA_PLAYER_STATE_ERROR ) ) ) {//推断当前的状态是否同意调用attachNewPlayer()函数
                ALOGE("attachNewPlayer called in state %d", mCurrentState);
                return INVALID_OPERATION;
            }
    
            clear_l();//清理状态
            p = mPlayer;
            mPlayer = player;//保存这次的IMediaPlayer对象,实际是MediaPlayerServcie::Client实例
            if (player != 0) {
                mCurrentState = MEDIA_PLAYER_INITIALIZED;//将当前状态切换到INITIALIZED
                err = NO_ERROR;
            } else {
                ALOGE("Unable to create media player");
            }
        }
    
        if (p != 0) {//假设之前的IMediaPlayer没有清理
            p->disconnect();//对这次对象的资源进行清理
        }
    
        return err;
    }
    该函数的主要就是更新Native MediaPlayer保存的IMediaPlayer实例,并对旧的对象进行清理操作;随后还会将当前MediaPlayer的状态切换到MEDIA_PLAYER_INITIALIZED。MediaPlayerService::Client的disconnect()方法会清掉一些底层资源:
    void MediaPlayerService::Client::disconnect()
    {
        ALOGV("disconnect(%d) from pid %d", mConnId, mPid);
        // grab local reference and clear main reference to prevent future
        // access to object
        sp<MediaPlayerBase> p;
        {
            Mutex::Autolock l(mLock);
            p = mPlayer;
            mClient.clear();
        }
    
        mPlayer.clear();
    
        // clear the notification to prevent callbacks to dead client
        // and reset the player. We assume the player will serialize
        // access to itself if necessary.
        if (p != 0) {
            p->setNotifyCallback(0, 0);
    #if CALLBACK_ANTAGONIZER
            ALOGD("kill Antagonizer");
            mAntagonizer->kill();
    #endif
            p->reset();//重置状态
        }
    
        disconnectNativeWindow();
    
        IPCThreadState::self()->flushCommands();
    }
    至此,MediaPlayer在调用setDateSource()后转换到了NITIALIZED状态;最后。JNI中最外层的process_media_player_call()会依据setDateSource()的运行结果。推断是否须要抛出函数处理错误或异常信息。


    四、准备MediaPlayer实例


    给MediaPlayer设置完资源后,我们还须要对它调用prepare()方法进行准备操作:
         * Prepares the player for playback, synchronously.
         *
         * After setting the datasource and the display surface, you need to either
         * call prepare() or prepareAsync(). For files, it is OK to call prepare(),
         * which blocks until MediaPlayer is ready for playback.
         *
         * @throws IllegalStateException if it is called in an invalid state
         */
        public void prepare() throws IOException, IllegalStateException {
            _prepare();
            scanInternalSubtitleTracks();
        }
    
        private native void _prepare() throws IOException, IllegalStateException;
    直接看Native层的函数实现:
    //MediaPlayer::prepare()函数
    static void
    android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz)
    {
        sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
        if (mp == NULL ) {
            jniThrowException(env, "java/lang/IllegalStateException", NULL);
            return;
        }
    
        // Handle the case where the display surface was set before the mp was
        // initialized. We try again to make it stick.
        sp<IGraphicBufferProducer> st = getVideoSurfaceTexture(env, thiz);
        mp->setVideoSurfaceTexture(st);
    
        process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
    }
    
    static void
    android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz)
    {
        sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
        if (mp == NULL ) {
            jniThrowException(env, "java/lang/IllegalStateException", NULL);
            return;
        }
    
        // Handle the case where the display surface was set before the mp was
        // initialized. We try again to make it stick.
        sp<IGraphicBufferProducer> st = getVideoSurfaceTexture(env, thiz);
        mp->setVideoSurfaceTexture(st);
    
        process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." );
    }
    本例中,我们没有设置纹理等;直接看MediaPlayer::prepare()的实现:
    // one defined in the Android framework and one provided by the implementation
    // that generated the error. The sync version of prepare returns only 1 error
    // code.
    status_t MediaPlayer::prepare()
    {
        ALOGV("prepare");
        Mutex::Autolock _l(mLock);
        mLockThreadId = getThreadId();
        if (mPrepareSync) {
            mLockThreadId = 0;
            return -EALREADY;
        }
        mPrepareSync = true; //表示是否是同步操作
        status_t ret = prepareAsync_l();// 1
        if (ret != NO_ERROR) {
            mLockThreadId = 0;
            return ret;
        }
    
        if (mPrepareSync) {
            mSignal.wait(mLock);  // wait for prepare done
            mPrepareSync = false;
        }
        ALOGV("prepare complete - status=%d", mPrepareStatus);
        mLockThreadId = 0;
        return mPrepareStatus;
    }
    而异步地prepareAsync()函数的实现是:
    status_t MediaPlayer::prepareAsync()
    {
        ALOGV("prepareAsync");
        Mutex::Autolock _l(mLock);
        return prepareAsync_l();
    }
    对照两个函数的实现内容,就可以发现这里同步、异步的差别主要是在是否等待mLock这个锁上面。
    我们分析真正的实现函数prepare_l()方法:
    // must call with lock held
    //mPlayer实际是一个MediaPlayerServcie::Client类型的实例,它是MediaPlayerServcie的服务端
    status_t MediaPlayer::prepareAsync_l()
    {
        if ( (mPlayer != 0) && ( mCurrentState & (MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
            if (mAudioAttributesParcel != NULL) {//假设有參数,须要进行设置
                mPlayer->setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, *mAudioAttributesParcel);
            } else {
                mPlayer->setAudioStreamType(mStreamType);//否则设置之前的音频流类型
            }
            mCurrentState = MEDIA_PLAYER_PREPARING;//变更状态:MEDIA_PLAYER_PREPARING
            return mPlayer->prepareAsync();//调用MediaPlayerServcie::Client的prepareAsync()
        }
        ALOGE("prepareAsync called in state %d", mCurrentState);
        return INVALID_OPERATION;
    }
    假设当前Native MediaPlayer实例持有IMediaPlayer对象。且当前状态能够调用prepare()方法,则去调用MediaPlayerService::Client的prepareAsync()函数进行准备工作:
    status_t MediaPlayerService::Client::prepareAsync()
    {
        ALOGV("[%d] prepareAsync", mConnId);
        sp<MediaPlayerBase> p = getPlayer();//getPlayer(){return mPlayer;}返回创建的播放器实例,是MediaPlayerBase的子类;以StagefrightPlayer为例
        if (p == 0) return UNKNOWN_ERROR;
        status_t ret = p->prepareAsync();
    #if CALLBACK_ANTAGONIZER
        ALOGD("start Antagonizer");
        if (ret == NO_ERROR) mAntagonizer->start();
    #endif
        return ret;
    }
    
    getPlayer()函数返回setDataSource()过程中的创建的播放器实例:
     sp<MediaPlayerBase>     getPlayer() const { Mutex::Autolock lock(mLock); return mPlayer; }
    本文中播放器都是以StagefrightPlayer为例,所以接着去调用StagefrightPlayer::prepareAsync():
    status_t StagefrightPlayer::prepareAsync() {
        return mPlayer->prepareAsync();
    }
    最后调用AwesomePlayer的prepareAsync()函数进行准备工作。我们忽略AwesomePlayer运行prepare操作的中间过程,直接看它是怎么向外抛出MEDIA_PREPARED事件的。在AwesomePlayer的prepare操作完毕后。会调用AwesomePlayer::finishAsyncPrepare_l()方法:
    void AwesomePlayer::finishAsyncPrepare_l() {
        if (mIsAsyncPrepare) {
            if (mVideoSource == NULL) {
                notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
            } else {
                notifyVideoSize_l();
            }
    
            notifyListener_l(MEDIA_PREPARED);//抛出事件
        }
    ......
    }
    它会调用AwesomePlayer::notifyListener_l()函数向外抛出事件:
    void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
        if ((mListener != NULL) && !mAudioTearDown) {
            sp<MediaPlayerBase> listener = mListener.promote();
    
            if (listener != NULL) {
                listener->sendEvent(msg, ext1, ext2);
            }
        }
    }
    这里的listener对象指向mListener实例。StagefrightPlayer对象创建时,会顺带初始化AwesomePlayer实例mPlayer,同一时候会将当前的StagefrightPlayer设置到AwesomePlayer中,保存到mListener字段中,作为往外抛出事件的钩子。明白了这些。再看代码实现,就会发现notifyListener_l()中的处理就是直接调用StagefrightPlayer的sendEvent()方法。又依据之前介绍的StagefrightPlayer的继承关系和它的类实现来看,事实上就是调用它的父类MediaPlayerBase的sendEvent()方法:
        void        MediaPlayerBase::setNotifyCallback(
                void* cookie, notify_callback_f notifyFunc) {
            Mutex::Autolock autoLock(mNotifyLock);
            mCookie = cookie; mNotify = notifyFunc;
        }
    
        void        MediaPlayerBase::sendEvent(int msg, int ext1=0, int ext2=0,
                              const Parcel *obj=NULL) {
            notify_callback_f notifyCB;
            void* cookie;
            {
                Mutex::Autolock autoLock(mNotifyLock);
                notifyCB = mNotify;
                cookie = mCookie;
            }
    
            if (notifyCB) notifyCB(cookie, msg, ext1, ext2, obj);
        }
    如今回想一下之前介绍的setDataSource()中的内容:在MediaPlayerFactory中创建我们须要的播放器对象时。在创建完Player对象后。我们就给它设置了这里的notifyCB和cookie对象:
    //找到相应视频源类型的播放器工厂实例,并创建Player对象;最后给该Player对象设置传递消息的notifyFunc回调函数
    sp<MediaPlayerBase> MediaPlayerFactory::createPlayer(
            player_type playerType,
            void* cookie,
            notify_callback_f notifyFunc,
            pid_t pid) {
        ...
    
        init_result = p->initCheck();//实现直接return OK;
        if (init_result == NO_ERROR) {
            p->setNotifyCallback(cookie, notifyFunc);//调用父类MediaPlayerBase::setNotifyCallback();cookie是当前调用MediaPlayerService::Client::createPlayer()的Client实例,notifyFunc这里是MediaPlayerService::Client::notify()函数指针.
        } else {
            ALOGE("Failed to create player object of type %d, initCheck failed"
                  " (res = %d)", playerType, init_result);
            p.clear();
        }
    
        return p;
    }
    
    当中:
    • cookie指向当前调用MediaPlayerService::Client::createPlayer()的Client实例
    • notifyFunc是一个函数指针,这里指向MediaPlayerService::Client::notify()函数
    所以可知sendEvent():
    void        MediaPlayerBase::sendEvent(int msg, int ext1=0, int ext2=0,
                              const Parcel *obj=NULL) {
            notify_callback_f notifyCB;
            void* cookie;
            {
                Mutex::Autolock autoLock(mNotifyLock);
                notifyCB = mNotify;
                cookie = mCookie;
            }
    
            if (notifyCB) notifyCB(cookie, msg, ext1, ext2, obj);
        }
    就是调用当前播放器所属的MediaPlayerService::Client的notify()函数。

    既然明白了这些,我们就直接看notify()函数实现:

    //用于向MediaPlayer对象传递消息;參数void* cookie实际指向当前的Client实例;msg參数是事件类型信息
    void MediaPlayerService::Client::notify(
            void* cookie, int msg, int ext1, int ext2, const Parcel *obj)
    {
        Client* client = static_cast<Client*>(cookie);//首先得到当前的Client对象
        if (client == NULL) {
            return;
        }
    
        sp<IMediaPlayerClient> c;
        {
            Mutex::Autolock l(client->mLock);
            c = client->mClient;//得到该Client保存的IMediaPlayerClient对象信息,它实际指向一个Native MediaPlayer实例
            if (msg == MEDIA_PLAYBACK_COMPLETE && client->mNextClient != NULL) {//假设当前事件是MEDIA_PLAYBACK_COMPLETE,表明当前播放已经结束。而且我们设置了下一个mNextClient
                if (client->mAudioOutput != NULL)                               //就须要切换运行mNextClient;效果就是当前播放结束后,会自己主动切换到下一个播放
                    client->mAudioOutput->switchToNextOutput();
                client->mNextClient->start();
                client->mNextClient->mClient->notify(MEDIA_INFO, MEDIA_INFO_STARTED_AS_NEXT, 0, obj);//并调用notify()方法,向外告知MEDIA_INFO_STARTED_AS_NEXT事件
            }
        }
    
        if (MEDIA_INFO == msg &&
            MEDIA_INFO_METADATA_UPDATE == ext1) {//msg为MEDIA_INFO的情况
            const media::Metadata::Type metadata_type = ext2;
    
            if(client->shouldDropMetadata(metadata_type)) {
                return;
            }
    
            // Update the list of metadata that have changed. getMetadata
            // also access mMetadataUpdated and clears it.
            client->addNewMetadataUpdate(metadata_type);
        }
    
        if (c != NULL) {
            ALOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2);
            c->notify(msg, ext1, ext2, obj);//调用这一次的MediaPlayerService::Client实例相应的Native MediaPlayer实例的notify()方法
        }
    }
    首先我们得到当前的Client实例,靠它再进一步得到与它相应的Native MediaPlayer实例(MediaPlayerService::Client构建时会保存该实例)。

    这里处理几种特殊情况,当我们设置了mNextClient时(通过MediaPlayerService::Client::setNextPlayer()设置),假设msg符合情况。就会自己主动切换到下一个播放。msg为MEDIA_INFO的情况,也会有一些特殊的处理。接着,就调用MediaPlayer::notify()方法,该函数的内容之前已经介绍过一些,这里在贴一遍它的实现:

    //向应用程序反馈当前状态变化的回调事件,设置当前MediaPlayer的状态
    void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
    {
        ALOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
        bool send = true;
        bool locked = false;
    
        // TODO: In the future, we might be on the same thread if the app is
        // running in the same process as the media server. In that case,
        // this will deadlock.
        //
        // The threadId hack below works around this for the care of prepare,
        // seekTo and start within the same process.
        // FIXME: Remember, this is a hack, it's not even a hack that is applied
        // consistently for all use-cases, this needs to be revisited.
        if (mLockThreadId != getThreadId()) {
            mLock.lock();
            locked = true;
        }
    
        // Allows calls from JNI in idle state to notify errors
        if (!(msg == MEDIA_ERROR && mCurrentState == MEDIA_PLAYER_IDLE) && mPlayer == 0) {
            ALOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
            if (locked) mLock.unlock();   // release the lock when done.
            return;
        }
    
        switch (msg) {
        case MEDIA_NOP: // interface test message
            break;
        case MEDIA_PREPARED://符合当前的情况,处理Prepare完毕的情况
            ALOGV("prepared");
            mCurrentState = MEDIA_PLAYER_PREPARED;
            if (mPrepareSync) {
                ALOGV("signal application thread");
                mPrepareSync = false;
                mPrepareStatus = NO_ERROR;
                mSignal.signal();
            }
            break;
        case MEDIA_PLAYBACK_COMPLETE:
            ALOGV("playback complete");
            if (mCurrentState == MEDIA_PLAYER_IDLE) {
                ALOGE("playback complete in idle state");
            }
            if (!mLoop) {
                mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
            }
            break;
        case MEDIA_ERROR:
            // Always log errors.
            // ext1: Media framework error code.
            // ext2: Implementation dependant error code.
            ALOGE("error (%d, %d)", ext1, ext2);
            mCurrentState = MEDIA_PLAYER_STATE_ERROR;
            if (mPrepareSync)
            {
                ALOGV("signal application thread");
                mPrepareSync = false;
                mPrepareStatus = ext1;
                mSignal.signal();
                send = false;
            }
            break;
        case MEDIA_INFO:
            // ext1: Media framework error code.
            // ext2: Implementation dependant error code.
            if (ext1 != MEDIA_INFO_VIDEO_TRACK_LAGGING) {
                ALOGW("info/warning (%d, %d)", ext1, ext2);
            }
            break;
        case MEDIA_SEEK_COMPLETE:
            ALOGV("Received seek complete");
            if (mSeekPosition != mCurrentPosition) {
                ALOGV("Executing queued seekTo(%d)", mSeekPosition);
                mSeekPosition = -1;
                seekTo_l(mCurrentPosition);
            }
            else {
                ALOGV("All seeks complete - return to regularly scheduled program");
                mCurrentPosition = mSeekPosition = -1;
            }
            break;
        case MEDIA_BUFFERING_UPDATE:
            ALOGV("buffering %d", ext1);
            break;
        case MEDIA_SET_VIDEO_SIZE:
            ALOGV("New video size %d x %d", ext1, ext2);
            mVideoWidth = ext1;
            mVideoHeight = ext2;
            break;
        case MEDIA_TIMED_TEXT:
            ALOGV("Received timed text message");
            break;
        case MEDIA_SUBTITLE_DATA:
            ALOGV("Received subtitle data message");
            break;
        case MEDIA_META_DATA:
            ALOGV("Received timed metadata message");
            break;
        default:
            ALOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
            break;
        }
    
    	//JNIMediaPlayerListener继承自MediaPlayerListener,并实现了notify()方法;声明实如今android_media_MediaPlayer.cpp中
        sp<MediaPlayerListener> listener = mListener;//mListener保存了MediaPlayer实例创建时初始化的JNIMediaPlayerListener监听对象
        if (locked) mLock.unlock();
    
        // this prevents re-entrant calls into client code
        if ((listener != 0) && send) {
            Mutex::Autolock _l(mNotifyLock);
            ALOGV("callback application");
            listener->notify(msg, ext1, ext2, obj);//调用JNIMediaPlayerListener类实例的notify()方法
            ALOGV("back from callback");
        }
    }
    此时msg是MEDIA_PREPARED。看它的处理过程:
    case MEDIA_PREPARED:
            ALOGV("prepared");
            mCurrentState = MEDIA_PLAYER_PREPARED;
            if (mPrepareSync) {
                ALOGV("signal application thread");
                mPrepareSync = false;
                mPrepareStatus = NO_ERROR;
                mSignal.signal();
            }
            break;
    主要地,将MediaPlayer的当前状态设置为了MEDIA_PLAYER_PREPARED。

    最后。调用JNIMediaPlayerListener::notify()函数:
    //回调MediaPlayer.java中的postEventFromNative()方法,反馈Native层发生的事件;postEventFromNative()会EventHandler(运行在MediaPalyer的线程中)
    //发送附带msg參数的消息,EventHandler推断当前的事件类型,如MEDIA_PREPARED等,最后调用应用程序设置的相关回调处理相应的事件信息
    void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj)
    {
        JNIEnv *env = AndroidRuntime::getJNIEnv();
        if (obj && obj->dataSize() > 0) {
            jobject jParcel = createJavaParcelObject(env);
            if (jParcel != NULL) {
                Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
                nativeParcel->setData(obj->data(), obj->dataSize());
                env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
                        msg, ext1, ext2, jParcel);
                env->DeleteLocalRef(jParcel);
            }
        } else {
            env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
                    msg, ext1, ext2, NULL);
        }
        if (env->ExceptionCheck()) {
            ALOGW("An exception occurred while notifying an event.");
            LOGW_EX(env);
            env->ExceptionClear();
        }
    }
    JNIMediaPlayerListener::mObject字段是一个指向上层MediaPlayer的全局引用。终于的主要操作就是借助JNI,通过fields.post_event字段的ID值在Native层调用Java层MediaPlayer的方法-MediaPlayer::postEventFromNative():
        /*
         * Called from native code when an interesting event happens.  This method
         * just uses the EventHandler system to post the event back to the main app thread.
         * We use a weak reference to the original MediaPlayer object so that the native
         * code is safe from the object disappearing from underneath it.  (This is
         * the cookie passed to native_setup().)
         */
        private static void postEventFromNative(Object mediaplayer_ref,
                                                int what, int arg1, int arg2, Object obj)
        {
            MediaPlayer mp = (MediaPlayer)((WeakReference)mediaplayer_ref).get();//拿到给弱引用指向的MediaPlayer实例
            if (mp == null) {
                return;
            }
    
            if (what == MEDIA_INFO && arg1 == MEDIA_INFO_STARTED_AS_NEXT) {//假设是自己主动切换到下一个播放的事件或是MEDIA_INFO
                // this acquires the wakelock if needed, and sets the client side state
                mp.start();//就直接start()
            }
            if (mp.mEventHandler != null) {//最后将该事件发送到EventHandler中处理
                Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);//此时what是MEDIA_PREPARED
                mp.mEventHandler.sendMessage(m);
            }
        }
    最后会将该事件发送到EventHandler中处理:
        private class EventHandler extends Handler
        {
            private MediaPlayer mMediaPlayer;
    
            public EventHandler(MediaPlayer mp, Looper looper) {
                super(looper);
                mMediaPlayer = mp;
            }
    
            @Override
            public void handleMessage(Message msg) {
                if (mMediaPlayer.mNativeContext == 0) {
                    Log.w(TAG, "mediaplayer went away with unhandled events");
                    return;
                }
                switch(msg.what) {
                case MEDIA_PREPARED:
                    try {
                        scanInternalSubtitleTracks();
                    } catch (RuntimeException e) {
                        // send error message instead of crashing;
                        // send error message instead of inlining a call to onError
                        // to avoid code duplication.
                        Message msg2 = obtainMessage(
                                MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
                        sendMessage(msg2);
                    }
                    if (mOnPreparedListener != null)
                        mOnPreparedListener.onPrepared(mMediaPlayer);
                    return;
    
                case MEDIA_PLAYBACK_COMPLETE:
                    if (mOnCompletionListener != null)
                        mOnCompletionListener.onCompletion(mMediaPlayer);
                    stayAwake(false);
                    return;
    
                case MEDIA_STOPPED:
                    {
                        TimeProvider timeProvider = mTimeProvider;
                        if (timeProvider != null) {
                            timeProvider.onStopped();
                        }
                    }
                    break;
    
                case MEDIA_STARTED:
                case MEDIA_PAUSED:
                    {
                        TimeProvider timeProvider = mTimeProvider;
                        if (timeProvider != null) {
                            timeProvider.onPaused(msg.what == MEDIA_PAUSED);
                        }
                    }
                    break;
    
                case MEDIA_BUFFERING_UPDATE:
                    if (mOnBufferingUpdateListener != null)
                        mOnBufferingUpdateListener.onBufferingUpdate(mMediaPlayer, msg.arg1);
                    return;
    
                case MEDIA_SEEK_COMPLETE:
                    if (mOnSeekCompleteListener != null) {
                        mOnSeekCompleteListener.onSeekComplete(mMediaPlayer);
                    }
                    // fall through
    
                case MEDIA_SKIPPED:
                    {
                        TimeProvider timeProvider = mTimeProvider;
                        if (timeProvider != null) {
                            timeProvider.onSeekComplete(mMediaPlayer);
                        }
                    }
                    return;
    
                case MEDIA_SET_VIDEO_SIZE:
                    if (mOnVideoSizeChangedListener != null) {
                        mOnVideoSizeChangedListener.onVideoSizeChanged(
                            mMediaPlayer, msg.arg1, msg.arg2);
                    }
                    return;
    
                case MEDIA_ERROR:
                    Log.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")");
                    boolean error_was_handled = false;
                    if (mOnErrorListener != null) {
                        error_was_handled = mOnErrorListener.onError(mMediaPlayer, msg.arg1, msg.arg2);
                    }
                    if (mOnCompletionListener != null && ! error_was_handled) {
                        mOnCompletionListener.onCompletion(mMediaPlayer);
                    }
                    stayAwake(false);
                    return;
    
                case MEDIA_INFO:
                    switch (msg.arg1) {
                    case MEDIA_INFO_VIDEO_TRACK_LAGGING:
                        Log.i(TAG, "Info (" + msg.arg1 + "," + msg.arg2 + ")");
                        break;
                    case MEDIA_INFO_METADATA_UPDATE:
                        try {
                            scanInternalSubtitleTracks();
                        } catch (RuntimeException e) {
                            Message msg2 = obtainMessage(
                                    MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
                            sendMessage(msg2);
                        }
                        // fall through
    
                    case MEDIA_INFO_EXTERNAL_METADATA_UPDATE:
                        msg.arg1 = MEDIA_INFO_METADATA_UPDATE;
                        // update default track selection
                        if (mSubtitleController != null) {
                            mSubtitleController.selectDefaultTrack();
                        }
                        break;
                    case MEDIA_INFO_BUFFERING_START:
                    case MEDIA_INFO_BUFFERING_END:
                        TimeProvider timeProvider = mTimeProvider;
                        if (timeProvider != null) {
                            timeProvider.onBuffering(msg.arg1 == MEDIA_INFO_BUFFERING_START);
                        }
                        break;
                    }
    
                    if (mOnInfoListener != null) {
                        mOnInfoListener.onInfo(mMediaPlayer, msg.arg1, msg.arg2);
                    }
                    // No real default action so far.
                    return;
                case MEDIA_TIMED_TEXT:
                    if (mOnTimedTextListener == null)
                        return;
                    if (msg.obj == null) {
                        mOnTimedTextListener.onTimedText(mMediaPlayer, null);
                    } else {
                        if (msg.obj instanceof Parcel) {
                            Parcel parcel = (Parcel)msg.obj;
                            TimedText text = new TimedText(parcel);
                            parcel.recycle();
                            mOnTimedTextListener.onTimedText(mMediaPlayer, text);
                        }
                    }
                    return;
    
                case MEDIA_SUBTITLE_DATA:
                    if (mOnSubtitleDataListener == null) {
                        return;
                    }
                    if (msg.obj instanceof Parcel) {
                        Parcel parcel = (Parcel) msg.obj;
                        SubtitleData data = new SubtitleData(parcel);
                        parcel.recycle();
                        mOnSubtitleDataListener.onSubtitleData(mMediaPlayer, data);
                    }
                    return;
    
                case MEDIA_META_DATA:
                    if (mOnTimedMetaDataAvailableListener == null) {
                        return;
                    }
                    if (msg.obj instanceof Parcel) {
                        Parcel parcel = (Parcel) msg.obj;
                        TimedMetaData data = TimedMetaData.createTimedMetaDataFromParcel(parcel);
                        parcel.recycle();
                        mOnTimedMetaDataAvailableListener.onTimedMetaDataAvailable(mMediaPlayer, data);
                    }
                    return;
    
                case MEDIA_NOP: // interface test message - ignore
                    break;
    
                default:
                    Log.e(TAG, "Unknown message type " + msg.what);
                    return;
                }
            }
        }
    当前事件是MEDIA_PREPARED。它的处理过程是:
    case MEDIA_PREPARED:
                    try {
                        scanInternalSubtitleTracks();
                    } catch (RuntimeException e) {
                        // send error message instead of crashing;
                        // send error message instead of inlining a call to onError
                        // to avoid code duplication.
                        Message msg2 = obtainMessage(
                                MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
                        sendMessage(msg2);
                    }
                    if (mOnPreparedListener != null)
                        mOnPreparedListener.onPrepared(mMediaPlayer);
                    return;
    当中要注意最后一部分。mOnPreparedListener对象是一个回调,它一般通过setOnPreparedListener()函数注冊:
        /**
         * Register a callback to be invoked when the media source is ready
         * for playback.
         *
         * @param listener the callback that will be run
         */
        public void setOnPreparedListener(OnPreparedListener listener)
        {
            mOnPreparedListener = listener;
        }
    像我们使用异步prepareAsync()时,由于它的运行会立马返回。所以我们就须要系统告诉我们MediaPlayer的prepare工作何时已经完毕。并在完毕时让系统调用我们注冊的回调。让我们的MediaPlayer在prepare完毕后開始运行播放。
    在EventHandler的处理中,假设mOnPreparedListener不为空(表明用户注冊了这个回调,那么这时就去调用它。以完毕用户须要的操作)。

    这一部分除了分析prepare()函数外,我们还要注意的是MediaPlayer的状态事件是怎样从底层一步一步传到上层来的,这对我们理解MediaPlayer的整个实现过程是非常重要的。
    最后,在JNI部分的处理中,最外层的process_media_player_call()会依据prepare()的运行结果,推断是否须要抛出函数处理错误或异常信息。

    五、开启MediaPlayer


    在MediaPlayer运行完prepare之后,我们就能够正式开启它開始播放了。看MediaPlayer::start()方法实现:
        /**
         * Starts or resumes playback. If playback had previously been paused,
         * playback will continue from where it was paused. If playback had
         * been stopped, or never started before, playback will start at the
         * beginning.
         *
         * @throws IllegalStateException if it is called in an invalid state
         */
        public void start() throws IllegalStateException {
            if (isRestricted()) {
                _setVolume(0, 0);
            }
            stayAwake(true);
            _start();
        }
    
        private native void _start() throws IllegalStateException;
    调用start()后。能够是从暂停状态又一次開始 播放;也可是全然从头開始播放。直接看它的native层调用:
    static void
    android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
    {
        ALOGV("start");
        sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
        if (mp == NULL ) {
            jniThrowException(env, "java/lang/IllegalStateException", NULL);
            return;
        }
        process_media_player_call( env, thiz, mp->start(), NULL, NULL );
    }
    有了前面分析的内容铺垫。我们就直接进入MediaPlayer::start():
    status_t MediaPlayer::start()
    {
        ALOGV("start");
    
        status_t ret = NO_ERROR;
        Mutex::Autolock _l(mLock);
    
        mLockThreadId = getThreadId();
    
        if (mCurrentState & MEDIA_PLAYER_STARTED) {//MediaPlayer当前状态是MEDIA_PLAYER_STARTED,则直接返回
            ret = NO_ERROR;
        } else if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
                        MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {//能运行start操作的状态
            mPlayer->setLooping(mLoop);//mLoop是一个布尔值,它表示当前是否须要循环播放;它的初始值是FALSE,上层能够设置该值
            mPlayer->setVolume(mLeftVolume, mRightVolume);//设置音量
            mPlayer->setAuxEffectSendLevel(mSendLevel);
            mCurrentState = MEDIA_PLAYER_STARTED;//将MediaPlayer的状态设置为MEDIA_PLAYER_STARTED
            ret = mPlayer->start();//调用MediaPlayerService::Client的start()
            if (ret != NO_ERROR) {
                mCurrentState = MEDIA_PLAYER_STATE_ERROR;
            } else {
                if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
                    ALOGV("playback completed immediately following start()");
                }
            }
        } else {
            ALOGE("start called in state %d", mCurrentState);
            ret = INVALID_OPERATION;
        }
    
        mLockThreadId = 0;
    
        return ret;
    }
    首先会推断MediaPlayer当前的状态能否进行start操作。接着。还会涉及到是否循环播放、音量的设置;最后调用到MediaPlayerService::Client::start()方法中:
    status_t MediaPlayerService::Client::start()
    {
        ALOGV("[%d] start", mConnId);
        sp<MediaPlayerBase> p = getPlayer();
        if (p == 0) return UNKNOWN_ERROR;
        p->setLooping(mLoop);
        return p->start();
    }
    处理非常easy。设置是否循环播放。调用播放器的start()方法开启播放(StagefrightPlayer为例)。

    StagefrightPlayer::start()方法实现:

    status_t StagefrightPlayer::start() {
        ALOGV("start");
    
        return mPlayer->play();
    }
    终于调用到AwesomePlayer::play()方法。通过AwesomePlayer与HAL的交互来完毕视频的播放操作。
    与MediaPlayer的prepare操作相似。当AwesomePlayer完毕start()后,就会调用AwesomePlayer::notifyIfMediaStarted_l()函数:
    void AwesomePlayer::notifyIfMediaStarted_l() {
        if (mMediaRenderingStartGeneration == mStartGeneration) {
            mMediaRenderingStartGeneration = -1;
            notifyListener_l(MEDIA_STARTED);
        }
    }
    它会向上层抛出MEDIA_STARTED事件。该事件的处理流程与prepare阶段中的事件处理流程一致(仅仅是有最后处不处理的差别)。

    最后,最外层的process_media_player_call()调用会依据start()的运行结果,推断是否须要抛出函数处理错误或异常信息。


    至此,MediaPlayer使用演示样例代码中的5个重要步骤的底层实现就介绍完了。


    事实上MediaPlayer还提供了一系列重载的create()函数。来简化我们使用的步骤。我们仅仅看一个比較具代表性的样例:
        /**
         * Same factory method as {@link #create(Context, int)} but that lets you specify the audio
         * attributes and session ID to be used by the new MediaPlayer instance.
         * @param context the Context to use
         * @param resid the raw resource id (<var>R.raw.<something></var>) for
         *              the resource to use as the datasource
         * @param audioAttributes the {@link AudioAttributes} to be used by the media player.
         * @param audioSessionId the audio session ID to be used by the media player,
         *     see {@link AudioManager#generateAudioSessionId()} to obtain a new session.
         * @return a MediaPlayer object, or null if creation failed
         */
        public static MediaPlayer create(Context context, int resid,
                AudioAttributes audioAttributes, int audioSessionId) {
            try {
                AssetFileDescriptor afd = context.getResources().openRawResourceFd(resid);
                if (afd == null) return null;
    
                MediaPlayer mp = new MediaPlayer();// 1
    
                final AudioAttributes aa = audioAttributes != null ? audioAttributes :
                    new AudioAttributes.Builder().build();
                mp.setAudioAttributes(aa);
                mp.setAudioSessionId(audioSessionId);
    
                mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());// 2
                afd.close();
                mp.prepare();// 3
                return mp;
            } catch (IOException ex) {
                Log.d(TAG, "create failed:", ex);
                // fall through
            } catch (IllegalArgumentException ex) {
                Log.d(TAG, "create failed:", ex);
               // fall through
            } catch (SecurityException ex) {
                Log.d(TAG, "create failed:", ex);
                // fall through
            }
            return null;
        }
    通过MediaPlayer::create()的凝视可知,官方是推荐我们使用createe()方法的。从代码中的1、2、3标记可知。我们仅仅需传入须要使用的资源标示符就可以,create()会帮助我们创建MediaPlayer、同一时候也会去初始化和prepare它。

    MediaPlayer::create()让我们使用MediaPlayer时更加简便、快捷。在调用create()函数之后。我们仅仅需调用start()就可使用MediaPlayer了。



    另外,有了之前的分析,相信我们再看MediaPlayer的其它函数实现,也不会有太大问题了。





  • 相关阅读:
    POJ--3164--Command Network【朱刘算法】最小树形图
    金典 SQL笔记(6)
    hdoj1106排序
    linux程序设计——运行SQL语句(第八章)
    iOS-UITextView-文本输入视图的使用
    HDU 5305 Friends(简单DFS)
    Android IntentService全然解析 当Service遇到Handler
    概要设计的要点
    DispatcherTimer
    原型模式
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/8715660.html
Copyright © 2011-2022 走看看