Android Wi-Fi Display(Miracast)介紹
2012年11月中旬,Google發佈了Android 4.2。雖然它和Android 4.1同屬Jelly Bean系列,但卻添加了不少新的功能。其中,在顯示部分,Android 4.2在Project Butter基礎上再接再礪,新增了對Wi-Fi Display功能的支持。由此也致使整個顯示架構發生了較大的變化。 數組
本文首先介紹Wi-Fi Display的背景知識,而後再結合代碼對Android 4.2中Wi-Fi Display的實現進行介紹。 網絡
一背景知識介紹
Wi-Fi Display常常和Miracast聯繫在一塊兒。實際上,Miracast是Wi-Fi聯盟(Wi-Fi Alliance)對支持Wi-Fi Display功能的設備的認證名稱。經過Miracast認證的設備將在最大程度內保持對Wi-Fi Display功能的支持和兼容。由此可知,Miracast考察的就是Wi-Fi Display(本文後續將再也不區分Miracast和Wi-Fi Display)。而Wi-Fi Display的核心功能就是讓設備之間經過Wi-Fi無線網絡來分享視音頻數據。以一個簡單的應用場景爲例:有了Wi-Fi Display後,手機和電視機之間能夠直接藉助Wi-Fi,而無需硬連線(如HDMI)就可將手機中的視頻投遞到TV上去顯示[①]。以目前智能設備的發展趨勢來看,Wi-Fi Display極有可能在較短期內幫助咱們真正實現多屏互動。 session
從技術角度來講,Wi-Fi Display並不是另起爐竈,而是充分利用了現有的Wi-Fi技術。圖1所示爲Wi-Fi Display中使用的其餘Wi-Fi技術項。 架構
圖1 Miracast的支撐體系結構 less
由圖1可知,Miracast依賴的Wi-Fi技術項[②]有: ide
- Wi-Fi Direct,也就是Wi-Fi P2P。它支持在沒有AP(Access Point)的狀況下,兩個Wi-Fi設備直連並通訊。
- Wi-Fi Protected Setup:用於幫助用戶自動配置Wi-Fi網絡、添加Wi-Fi設備等。
- 11n/WMM/WPA2:其中,11n就是802.11n協議,它將11a和11g提供的Wi-Fi傳輸速率從56Mbps提高到300甚至600Mbps。WMM是Wi-Fi Multimedia的縮寫,是一種針對實時視音頻數據的QoS服務。而WPA2意爲Wi-Fi Protected Acess第二版,主要用來給傳輸的數據進行加密保護。
上述的Wi-Fi技術中,絕大部分功能由硬件廠商實現。而在Android中,對Miracast來講最重要的是兩個基礎技術: 函數
- Wi-Fi Direct:該功能由Android中的WifiP2pService來管理和控制。
- Wi-Fi Multimedia:爲了支持Miracast,Android 4.2對MultiMedia系統也進行了修改。
下邊咱們對Miracast幾個重要知識點進行介紹,首先是拓撲結構和視音頻格式方面的內容。 oop
Miracast一個重要功能就是支持Wi-Fi Direct。但它也考慮了無線網絡環境中存在AP設備的狀況下,設備之間的互聯問題。讀者可參考如圖2所示的四種拓撲結構。 post
圖2 Miracast的四種拓撲結構 編碼
圖2所示內容比較簡單,此處就再也不詳述。另外,在Wi-Fi Display規範中,還存在着Source將Video和Audio內容分別傳送給不一樣Render Device的狀況。感興趣的讀者可參考Wi-Fi Display技術規範。
另外,Miracast對所支持的視音頻格式也進行了規定,如表1所示。
表1 Miracast 視音頻格式支持
分辨率 |
17種 CEA格式,分辨率從640*480到1920*1080,幀率從24到60 29種VESA格式,分辨率從800*600到1920*1200,幀率從30到60 12種手持設備格式,分辨率從640*360到960*540,幀率從30到60 |
視頻 |
H.264高清 |
音頻 |
必選:LPCM 16bits,48kHz採樣率,雙聲道 可選: LPCM 16bits,44.1kHz採樣率,雙聲道 Advanced Audio coding Dolby Advanced Codec 3 |
最後,咱們簡單介紹一下Miracast的大致工做流程。Miracast以session爲單位來管理兩個設備之間的交互的工做,主要步驟包括(按順序):
- Device Discovery:經過Wi-Fi P2P來查找附近的支持Wi-Fi P2P的設備。
- Device Selection:當設備A發現設備B後,A設備須要提示用戶。用戶可根據須要選擇是否和設備B配對。
- Connection Setup:Source和Display設備之間經過Wi-Fi P2P創建鏈接。根據Wi-Fi Direct技術規範,這個步驟包括創建一個Group Owner和一個Client。此後,這兩個設備將創建一個TCP鏈接,同時一個用於RTSP協議的端口將被建立用於後續的Session管理和控制工做。
- Capability Negotiation:在正式傳輸視音頻數據前,Source和Display設備須要交換一些Miracast參數信息,例如雙方所支持的視音頻格式等。兩者協商成功後,才能繼續後面的流程。
- Session Establishment and streaming:上一步工做完成後,Source和Display設備將創建一個Miracast Session。然後就能夠開始傳輸視音頻數據。Source端的視音頻數據將經由MPEG2TS編碼後經過RTP協議傳給Display設備。Display設備將解碼收到的數據,並最終顯示出來。
- User Input back channel setup:這是一個可選步驟。主要用於在傳輸過程當中處理用戶發起的一些控制操做。這些控制數據將經過TCP在Source和Display設備之間傳遞。
- Payload Control:傳輸過程當中,設備可根據無線信號的強弱,甚至設備的電量情況來動態調整傳輸數據和格式。可調整的內容包括壓縮率,視音頻格式,分辨率等內容。
- Session teardown:中止整個Session。
經過對上面背景知識的介紹,讀者能夠發現:
- Miracast本質就是一個基於Wi-Fi的網絡應用。這個應用包括服務端和客戶端。
- 服務端和客戶端必須支持RTP/RTSP等網絡協議和相應的編解碼技術。
二 Android 4.2 Miracast功能實現介紹
Miracast的Android實現涉及到系統的多個模塊,包括:
- MediaPlayerService及相關模塊:緣由很明顯,由於Miracast自己就牽扯到RTP/RTSP及相應的編解碼技術。
- SurfaceFlinger及相關模塊:SurfaceFlinger的做用是將各層UI數據混屏並投遞到顯示設備中去顯示。如今,SurfaceFlinger將支持多個顯示設備。而支持Miracast的遠端設備也作爲一個獨立的顯示設備存在於系統中。
- WindowManagerService及相關模塊:WindowManagerService用於管理系統中各個UI層的位置和屬性。因爲並不是全部的UI層都會經過Miracast投遞到遠端設備上。例如手機中的視頻可投遞到遠端設備上去顯示,但假如在播放過程當中,忽然彈出一個密碼輸入框(多是某個後臺應用程序發起的),則這個密碼輸入框就不能投遞到遠端設備上去顯示。因此,WindowManagerService也須要修改以適應Miracast的須要。
- DisplayManagerService及相關模塊:DisplayManagerService服務是Android 4.2新增的,用於管理系統中全部的Display設備。
因爲篇幅緣由,本文將重點關注SurfaceFlinger和DisplayManagerService以及Miracast的動態工做流程。
2.1 SurfaceFlinger對Miracast的支持
相比前面的版本,Android 4.2中SurfaceFlinger的最大變化就是增長了一個名爲DisplayDevice的抽象層。相關結構如圖3所示:
圖3 SurfaceFlinger家族類圖
由圖3可知:
- Surface系統定義了一個DisplayType的枚舉,其中有表明手機屏幕的DISPLAY_PRIMARY和表明HDMI等外接設備的DISPLAY_EXTERNAL。比較有意思的是,做爲Wi-Fi Display,它的設備類型是DISPLAY_VIRTUAL。
- 再來看SurfaceFlinger類,其內部有一個名爲mDisplays的變量,它保存了系統中當前全部的顯示設備(DisplayDevice)。另外,SurfaceFlinger經過mCurrentState和mDrawingState來控制顯示層的狀態。其中,mDrawingState用來控制當前正在繪製的顯示層的狀態,mCurrentState表示當前全部顯示層的狀態。有這兩種State顯示層的緣由是不管是Miracast仍是HDMI設備,其在系統中存在的時間是不肯定的。例如用戶能夠隨時選擇鏈接一個Miracast顯示設備。爲了避免破壞當前正在顯示的內容,這個新顯示設備的一些信息將保存到CurrentState中。等到SurfaceFlinger下次混屏前再集中處理。
- mCurrentState和mDrawingState的類型都是SurfaceFlinger的內部類State。由圖3可知,State首先經過layerSortedByZ變量保存了一個按Z軸排序的顯示層數組(在Android中,顯示層的基類是LayerBase),另外還經過displays變量保存了每一個顯示層對應的DisplayDeviceState。
- DisplayDeviceState的做用是保存對應顯示層的DisplayDevice的屬性以及一個ISurfaceTexure接口。這個接口最終將傳遞給DisplayDevice。
- DisplayDevice表明顯示設備,它有兩個重要的變量,一個是mFrameBufferSurface和mNativeWindow。mFrameBufferSurace是FrameBufferSurface類型,當顯示設備不屬於VIRTUAL類型的話,則該變量不爲空。對於Miracast來講,顯示數據是經過網絡傳遞給真正的顯示設備的,全部在Source端的SurfaceFlinger來講,就不存在FrameBuffer。故當設備爲VIRTUAL時,其對應的mFrameBufferSurface就爲空。而ANativeWindow是Android顯示系統的老員工了。該結構體在多媒體的視頻I/O、OpenGL ES等地方用得較多。而在普通的UI繪製中,ISurfaceTexture接口用得較多。不過早在Android 2.3,Google開發人員就經過函數指針將ANativeWindow的各項操做和ISurfaceTexture接口統一塊兒來。
做爲VIRTUAL的Miracast設備是如何經過DisplayDevice這一層抽象來加入到Surface系統中來的呢?下面這段代碼對理解DisplayDevice的抽象做用極爲重要。如圖4所示。
圖4 SurfaceFlinger代碼片斷
由圖4代碼可知:
- 對於非Virtual設備,DisplayDevice的FrameBufferSurface不爲空。並且SurfaceTextureClient的構造參數來自於FrameBufferSurface的getBufferQueue函數。
- 若是是Virtual設備,SurfaceTextureClient直接使用了State信息中攜帶的surface變量。
憑着上面這兩點不一樣,咱們能夠推測出如圖5所示的DisplayDevice的做用
圖5 DisplayDevice的隔離示意圖
最後再來看一下SurfaceFlinger中混屏操做的實現,代碼如圖6所示:
圖6 SurfaceFilnger的混屏操做
由圖5可知,SurfaceFlinger將遍歷系統中全部的DisplayDevice來完成各自的混屏工做。
2.2 Framework對Miracast的支持
爲了完全解決多顯示設備的問題,Android 4.2乾脆在Framework中新增了一個名爲DisplayManagerService的服務,用來統一管理系統中的顯示設備。DisplayManagerService和系統其它幾個服務都有交互。總體結構如圖7所示。
圖7 DisplayManagerService及相關類圖
由圖7可知:
- DisplayManagerService主要實現了IDisplayManager接口。這個接口的大部分函數都和Wi-Fi Display操做相關。
- 另外,DisplayManagerService和WindowManagerService交互緊密。由於WindowManagerService管理系統全部UI顯示,包括屬性,Z軸位置等等。並且,WindowManagerService是系統內部和SurfaceFlinger交互的重要通道。
- DisplayManagerService經過mDisplayAdapters來和DisplayDevice交互。每個DisplayDevice都對應有一個DisplayAdapter。
- 系統定義了四種DisplayAdapter。HeadlessDisplayAdapter和OverlayDisplayAdapter針對的都是Fake設備。其中OverlayDisplay用於幫助開發者模擬多屏幕之用。LocalDisplayAdapter表明主屏幕,而WifiDisplayAdapter表明Wi-Fi Display。
2.3 Android中Miracast動態工做流程介紹
當用戶從Settings程序中選擇開啓Miracast並找到匹配的Device後[③],系統將經過WifiDisplayController的requestConnect函數向匹配設備發起鏈接。代碼如圖8所示:
圖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的進化速度很是快,尤爲在幾個重要的功能點上。做者在此也但願國內的手機廠商或那些感興趣的移動互聯網廠商能真正投入力量作一些更有深度和價值的研發工做。
[②]其餘可選技術項還有TDLS和WMM Power Save。本文不討論這兩項內容
[③]這部份內容和WifiP2pService結合緊密,感興趣的讀者可自行研究。