原文地址:http://blog.csdn.net/goohong/article/details/8536102
ANDROID從版本4.2開始提供了一個顯示管理服務DisplayManagerService,支援多種顯示類型的多個顯示器的鏡像顯示,包括內建的顯示類型(本地)、HDMI顯示類型以及支援WIFI Display 協議( MIRACAST),實現本地裝置在遠程顯示器上的鏡像顯示。
整個架構類圖如下:
顯示管理服務通過DisplayManager提供對外介面,提供的介面包括如下幾個:
1 、public Display getDisplay(int displayId)
根據displayId參數獲得一個邏輯顯示器的資訊
2、 public Display[] getDisplays()
獲得當前所有有效邏輯顯示器列表
3、public void registerDisplayListener(DisplayListener listener, Handler handler)
登記一個顯示監聽對象,用來監聽顯示器的新增、去除或改變通知事件。
4、public void unregisterDisplayListener(DisplayListener listener)
取消先前登記的一個顯示監聽對象
5、scanWifiDisplays()
啟動WIFI顯示器的掃描。
6、 public void connectWifiDisplay(String deviceAddress)
根據裝置地址串連WIFI顯示器
7、public void disconnectWifiDisplay()
斷開WIFI顯示器
8、 public void renameWifiDisplay(String deviceAddress, String alias)
為WIFI顯示器命名
9、public void forgetWifiDisplay(String deviceAddress)
取消先前記憶的WIFI顯示器
10、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介面,用來實現HDCPData Encryption Service。
顯示系統的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的WIFI Display的實現包括JAVA部分和C++部分。JAVA部分的功能主要對應DisplayManagerService服務,DisplayManagerService服務對於WIFI Display執行個體化和登記一個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顯示裝置的串連過程和鏡像資料的打包發送和接收流程,具體流程在下一篇博文中闡述。