图8 requestConnect函数实现
图8中,最终将调用connect函数去连接指定的设备。connect函数比较中,其中最重要的是updateConnection函数,我们抽取其中部分代码来看,如图9所示:
图9 updateConnection函数片段
在图8所示的代码中,系统创建了一个RemoteDisplay,并在这个Display上监听(listen)。从注释中可知,该RemoteDisplay就是和远端Device交互的RTP/RTSP通道。而且,一旦有远端Device连接上,还会通过onDisplayConnected返回一个Surface对象。
根据前面对SurfaceFlinger的介绍,读者可以猜测出Miracast的重头好戏就在RemoteDisplay以及它返回的这个Surface上了。
确实如此,RemoteDisplay将调用MediaPlayerService的listenForRemoteDisplay函数,最终会得到一个Native的RemoteDisplay对象。相关类图如图10所示。
图10 RemoteDisplay类图
由图10可知,RemoteDisplay有三个重要成员变量:
- mLooper,指向一个ALooper对象。这表明RemoteDisplay是一个基于消息派发和处理的系统。
- mNetSession指向一个ANetWorkSession对象。从它的API来看,ANetworkSession提供大部分的网络操作。
- mSource指向一个WifiDisplaySource对象。它从AHandler派生,故它就是mLooper中消息的处理者。注意,图中的M1、M3、M5等都是Wi-Fi Display技术规范中指定的消息名。
RemoteDisplay构造函数中,WifiDisplaySource的start函数将被调用。如此,一个类型为kWhatStart的消息被加到消息队列中。该消息最终被WifiDisplaySource处理,结果是一个RTSPServer被创建。代码如图11所示:
图11 kWhatStart消息的处理结果
以后,客户端发送的数据都将通过类型为kWhatRTSPNotify的消息加入到系统中来。而这个消息的处理核心在onReceiveClientData函数中,它囊括了设备之间网络交互的所有细节。其核心代码如图12所示:
图12 onReceiveClientData核心代码示意
图12的内容较多,建议读者根据需要自行研究。
根据前面的背景知识介绍,设备之间的交互将由Session来管理。在代码中,Session的概念由WifiSource的内部类PlaybackSession来表示。先来看和其相关的类图结构,如图13所示:
图13 PlaybackSession及相关类图
由图13可知:
- PlaybackSession及其内部类Track都从AHandler派生。故它们的工作也依赖于消息循环和处理。Track代表视频流或音频流。
- Track内部通过mMediaPull变量指向一个MediaPull对象。而MediaPull对象则保存了一个MediaSource对象。在PlaybackSession中,此MediaSource的真正类型为SurfaceMediaSource。它表明该Media的源来自Surface。
- BufferQueue从ISurfaceTexure中派生,根据前面对SurfaceFlinger的介绍,它就是SurfaceFlinger代码示例中代表虚拟设备的State的surface变量。
当双方设备准备就绪后,MediaPull会通过kWhatPull消息处理不断调用MediaSource的read函数。在SurfaceMediaSource实现的read函数中,来自SurfaceFlinger的混屏后的数据经由BufferQueue传递到MediaPull中。代码如图14所示:
图14 MediaPull和SurfaceMediaSource的代码示意
从图13可知:
- 左图中,MediaPull通过kWhatPull消息不断调用MediaSource的read函数。
- 右图中,SurfaceMediaSource的read函数由通过mBufferQueue来读取数据。
那么mBufferQueue的数据来自什么地方呢?对,正是来自图4的SurfaceFlinger。
当然,PlaybackSession拿到这些数据后还需要做编码,然后才能发送给远端设备。由于篇幅关系,本文就不再讨论这些问题了。
三总结
本文对Miracast的背景知识以及Android系统中Miracast的实现进行了一番简单介绍。从笔者个人角度来看,有以下几个点值得感兴趣的读者注意:
- 一定要结合Wi-Fi的相关协议去理解Miracast。重点关注的协议包括Wi-Fi P2p和WMM。
- Android Miracast的实现中,需要重点理解SurfaceFlinger和RemoteDisplay模块。这部分的实现不仅代码量大,而且类之间,以及线程之间关系复杂。
- 其他需要注意的点就是DisplayManagerService及相关模块。这部分内容在SDK中有相关API。应用开发者应关注这些新API是否能帮助自己开发出更有新意的应用程序。
另外,Android的进化速度非常快,尤其在几个重要的功能点上。作者在此也希望国内的手机厂商或那些感兴趣的移动互联网厂商能真正投入力量做一些更有深度和价值的研发工作。