【三】Android MediaPlayer整体架构源码分析 -【设置数据源】【Part 1】

承接上一章节分析:【一】Android MediaPlayer整体架构源码分析 -【初始化和创建】
本系列文章分析的安卓源码版本:【Android 10.0 版本】

setDataSource方法实现流程分析
设置数据源示例:

mMediaPlayer.setDataSource(mPath);

通过java层MediaPlayer的源码分析可知,setDataSource有多个重载方法,但最终只对应有3个native方法,如下:
多个java重载方法,但目前暂时只先分析传递string URL参数的方法(数据流可为本地文件或网络传输)处理流程:【后续有时间再分析其他实现】
由注释可知,该path可传入http/rtsp URL或文件路径均可。

// [android.media.MediaPlayer.java]
    /**
     * Sets the data source (file-path or http/rtsp URL) to use.
     *
     * <p>When <code>path</code> refers to a local file, the file may actually be opened by a
     * process other than the calling application.  This implies that the pathname
     * should be an absolute path (as any other process runs with unspecified current working
     * directory), and that the pathname should reference a world-readable file.
     * As an alternative, the application could first open the file for reading,
     * and then use the file descriptor form {@link #setDataSource(FileDescriptor)}.
     *
     * @param path the path of the file, or the http/rtsp URL of the stream you want to play
     * @throws IllegalStateException if it is called in an invalid state
     */
    public void setDataSource(String path)
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
        setDataSource(path, null, null);
    }

@UnsupportedAppUsage
    private void setDataSource(String path, Map<String, String> headers, List<HttpCookie> cookies)
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException
    {
        String[] keys = null;
        String[] values = null;

        if (headers != null) {
            keys = new String[headers.size()];
            values = new String[headers.size()];

            int i = 0;
            for (Map.Entry<String, String> entry: headers.entrySet()) {
                keys[i] = entry.getKey();
                values[i] = entry.getValue();
                ++i;
            }
        }
        setDataSource(path, keys, values, cookies);
    }
    
@UnsupportedAppUsage
    private void setDataSource(String path, String[] keys, String[] values,
            List<HttpCookie> cookies)
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
        // 将其转换为URI类型
        final Uri uri = Uri.parse(path);
        // URL(网络)协议头
        final String scheme = uri.getScheme();
        if ("file".equals(scheme)) {
        	// 若是file文件协议则
            path = uri.getPath();
        } else if (scheme != null) {
        	// 否则协议头就是非文件流即网络流
            // handle non-file sources
            nativeSetDataSource(
                MediaHTTPService.createHttpServiceBinderIfNecessary(path, cookies),
                path,
                keys,
                values);
            return;
        }

        final File file = new File(path);
        try (FileInputStream is = new FileInputStream(file)) {
        	// 读取文件输入流并且设置文件描述符
            setDataSource(is.getFD());
        }
    }
    
    public void setDataSource(FileDescriptor fd)
            throws IOException, IllegalArgumentException, IllegalStateException {
        // 默认设置文件长度为long类型最大,从头开始读取,一般情况下不会有比这个长
        // intentionally less than LONG_MAX
        setDataSource(fd, 0, 0x7ffffffffffffffL);
    }

    public void setDataSource(FileDescriptor fd, long offset, long length)
            throws IOException, IllegalArgumentException, IllegalStateException {
        // 最后调用该native层方法
        _setDataSource(fd, offset, length);
    }

3个native方法:

// [android.media.MediaPlayer.java]
	
	// 有参数名可知,该方法是给网络播放源使用的
    private native void nativeSetDataSource(
        IBinder httpServiceBinder, String path, String[] keys, String[] values)
        throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;

	// 文件播放源进行播放
    private native void _setDataSource(FileDescriptor fd, long offset, long length)
            throws IOException, IllegalArgumentException, IllegalStateException;

	// 根据MediaDataSource类的功能声明来看,其实就是给了应用层进行控制数据读取位置来指定数据播放
    private native void _setDataSource(MediaDataSource dataSource)
          throws IllegalArgumentException, IllegalStateException;

这三个native方法在jni层的调用声明如下:
即它们是通过JNI的方法映射对应别名方法的调用,JNI层这种做法比较主流。

// [frameworks/base/media/jni/android_media_MediaPlayer.cpp]
static const JNINativeMethod gMethods[] = {
	// 见第1小节分析
    {"_setDataSource",      "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer_setDataSourceFD},
    
	// 见第2小节分析
    {
        "nativeSetDataSource",
        "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;"
        "[Ljava/lang/String;)V",
        (void *)android_media_MediaPlayer_setDataSourceAndHeaders
    },
    
    // 见第3小节分析
    {"_setDataSource",      "(Landroid/media/MediaDataSource;)V",(void *)android_media_MediaPlayer_setDataSourceCallback },

	// ... 省略其他代码
}

1、android_media_MediaPlayer_setDataSourceFD实现分析:
通过文件描述符来设置数据源

// [frameworks/base/media/jni/android_media_MediaPlayer.cpp]
static void
android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
{
    // 获取native层此前创建缓存的MediaPlayer对象
    // 见1.1小节分析
    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;
    }
    // jni层从文件描述符对象中获取int型文件描述符值,用于标记该访问文件
    // 此处不展开分析【比如路径文件打不开则会返回-1等错误】
    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    ALOGV("setDataSourceFD: fd %d", fd);
    // 然后调用了native层MediaPlayer的setDataSource方法
    // 见1.2小节分析
    process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
}

1.1、getMediaPlayer(env, thiz)实现分析:
此为static方法,注意在C++中,static修饰的方法不是静态方法,而是只在当前cpp文件中被访问的方法,其他文件访问不了,可以称为本地方法

// [frameworks/base/media/jni/android_media_MediaPlayer.cpp]
static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)
{
    Mutex::Autolock l(sLock);
    // 由前面章节分析可知,该字段即为此前创建缓存的native层MediaPlayer对象指针值,
    // 将其强制转换为该对象指针,然后进行返回sp智能指针对象,
    // 以便在使用过程中用于控制指针的引用计数
    MediaPlayer* const p = (MediaPlayer*)env->GetLongField(thiz, fields.context);
    return sp<MediaPlayer>(p);
}

1.2、mp->setDataSource(fd, offset, length)实现分析:

// [frameworks/av/media/libmedia/mediaplayer.cpp]
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;
    // 通过Binder机制获取BpMediaPlayerService媒体播放器服务代理实现
    // 见1.2.1小节分析
    const sp<IMediaPlayerService> service(getMediaPlayerService());
    if (service != 0) {
    	// create实现,见1.2.2小节分析
        sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
        // doSetRetransmitEndpoint 处理为:判断player是否有效并且判断是否需要设置UDP重传端点URL设置信息,
        // 该功能是java层MediaPlayer会进行的设置,但是目前没有开放给应用层使用,
        // 其功能主要就是:若设置了该UDP端口重传端点信息,则MediaPlayer将不会进行解码和播放,
        // 只会进行网络传输数据(如使用RTP格式封装数据后进行传输)。
        
        // player->setDataSource:调用了服务端MediaPlayer的该方法
        // 见1.2.3小节分析
        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
            (NO_ERROR != player->setDataSource(fd, offset, length))) {
            // 若有异常失败,则释放当前持有的服务端MediaPlayer的Bp代理对象内存
            // clear方法是智能指针相关的实现,关于智能指针实现原理后续章节分析下
            player.clear();
        }
        // 进行关联新的服务端Client播放器代理对象
        // 见1.2.4小节分析
        err = attachNewPlayer(player);
    }
    return err;
}

1.2.1、getMediaPlayerService()实现分析:【获取BpMediaPlayerService】
此方法实现原理为:Android C++层Binder机制实现,即向注册服务管理中心获取自己的服务即Bp实现对象,也是Bn对象的在客户端的代理操作对象。
关于Binder机制实现原理可参考我另一章节分析:Android C++底层Binder通信机制原理分析总结【通俗易懂】

// [frameworks/av/media/libmedia/IMediaDeathNotifier.cpp]

// establish binder interface to MediaPlayerService
/*static*/const sp<IMediaPlayerService>
IMediaDeathNotifier::getMediaPlayerService()
{
    ALOGV("getMediaPlayerService");
    Mutex::Autolock _l(sServiceLock);
    if (sMediaPlayerService == 0) {
    	// 获取注册服务管理中心即BpServiceManager,单列模式
        sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder;
        do {
        	// 通过响应服务注册时的服务名称【"media.player"】获取注册过的服务
            binder = sm->getService(String16("media.player"));
            if (binder != 0) {
                break;
            }
            // 服务未注册,则每隔0.5毫秒重新获取一次
            ALOGW("Media player service not published, waiting...");
            usleep(500000); // 0.5 s
        } while (true);

        // 若为空则创建一个全局的Binder异常关闭的监听,监听接收到对端Binder进程异常的通知
        if (sDeathNotifier == NULL) {
            sDeathNotifier = new DeathNotifier();
        }
        binder->linkToDeath(sDeathNotifier);
        
        // 最后使用interface_cast转换成对应服务取得Bp代理对象,
        // 即获取到了BpMediaPlayerService实现,此处转换成它的父类类型返回
        sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
    }
    ALOGE_IF(sMediaPlayerService == 0, "no media player service!?");
    return sMediaPlayerService;
}

1.2.2、service->create(this, mAudioSessionId)实现分析:
由前面的分析,我们直接查找BpMediaPlayerService对应的实现,如下

// [frameworks/av/media/libmedia/IMediaPlayerService.cpp]
    virtual sp<IMediaPlayer> create(
            const sp<IMediaPlayerClient>& client, audio_session_t audioSessionId) {
        // 此处即为Binder机制实现的代理调用发送端实现,发送和等待返回的数据类型均为Parcel
        // 将请求参数封装到data中,创建等待返回数据的replay
        Parcel data, reply;
        
		// 通过Binder机制分析可知,getInterfaceDescriptor()该方法为宏定义中实现的,
		// 其获取的值其实是如下宏定义赋值的字符串即接口描述符【"android.media.IMediaPlayerService"】
		// IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.media.IMediaPlayerService");
        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
        // 将client即当前native层的MediaPlayer对象,
        // 即由Binder机制实现可知,该对象为Bn实现端,将其强转为IBinder类型传递
        data.writeStrongBinder(IInterface::asBinder(client));
        data.writeInt32(audioSessionId);

        // 发起【CREATE】事务码的Binder请求,
        // 写入请求数据到Binder驱动,等待replay读取返回数据,
        // BpRefBase中的remote()方法返回的mRemote即BpBinder对象实例用来和Binder驱动交互使用。
        // 注意:此处的【CREATE】非常重要,其是枚举类型,代表着Binder通信的事务请求事件标识码,
        // 即服务端在Bn实现端的onTransact()需要根据该请求类型标识,
        // 来执行对应的任务,此处为创建MediaPlayer的事务请求事件
        remote()->transact(CREATE, data, &reply);
        // 远程服务端响应处理后返回创建的IMediaPlayer对象。
        // 最后使用interface_cast转换成对应的Bp代理对象,
        // 即获取到了BpMediaPlayer实现,此处转换成它的父类类型返回
        return interface_cast<IMediaPlayer>(reply.readStrongBinder());
    }

根据Binder实现机制,直接定位到服务端的Bn实现端即BnMediaPlayerService的onTransact()方法处理【CREATE】事务事件流程:

// [frameworks/av/media/libmedia/IMediaPlayerService.cpp]
tatus_t BnMediaPlayerService::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch (code) {
    	// 接收到Binder通信的事务请求事件标识码[CREATE]
        case CREATE: {
        	// 宏定义代码,检查接口调用端是否有权限,内部主要就是对参数中的接口描述符字符串
        	// 和当前进程中对应值进行校验【binder->getInterfaceDescriptor()】
        	// 若校验失败则直接return返回PERMISSION_DENIED无权限。
        	// 校验方式主要是调用传入参数Parcel对象的【checkInterface】方法
            CHECK_INTERFACE(IMediaPlayerService, data, reply);
            
            // 由上面的分析,此处读取的就是传入参数中的IMediaPlayerClient的Bn实现对象,因此服务端使用时需要使用interface_cast转换成对应的Bp代理对象
            sp<IMediaPlayerClient> client =
                interface_cast<IMediaPlayerClient>(data.readStrongBinder());
            // 再获取session id信息
            // 【备注:Parcel读取必须按顺序读取】
            audio_session_t audioSessionId = (audio_session_t) data.readInt32();
            // 然后调用了BnMediaPlayerService派生类的create方法
            // 见下面的分析
            sp<IMediaPlayer> player = create(client, audioSessionId);
            // 创建执行完毕后,响应【返回】创建服务端IMediaPlayer的Bn实现对象给调用端【客户端】
            // 由上可知,客户端最后也使用了interface_cast转换成对应的Bp代理对象进行使用
            reply->writeStrongBinder(IInterface::asBinder(player));
            return NO_ERROR;
        } break;
        
        // ... 省略其他代码
    }
}

create(client, audioSessionId)实现分析:
通过分析可知,BnMediaPlayerService的子类实现了该方法,即MediaPlayerService实现类,其声明如下

// [frameworks/av/media/libmediaplayerservice/MediaPlayerService.h]
class MediaPlayerService : public BnMediaPlayerService {}

// [frameworks/av/media/libmedia/include/media/IMediaPlayerServive.h]
class BnMediaPlayerService: public BnInterface<IMediaPlayerService> {}

// [frameworks/av/media/libmedia/include/media/IMediaPlayerServive.h]
class IMediaPlayerService: public IInterface {}

// [frameworks/native/libs/binder/include/binder/IInterface.h]
class IInterface : public virtual RefBase {}

// [frameworks/native/libs/binder/include/binder/IInterface.h]
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder {}

// [frameworks/native/libs/binder/include/binder/Binder.h]
class BBinder : public IBinder {}

// [frameworks/native/libs/binder/include/binder/IBinder.h]
class [[clang::lto_visibility_public]] IBinder : public virtual RefBase {}

create该方法的实现:

// [frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp]
sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,
        audio_session_t audioSessionId)
{
    // 此为获取到当前调用进程的进程ID【如何获取此处暂不展开分析】
    // 【注:该值其实就是调用者进程ID,即上层APP的调用进程】
    pid_t pid = IPCThreadState::self()->getCallingPid();
    // 【mNextConnId】该字段值记录的是:
    // 当前MediaPlayerService创建连接过的Client播放器的计数值,作为一个连接ID
    // 【包括已释放的对象,因为该变量计数没有调用减法操作】。
    // android_atomic_inc方法为原子性自增操作,其内部调用了android_atomic_add函数(内嵌汇编实现)
    int32_t connId = android_atomic_inc(&mNextConnId);

    // 创建服务端Bn实现端(BnMediaPlayer)子类Client播放器对象
    // Client类的声明是[/frameworks/av/media/libmediaplayerservice/MediaPlayerService.h]文件中MediaPlayerService类的内部类
    // 参数【getCallingUid()】获取的是调用者用户ID,
    // 在 Android 上,一个应用程序只有一个UID,当然多个应用程序也可以共享(android:sharedUserId)一个UID。
    // 该ID主要用于数据共享或权限检查(Linux上是多用户ID)
    // Client类对象初始化创建,见下面的分析
    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());

    // 注意此处将Client新对象强引用转换给弱引用指针对象,然后进行缓存
    wp<Client> w = c;
    {
        // 加锁缓存的当前新创建Client弱引用对象在【mClients】集合列表中,
        // 其声明为【SortedVector< wp<Client> >  mClients;】
        Mutex::Autolock lock(mLock);
        mClients.add(w);
    }
    // 然后Binder机制返回给请求的客户端
    return c;
}

Client类声明和构造函数实现:

// [/frameworks/av/media/libmediaplayerservice/MediaPlayerService.h]
    class Client : public BnMediaPlayer {
        // IMediaPlayer interface
    	// 省略其他代码
    }
    
// [/frameworks/av/media/libmedia/include/media/IMediaPlayer.h]
class BnMediaPlayer: public BnInterface<IMediaPlayer> {}

// [/frameworks/av/media/libmedia/include/media/IMediaPlayer.h]
class IMediaPlayer: public IInterface {}

// 构造函数
// [/frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp]
MediaPlayerService::Client::Client(
        const sp<MediaPlayerService>& service, pid_t pid,
        int32_t connId, const sp<IMediaPlayerClient>& client,
        audio_session_t audioSessionId, uid_t uid)
{// 初始化操作
    ALOGV("Client(%d) constructor", connId);
    mPid = pid;
    mConnId = connId;
    mService = service;
    mClient = client;
    mLoop = false;
    mStatus = NO_INIT;
    mAudioSessionId = audioSessionId;
    mUid = uid;
    mRetransmitEndpointValid = false;
    mAudioAttributes = NULL;
    // 该类是当前Client类的内部类,其声明和实现见下面的分析
    // 创建一个监听事件对象,其实际就是代理调用Client自己的notify()方法
    mListener = new Listener(this);

// 该宏定义默认为0即false,因此暂不分析
#if CALLBACK_ANTAGONIZER
    ALOGD("create Antagonizer");
    mAntagonizer = new Antagonizer(mListener);
#endif
}

Listener的声明和实现:
Client类的内部类,其实现很简单,就是缓存当前Client对象的弱引用,并调用client对象的notify方法,就相当于一个代理类实现作用,主要就是简化调用即若直接调用则需要每次都判断Client弱引用对象并将其提升为强引用对象,然后判断是否提升成功,若当前Client对象没有被释放内存,则提升成功,否则为null

// [/frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp]
        class Listener : public MediaPlayerBase::Listener {
        public:
            Listener(const wp<Client> &client) : mClient(client) {}
            virtual ~Listener() {}
            virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) {
                // 提升弱指针代理调用处理
                sp<Client> client = mClient.promote();
                if (client != NULL) {
                    client->notify(msg, ext1, ext2, obj);
                }
            }
        private:
            wp<Client> mClient;
        };

1.2.3、player->setDataSource(fd, offset, length)实现分析:
由上面的分析,可知调用的Client代理对象即BpMediaPlayer代理类的该方法实现:

// [frameworks/av/media/libmedia/IMediaPlayer.cpp]
    status_t setDataSource(int fd, int64_t offset, int64_t length) {
    	// 数据打包并进行Binder事务请求
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
        data.writeFileDescriptor(fd);
        data.writeInt64(offset);
        data.writeInt64(length);
        // 发起【SET_DATA_SOURCE_FD】事务码的Binder请求,
        // 写入请求数据到Binder驱动,等待replay读取返回数据,
        // BpRefBase中的remote()方法返回的mRemote即BpBinder对象实例用来和Binder驱动交互使用。
        remote()->transact(SET_DATA_SOURCE_FD, data, &reply);
        // 服务端处理完成后在reply变量中存储了状态值,进行读取
        return reply.readInt32();
    }

然后通过Binder机制请求服务端BnMediaPlayer的onTransact()方法对应事务码处理流程实现:

// [frameworks/av/media/libmedia/IMediaPlayer.cpp]
status_t BnMediaPlayer::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{// ... 省略其他代码
    switch (code) {
        case SET_DATA_SOURCE_FD: {
        	// 检查客户端调用接口是否有权限
            CHECK_INTERFACE(IMediaPlayer, data, reply);
            // 依次读取参数变量Parcel中的参数值
            int fd = data.readFileDescriptor();
            int64_t offset = data.readInt64();
            int64_t length = data.readInt64();
            // 调用BnMediaPlayer实现者子类该方法【setDataSource】实现即Client类的该方法实现,见下面的分析
            // 然后将该方法的返回状态码写入应答reply对象中,以供调用端读取该值
            reply->writeInt32(setDataSource(fd, offset, length));
            return NO_ERROR;
        }
    }
}

setDataSource(fd, offset, length)实现分析:
【由于当前文章篇幅较长,因此将其放入当前章节的第二部分接着分析】
请查看:
【三】Android MediaPlayer整体架构源码分析 -【设置数据源】【Part 2】

1.2.4、attachNewPlayer(player)实现分析:
关联新的服务端Client播放器代理对象

// [frameworks/av/media/libmedia/mediaplayer.cpp]
status_t MediaPlayer::attachNewPlayer(const sp<IMediaPlayer>& player)
{
    status_t err = UNKNOWN_ERROR;
    sp<IMediaPlayer> p;
    // 加锁代码块处理
    { // scope for the lock
        Mutex::Autolock _l(mLock);

        // 此处检查当前native层播放器类状态,必须为包含IDLE或等于ERROR状态,才能关联(缓存)新的播放器对象。
        // 注意此处的处理上的不同,IDLE使用的&与运算符,若包含该状态则结果为true,
        // 而ERROR是 == 相等运算符即必须当前状态不包含其他状态并且等于该状态则为true。
        if ( !( (mCurrentState & MEDIA_PLAYER_IDLE) ||
                (mCurrentState == MEDIA_PLAYER_STATE_ERROR ) ) ) {
            ALOGE("attachNewPlayer called in state %d", mCurrentState);
            return INVALID_OPERATION;
        }

        // 清空相关变量值操作
        // 见1.2.4.1小节分析
        clear_l();
        // 记录旧对象,并缓存新对象到类全局变量中
        p = mPlayer;
        mPlayer = player;
        if (player != 0) {
        	// 新对象成功,则改为初始化状态
            mCurrentState = MEDIA_PLAYER_INITIALIZED;
            err = NO_ERROR;
        } else {
            ALOGE("Unable to create media player");
        }
    }

    if (p != 0) {
    	// 若有旧对象,则执行其断开连接操作方法
    	// // 见1.2.4.2小节分析【根据前面分析,可知该对象为服务端Client播放器对象】
        p->disconnect();
    }
	
	// 并且注意,在该方法返回时旧对象p即智能指针对象将会执行智能指针对象自身析构函数,
	// 即减少Client对象指针引用到0,释放Client对象内存【delete】,
	// 因此即会导致Client对象的析构函数也会被调用。
	// 见1.2.4.3小节分析
	
    return err;
}

1.2.4.1、clear_l()实现分析:
清空相关变量值操作

// [frameworks/av/media/libmedia/mediaplayer.cpp]
// always call with lock held
void MediaPlayer::clear_l()
{
    mCurrentPosition = -1;
    mCurrentSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
    mSeekPosition = -1;
    mSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
    mVideoWidth = mVideoHeight = 0;
    mRetransmitEndpointValid = false;
}

1.2.4.2、p->disconnect()实现分析:

// [frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp]
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);
        // 由前面的分析可知,mPlayer是前面创建的NuPlayerDriver播放器对象
        // 获取缓存的NuPlayerDriver类对象
        // 注意:由智能指针sp的实现原理可知,赋值=运算符会导致其内部缓存的NuPlayerDriver对象指针引用计数再加1
        p = mPlayer;
        // 执行智能指针clear方法即减少mClient指针对象的引用计数,
        // 该对象是native层MediaPlayer对象类型,
        // 但注意:此处执行之后却不会执行该对象的析构函数,因此此处的处理
        // 只为清空Client的该缓冲字段值即将其指针引用计数减少,
        // 但其引用计数不会为0【因为JNI层还有对该对象的引用计数】,
        // 所以不会执行其析构函数,只是不在引用它
        mClient.clear();
        // 执行智能指针clear方法,减小NuPlayerDriver类对象指针引用计数
        // 注意:有上面分析,此处执行智能指针sp的clear方法只是减少引用计数到1,还不会执行释放内存操作【即delete内存,会由此处的局部变量p来自动完成】
        // 并且此处执行clear也是为了清空类全局智能指针变量mPlayer内部的实际对象指针赋值为空即0
        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) {
    	// 清空旧NuPlayerDriver对象的通知回调监听,前面已分析过
        p->setNotifyCallback(0);
#if CALLBACK_ANTAGONIZER
        ALOGD("kill Antagonizer");
        mAntagonizer->kill();
#endif
		// 然后执行该对象的reset操作
		// 见第2小节分析【由于后续篇幅长,因此小节计数从2开始】
        p->reset();
    }

    {// 加锁代码块,执行断开native层window的连接操作
        Mutex::Autolock l(mLock);
        // 见第3小节分析
        disconnectNativeWindow_l();
    }
	
	// IPC线程执行刷新清空指令【即清空此时的Binder请求操作,
	// 因为当前Client已经执行断开连接了,不需要处理后续请求操作】
	// 不展开分析
    IPCThreadState::self()->flushCommands();
	
	// 然后在该函数结束返回时,会执行智能指针p对象的析构函数,
	// 也就如上类似分析的结论,将会减少NuPlayerDriver对象指针引用计数到0,
	// 随即delete释放其内存,然后就会执行NuPlayerDriver的析构函数
	// 见第4小节分析
}

1.2.4.3、Client对象的析构函数实现分析:

// [frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp]
MediaPlayerService::Client::~Client()
{
    ALOGV("Client(%d) destructor pid = %d", mConnId, mPid);
    // 清空该对象【实际是智能指针对象,相当于字段变量赋值为null,
    // 并且减去当前对象指针的引用计数,若减去之后为0,
    // 那么则会执行delete释放其内存,然后还会执行该实际指针对象的析构函数,这就是智能指针的clear()实现原理处理,不展开分析,可自行分析】
    mAudioOutput.clear();
    wp<Client> client(this);
    // 又调用了上面分析的方法
    disconnect();
    // 执行移除当前Client对象,mService如前面分析就是MediaPlayerService对象
    // 见下面的分析
    mService->removeClient(client);
    if (mAudioAttributes != NULL) {
    	// 释放该内存
        free(mAudioAttributes);
    }
    // 清空该对象
    mAudioDeviceUpdatedListener.clear();
}

mService->removeClient(client)实现分析:

// [frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp]
void MediaPlayerService::removeClient(const wp<Client>& client)
{
    Mutex::Autolock lock(mLock);
    // 其实就是从此前创建Client缓存的集合变量中移除当前需要被移除的Client对象
    mClients.remove(client);
}

2、p->reset()实现分析:
分析NuPlayerDriver的reset方法
由于篇幅较长,该部分放入靠后章节即MediaPlayer的reset处理流程章节进行统一分析。
请查看章节:
【XX】Android MediaPlayer整体架构源码分析 -【reset处理流程】
TODO 【后续完成后补上链接】

本章节结束,其它相关内容请查看其他章节分析。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值