ANDROID從版本4.2開始提供了一個顯示管理服務DisplayManagerService,支持多種顯示類型的多個顯示器的鏡像顯示,包括內建的顯示類型(本地)、HDMI顯示類型以及支持WIFI Display 協議( MIRACAST),實現本地設備在遠程顯示器上的鏡像顯示。網絡
整個架構類圖以下:架構
顯示管理服務經過DisplayManager提供對外接口,提供的接口包括以下幾個:框架
1 、public Display getDisplay(int displayId)異步
根據displayId參數得到一個邏輯顯示器的信息ide
二、 public Display[] getDisplays()函數
得到當前全部有效的邏輯顯示器列表測試
三、public void registerDisplayListener(DisplayListener listener, Handler handler)編碼
登記一個顯示監聽對象,用來監聽顯示器的新增、去除或改變通知事件。加密
四、public void unregisterDisplayListener(DisplayListener listener)spa
取消先前登記的一個顯示監聽對象
五、scanWifiDisplays()
啓動WIFI顯示器的掃描。
六、 public void connectWifiDisplay(String deviceAddress)
根據設備地址鏈接WIFI顯示器
七、public void disconnectWifiDisplay()
斷開WIFI顯示器
八、 public void renameWifiDisplay(String deviceAddress, String alias)
爲WIFI顯示器命名
九、public void forgetWifiDisplay(String deviceAddress)
取消先前記憶的WIFI顯示器
十、public WifiDisplayStatus getWifiDisplayStatus()
獲得當前的WIFI顯示器的狀態
顯示管理系統還與其它系統交互,實現WIFI顯示器的發現、WIFI顯示器在窗口系統中的登記、窗口內容在WIFI顯示器的顯示(源端鏡像數據的獲取、加密、編碼,SINK端接收的鏡像數據的解碼和播放等)等功能。
經過WifiP2pManager接口與WifiP2pService交互,經過WIFI-DIRECT來實現WIFI顯示器的自動發現。
窗口管理服務是顯示管理服務的監聽對象,窗口管理服務經過DisplayManager接口向DisplayManagerService進行登記,當WIFI顯示器被發現和鏈接成功後以及WIFI顯示器斷開和狀態改變後,都會經過回調向窗口管理服務發送事件,窗口管理服務的相應回調函數onDisplayAdded、onDisplayChanged、onDisplayRemoved被調用,用來在窗口系統中進行WIFI顯示器的登記以及取消登記、狀態改變等處理。
另外DisplayManagerService服務還經過WindowManagerFuncs窗口管理功能接口直接調用窗口管理服務(WindowManagerService是該接口的實現)的函數,實現窗口內容的刷新。一樣DisplayManagerService服務還經過InputManagerFuncs接口直接調用輸入管理服務的函數setDisplayViewports,用來設置輸入系統須要的顯示器的顯示視圖信息。
顯示管理系統還經過IMediaPlayerService接口與MediaPlayerService服務交互。
如調用MediaPlayerService服務的listenForRemoteDisplay函數,用來在媒體服務中實例化一個遠端顯示器的本地代理對象RemoteDisplay,顯示系統經過IRemoteDisplay接口調用媒體服務,目前IRemoteDisplay接口只有dispose一個接口函數,用來斷開遠端顯示器,中止監聽新的鏈接。
顯示管理系統的WifiDisplaySource對象還調用MediaPlayerService服務的makeHDCP函數來實例化一個HDCP對象並返回給顯示系統一個IHDCP接口,用來實現HDCP加密服務。
顯示系統的SINK端的TunnelRenderer對象在其initPlayer中還調用MediaPlayerService服務的create函數來建立一個MediaPlayer對象,並返回一個IMediaPlayer接口給顯示系統使用,用來實現SINK端接收的鏡像數據的播放。
顯示管理系統源端獲取的鏡像數據通過音視頻編碼(H264),而後進行HDCP加密和PES packetization及TS流化(轉換爲TS流)後 ,最後打包成RTP包通過UDP通道發送到SINK端,SINK端要通過相反的處理過程,從UDP通道接收RTP包,而後進行TS解析和PES去packetization化和HDCP解密,最後送給解碼器進行解碼。解碼後的數據送給播放器的呈現器進行呈現。
源端和SINK端的音視頻編解碼都經過IOMX接口與底層的多媒體框架交互,實現音視頻編解碼功能。IOMX接口對應的對象OMX也是在MediaPlayerService服務端實例化的,在客戶端對象OMXClient的connect函數中經過調用MediaPlayerService服務的getOMX函數返回OMX對應的IOMX接口。OMX對象是對多媒體框架OPENOMX的封裝。
源端的音視頻編碼、TS流化、HDCP加密、RTP打包發送的流程都有PlaybackSession線程類管理和調度,PlaybackSession類初始化時實例化一個SurfaceMediaSource對象,SurfaceMediaSource對象內部實例化一個BufferQueue對象(BufferQueue從ISurfaceTexure中派生)。在與SINK端創建鏈接後,經過IRemoteDisplayClient接口的回調函數onDisplayConnected把BufferQueue對象傳給JAVA層,JAVA層的WifiDisplayAdapter對象收到onDisplayConnected事件後調用Surface類的createDisplay函數在SurfaceFlinger服務中登記一個虛擬顯示器,並調用Surface類的setDisplaySurface函數把BufferQueue傳給SurfaceFlinger服務虛擬顯示器對應的DisplayDeviceState變量中.。所以PlaybackSession可使用BufferQueue對象從SurfaceFlinger服務讀取要鏡像的數據。
SINK端WifiDisplaySink對象接收的數據經RTP解碼(由RTPSink對象負責)後,送給TunnelRenderer對象進進行呈現, TunnelRenderer對象在initPlayer函數中實例化一個PlayerClient播放客戶端,並經過IMediaPlayerService接口調用MediaPlayerService服務的create函數建立一個MediaPlayer對象並返回TunnelRenderer對象IMediaPlayer接口, TunnelRenderer對象使用IMediaPlayer接口對接收到的鏡像數據進行播放和呈現, TunnelRenderer對象還在initPlayer函數中經過SurfaceComposerClient對象實例化和得到一個Surface對象,並調用其getSurfaceTexture函數得到Surface對象對應的ISurfaceTexture,並調用IMediaPlayer接口的setVideoSurfaceTexture函數把ISurfaceTexture賦值給播放器,從而實現播放器解碼後的顯示數據送給SurfaceFlinger顯示服務進行顯示.
SINK端的WifiDisplaySink對象和源端WifiDisplaySource的對象負責WIFI Display 交互協議的處理,兩個對象都包含一個ANetworkSession對象負責二者之間的網絡交互會話過程。
以下是WIFI Display 協議的框架圖。
ANDROID4.2的開源代碼提供了WIFI Display 協議的具體實現,但對SINK端只是做爲一個本地測試命令來執行,而且沒有提供圖中的用戶輸入功能,而對於WFD Source端則提供了完整的實現代碼,這主要是ANDROID系統主要是做爲手機平板操做系統使用的緣故。
ANDROID4.2的WIFIDisplay的實現包括JAVA部分和C++部分。JAVA部分的功能主要對應DisplayManagerService服務,DisplayManagerService服務對於WIFIDisplay實例化和登記一個WifiDisplayAdapter對象(派生自DisplayAdapter),用來與對應的顯示設備創建鏈接,每一個DisplayAdapter與一個顯示設備DisplayDevice類一一對應 。每一個顯示設備在DisplayManagerService服務中 對應一個LogicalDisplay對象。
DisplayManager發起的對WIFI Display的請求都由DisplayManagerService服務轉發給WifiDisplayAdapter對象處理,爲了實現異步交互和避免死鎖,WifiDisplayAdapter對象對於每一個請求都啓動一個線程來實際完成請求處理,並實例化一個WifiDisplayController對象來封裝這些請求的調用。WifiDisplayAdapter對象內部也實例化一個WifiDisplayController.Listener對象用來監聽請求的狀態。 WifiDisplayController對象內部實例化一個WifiP2pManager對象用來經過其接口向WifiP2pService服務發起WI-FI DIRECT請求。在與WIFI Display鏈接時經過實例化一個RemoteDisplay 對象來啓動監聽底層WIFI Display的鏈接事件。
C++ 部分位於媒體框架層,處於libstagefright目錄的wifi-display目錄下,wifi-display目錄包含兩個sink和source兩個子目錄(分別對應wifi display的sink和source 對應的程序),wifi-display目錄還包含source和SINK公用的程序。
主要包含以下文件:
Sink目錄主要包含WifiDisplaySink.cpp、RTPSink.cpp、TunnelRenderer.cpp等C++類文件和相應的頭文件,分別負責SINK端的協議協議,RTP接收和鏡像數據的呈現過程。而TS解析和PES去packetization化及解碼過程都有播放器NuPlayer完成,因爲Sink端只是一個測試例程,所以暫沒有提供HDCP解碼流程。
Source目錄主要包括WifiDisplaySource.cpp、PlaybackSession.cpp、MediaPuller.cpp、Converter.cpp、TSPacketizer.cpp、Sender.cpp等C++類文件和相應的頭文件,分別負責Source端的協議交互,會話過程管理、鏡像媒體讀取、編碼、TS打包及RTP打包發送等過程。Converter 對象中包括一個MediaCodec對象具體負責編碼過程,MediaCodec對象實際經過ACodec對象調用IOMX接口使用OPENOMX媒體框架完成鏡像數據的編碼。
sink和source使用的公共類文件主要是ANetworkSession.cpp和對應頭文件以及一個 啓動WifiDisplaySink的主程序wfd.cpp,用來 生成命令wfd。
整個協議主要的流程包括WIFI Display顯示設備的鏈接過程和鏡像數據的打包發送和接收流程,具體流程在下一篇博文中闡述。
版權全部,轉載時請顯要處註明連接,謝謝!