編輯:關於Android編程
WiFiDisplay(WFD)是WiFi聯盟在已有技術的基礎上,為了加速視/音頻的傳輸分享而提出來的一個新概念。WiFi聯盟對此成立了一個認證項目:Miracast-- 用來認證一個設備是否支持WiFiDisplay功能。
下圖是WiFiDisplay功能的技術支撐體系,實際上最重要的部分就是WiFi Direct:也就是兩個設備無需AP(AccessPoint)的情況下直接相連,這就奠定了兩個帶WiFi功能的設備能夠隨時傳遞高質/高清視頻的前提。另外,其他深藍色的技術是必須支持的:
11n:即802.11n協議,支持最高傳輸速度540Mbit/s;
WMM:即WiFi Multimedia的簡稱,主要針對不同的數據內容保證其傳輸的穩定和質量;
WPA2:是WiFi聯盟對於采用802.11i協議並采用更為復雜加密算法的認證項目;
WiFi ProtectedSteup:也是一個WiFi聯盟的一個認證項目:簡化用戶安裝無線局域網和對安全性能的配置工作;
WiFi Direct:表示設備可以實現直接互聯,無需AP的參與;
WiFi Miracast:即為是否可以實現wifi-display功能的認證項目。
圖 1 WiFiDisplay技術支撐架構
另外,WiFi聯盟還描述了WiFiDisplay的簡化工作模型(圖2)。在這個工作模型中,Miracast定義傳輸視/音頻數據的一方為source端;接受數據並重新呈現的為sink端。從圖中可以看到,source端要有數據內容的存儲和下載/生成能力;對數據進行編碼能力。而sink端則需要對數據的解碼能力;對視/音頻進行再度呈現的能力。而Miracast則是定義了這兩個設備之間,怎樣保持會話;可以傳輸數據的格式標准;會話控制等內容。
圖 2 WiFiDisplay的工作模型
3 Miracast支持的顯示、視頻、音頻格式標准
同時,Miracast也規范了設備連接後進行協商(圖4)、建立會話的流程(圖5)。詳細描述了設備在建立物理連接後,通過標准步驟來完成WiFi Display的會話建立,然後開始數據傳輸。關於各個標准步驟的詳細信息,請見Miracast官方解釋。
4 Miracast定義的設備協商標准過程
圖5 Miracast定義的顯示會話建立過程標准
由於WFD功能主要涉及wifiP2P功能和display功能,現對Android中涉及的兩個模塊wifiP2pService和SurfaceFlinger做一些介紹。
WiFiP2P是WiFi聯盟提出的一項重要技術規范,它定義了兩個wifi設備如何在沒有路由的情形下連接並通信。根據定義,支持WiFiP2P的設備需要扮演P2P GroupOwner或P2P Client角色來形成一個P2P Group:
圖6 WiFiP2P工作組模型
其中P2P Group Owner的設備需要發揮傳統路由的功能:控制WiFiP2P工作組,使能設備通信等;P2PClient設備則需要連接上P2P Group Owner設備來形成一個工作組來通信。
在以上的工作模型基礎上,WiFiP2P細化了以下技術項:
圖7 WiFiP2P定義的P2PDiscovery規范
在P2P Discovery規范中,定義了發現設備(Device Discovery )並構建工作組(GroupFormation )的細節。其中發現設備規定設備首先進入掃描階段(ScanPhase),去發送Probe Request幀;然後進入尋找階段(Find Phase),在這個階段中設備會在SearchState和Listen State中切換:兩個階段分別是發送Probe Request幀、監聽ProbeRequest幀並發送Probe Response幀。當找到附近的P2P設備後,就可以來構建一個工作組:包括決定誰是Group Owner的協商(GONegotiation )和設備交換安全配置信息(Provisioning),用於Client設備利用安全配置信息連接GO。
另外,WiFiP2P還定義了GroupOperation技術項,具體描述了和工作組交互的場景和流程:
·P2P Device Join GO(Group Owner)
·P2P Device Join GC(Group Client)
·GC invite P2P Device
·GO invite P2P Device
… …
Android中關於WiFiP2P模塊主要涉及以下幾個部分:
圖8 Android中WiFiP2P涉及模塊
WiFiP2PSettings 是用來和用戶交互的部分,主要是提供UI給用戶選擇打開/開閉WiFiP2P功能、呈現搜尋到的P2P設備給用戶等;WiFiP2PSettings實現的功能調用的是WiFiP2PManager中的接口;WiFiP2PManager最終會與WiFiP2PService交互,它們依靠Android的Binder機制來實現進程間的通信,WiFiP2PService則是用來管理Android中WiFiP2P功能的核心模塊:
圖9 Android中WiFiP2P涉及模塊
在WiFiP2PService類中有一個內部類P2pStateMachine(狀態機)用來管理WiFiP2P的不同狀態然後執行不同的操作;另外WiFiP2PService還會創建一個WifiMonitor對象用於接收來自wpa_supplicant的消息並根據接收到的消息給P2pStateMachine傳值來推動狀態機的工作。從圖中可以看到,WiFiP2PService或WifiMonitor交互的是WiFiNative.Java中的接口,這裡面的都是一些native函數;這是因為wap_supplicant進程是C語言實現,Android是通過JNI機制調用android_net_wifi_Wifi.cpp 裡面的本地接口,這些本地接口來最終和wpa_supplicant交互(wifi.c裡面是對發送到wpa_supplicant裡面消息的封裝)。
wpa_supplicant是一個開源項目,實現了WiFi聯盟規范中的眾多功能,詳見官方文檔。下圖是wpa_supplicant及與下層部件的一個草圖:
圖10 wpa_supplicant及底層部件草圖
2.2 SurfaceFlinger
總所周知,SurfaceFlinger是Android中對圖形畫面進行管理並交由FrameBuffer實際顯示的重要模塊,它需要收集系統中所有應用程序繪制的圖像數據,然後集中處理後顯示到物理屏幕上。下圖是Android下圖形顯示的一個簡略框圖:
圖11 Android顯示系統簡略框圖
上圖描述的是使用OpenGL ES圖形開發規范下的情況。首先,每個應用程序在自己的窗口上進行繪圖,這裡的窗口(Window-2)實際上對應的是一些緩沖區;然後SurfaceFlinger則會對這些緩沖區進行統一管理;最後每一幀的圖形數據會被送到FrameBuffer上並實際顯示在設備上。
對於上層應用來說,Window-2在Android中的實現為SurfaceTextureClient類。由於是在OpenGL ES的開發框架下,SurfaceTextureClient實際上是繼承自ANativeWindow同時在本地實現了一些接口(參見EGL知識):
圖12 上層應用的window實現
hook_dequeueBuffer()和hook_queueBuffer()是框架定義中需要實現的本地函數,上層應用作圖時需要從緩沖隊列得到緩沖區;作圖完成後需要把緩沖區送還給緩沖隊列。具體情形如下:
圖13 本地窗口和緩沖隊列交互圖
如上圖,本地窗口實際上是從BufferQueue來得到緩沖區;畫圖後再將緩沖區入列到緩沖隊列。而BufferQueue是在應用程序創建Surface(在SurfaceFlinger端對應Layer)的時候生成的,本地窗口通過返回的ISurface對象得到ISurfaceTexture對象來最終和BufferQueue交互。
對於SurfaceFlinger側的本地窗口Window-1(圖11)來說,SurfaceTextureClient也是作為本地窗口的功能。不過在SurfaceFlinger端通過標准的OpenGL ES接口進行請求緩沖區操作和入列緩沖區操作的對象就不一樣了;而且在入列緩沖區後所進行的操作也不一樣:
圖14 SurfaceFlinger的本地窗口
如上圖,在SurfaceFlinger端的本地窗口Window-1,會有自己的BufferQueue對象,而最終和HAL層的Gralloc模塊交互實際分配緩沖區的時候,會根據功用不同來分配不同類型的緩沖區:上層應用分配的緩沖區是給OpenGL繪圖用的;SurfaceFlinger這邊分配的緩沖區是要送顯FrameBuffer的(詳見gralloc.h中定義)。
對於上層應用來說,填充好緩沖區後處理端(consumer&producter模型)會調用到Layer文件的onFrameQueued()函數,如果需要渲染圖形這時候需要等待一個VSYNC信號(詳見Android的Project Butter),收到VSYNC信號後會對需要渲染的Buffer按照Z軸計算可見區域並進行圖像混合;而對於SurfaceFlinger端來說,緩沖區入列後consumer會最終調用fb的HAL層接口完成實際顯示。
Android自從4.2後就支持WiFiDisplay功能了。以下是Miracast官方公布的WFD工作模塊框圖:
圖15WiFiDisplay的工作模塊框圖
在以上工作模型的基礎上,Android主要做了以下工作:
·新加了WiFiDisplay的setting部分,用來為用戶提供操作選項;
·新加DisplayDevice類用來描述不同的顯示設備,WiFiDisplay作為一個虛擬顯示設備;
·修改了SurfaceFlinger模塊來支持WiFiDisplay,通過SF把顯示內容投放到不同的設備上;
·新加了DisplayManagerService來對系統的顯示設備進行統一管理
·根據Miracast規定的會話建立管理流程,實現了source端和sink端的程序
3.1 應用程序端
對於WiFiDisplay功能,Android提供了相應接口給應用程序使用,以實現在第二顯示設備上進行顯示。具體內容參考官方描述,其中關鍵步驟見圖16:
圖16Android上WFD應用編程簡要步驟
可以看到主要包括Presentation和MediaRouter兩個class。實際上它們都會調用一個重要的class提供的功能 – DisplayManager,而DisplayManager接口的具體實現在另外一個進程中的DisplayManagerService.java文件中。
DisplayManagerService是Android中管理WiFiDisplay功能的核心服務:
圖17 DisplayManagerService簡圖
每一種顯示設備(LocalDisplayDevice、WiFiDisplayDevice)都有一個對應的DisplayAdapter,DisplayManagerService通過管理這些Adapter來管理不同的顯示設備。比如DisplayManager發起的對WiFiDisplay的操作請求,都會由DisplayManagerService轉給WifiDisplayAdapter來實際完成。另外DisplayManagerService服務還通過WindowManagerFuncs窗口管理功能接口直接調用WindowManagerService的函數,實現窗口內容的刷新;同樣DisplayManagerService服務還通過InputManagerFuncs接口直接調用InputManagerService的函數,用來設置輸入系統需要的顯示器的顯示視圖信息。
而WifiDisplayAdapter的操作最終會實現在WifiDisplayController中,去實現設備掃描、設備連接等操作:
圖18 WifiDisplayController簡圖
關於和其他設備的WiFiDirect連接,Android有專門的一個WifiP2pService來管理,這裡對於設備的連接就是直接調用WifiP2pManager(和WifiP2pService交互)所提供的接口來完成。
3.3 Source/Sink設備會話管理端
在設備建立WiFi連接後,會在RemoteDisplay上監聽RTSP的連接,用於後續創建session和傳輸實時流數據。
圖19 監聽RTSP連接流程簡圖
如上圖,實際的監聽最終流程會走到RemoteDisplay中,即一個RemoteDisplay對象的創建。通過創建這個本地的RemoteDisplay對象將會創建一個ANetworkSession對象,用於管理網絡部分的操作;創建一個ALooper對象,實現各類消息的派發和處理;創建一個WifiDisplaySource對象(由於搭載Android系統的大多數設備在WiFiDisplay場景中,多數會扮演source端的角色,因此這裡創建的是WifiDisplaySource對象),具體處理各類消息:
圖20 RemoteDisplay簡圖
另外,Source目錄還包括PlaybackSession.cpp、MediaPuller.cpp、Converter.cpp、TSPacketizer.cpp、Sender.cpp等C++類文件和相應的頭文件,分別負責Source端的會話過程管理、鏡像媒體讀取、編碼、TS打包及RTP打包發送等過程。Converter 對象中包括一個MediaCodec對象具體負責編碼過程,MediaCodec對象實際通過ACodec對象調用IOMX接口使用OPENOMX媒體框架完成鏡像數據的編碼。
3.4 視/音頻數據獲取方式
圖21 source端的媒體數據獲取簡圖
如圖,source設備端程序對要在遠端設備進行呈現的視/音頻數據通過MediaSource類進行管理。上圖中的SurfaceMediaSource和AudioSource都是繼承自MediaSource類,它們分別對應視頻數據和音頻數據,根據不同的情景,source設備端程序可以添加視頻或者音頻數據源到當前程序中來,而且每一個MediaSource會對應創建一個Converter對象和一個MediaPuller對象,用於媒體數據的編碼和數據讀取等操作。下圖是獲取視頻數據的程序片段,調用MediaSource的通用接口read來實現。
圖22 獲取視頻數據程序片段
3.4.1 視頻數據源
由圖22可知,視頻數據是從一個BufferQueue中讀取的。上層應用正是將需要顯示的視頻數據放到和這個BufferQueue對應的Surface中,實現視頻數據的遠端設備投遞。
圖23 SurfaceFlinger管理不同顯示設備簡圖
較詳細來說,上文中的surface是由WiFiDisplayDevice所持有的,這部分內容還和SurfaceFlinger為支持畫面投遞到不同的設備上而進行的改動有關。如圖23,主要是抽象了DisplayDevice來表述本地顯示設備和WiFiDisplay等顯示設備,在SurfaceFlinger.cpp的handleTransactionLocked函數中可以看到:
圖24SurfaceFlinge對不同顯示設備處理代碼片段
對於virtualDisplay的話(WiFiDisplay設備),mFramebufferSurface為空;SurfaceTextureClient直接使用了State信息中攜帶的surface變量。這個Surface正是當RTSP建立後,在回調函數onDisplayConnected中注冊到SufaceFlinger中的(3.3節描述監聽連接),這樣SurfaceFlinger會將上層應用的顯示數據投遞到這個Surface上面,而source端的程序則會從這個surface上取出數據。
3.4.2 音頻數據源
由圖21可以看到,音頻數據的獲取是通過AudioRecod來得到。Android系統對於Audio系統抽象了AudioTrack對象和AudioRecord對象來分別用於音頻數據的輸出和音頻數據的采集/獲取。對於WiFiDisplay情景下的音頻數據處理,Android也是在不破壞原有架構的情況進行的:
圖25 WFD情景下音頻簡單架構圖
AudioRecord通過AudioSystem對象來獲得AudioFlinger和AudioPolicyService的遠端接口進行操作,最終和HAL層的module交互,實際上完成的是從一個管道中的讀取操作;而AndroidTrack也是基於同樣的模型,只不過流程相反,完成的是向HAL層的一個對應管道中的寫操作。其中AudioPolicyService在Android關於Audio的各個組件中扮演著核心角色:
圖26 AudioPolicyService核心與其他組件交互圖
如上圖,詳細來說:AudioPolicyService直接交互的是一個稱為‘POLICY’的HAL層模塊,這個模塊提供了通用接口;然後通用接口會調用到一個具體的策略管理類中提供的接口,對應上圖的AudioPolicyManagerALSA;最終,會根據不同的調用參數來獲取真正的HAL層模塊,和硬件交互,而AudioFlinger得到具體的HAL層模塊後,就可以直接對其操作了。
這些具體的HAL模塊,ID名稱都為AUDIO_HARDWARE_MODULE_ID ,只是被編譯成了不同名稱的庫文件,而對應於WiFiDisplay的HAL層模塊不需要和具體的硬件打交道,實際實現為一個管道:
圖27 WiFiDisplay的HAL模塊程序片段
因此,對於需要通過WiFiDisplay到遠端設備進行呈現的音頻數據,只需要使用AudioTrack的接口來把音頻數據放到上文HAL模塊中的管道;而WiFiDisplay的source程序端也只需要調用AudioRecord的接口取出數據即可。最發送前的編碼,音頻/視頻打包則專門去處理,不破壞原有的系統架構。
WiFiDisplay技術實現視/音頻數據的無線遠端呈現,目前涉及視/音頻數據處理的設備較多,常用的應用場景有:
1、數字播放器和數字電視工作場景:在這個應用場景下,由於source端設備不具有用戶交互屏幕,因此sink端設備需要和用戶交互完成設備的配對、傳輸的控制等工作;
圖28 WFD應用場景1
2、下圖描述的是一個數字機頂盒和DTV加上一個AP的工作模型,source設備在這個模型中同時連接到AP和sink設備,source端的數據此時是從網絡獲取的。這在WiFiDirect模型中是允許的,對於P2P連接在底層實際上對應的一個虛擬地址。
圖28 WFD應用場景2
3、下圖是描述的是有兩個sink端設備的應用場景,此時source設備需要發現和連接兩個sink設備,並發送視頻/音頻數據到不同的sink設備上。同時兩個sink設備也需要彼此通信,來做同步和其他信息交換。
圖28 WFD應用場景3
WiFiDisplay的應用產品,市場上已經有一些,比如百度推出的百度影音棒、小米盒子等。其中百度影音棒的工作情況如下:(官方說明)
圖29 百度影音棒2S工作簡圖
百度開發出的百度影音棒系列,實際上一種充分考慮現實情況的一套無線視頻播放方案。由上圖可知,考慮到現有電視的實際情形(大多數只帶HDMI功能),這套方案對於TV還是使用HDMI和BaiDu 2S有線連接,而真正的無線模塊則是這裡的BaiDu 2S。這裡的source設備即為手機,sink端設備其實就是BaiDu 2S。
小米盒子和上圖的工作模型基本一致,不過根據官方說明支持音樂遠端播放以及AirPlay協議和DLNA協議(官方說明)。
DLNA(Digital Living Network Alliance)是由Sony、Intel、Microsoft等發起成立的一個認證組織,其目的也是實現消費電子產品通過有線/無線網絡實現設備互聯、數據互通。相比於Miracast認證項目,DLNA有著自己的一套框架和相應標准:首先DLNA將市場上幾乎所有的電子產品進行了分類(圖30),一方面可以便於DLNA對眾多的設備進行規范認證,另一方面也是DLNA為不同設備間進行交互制定標准的基礎。
圖30 DLNA定義的設備類別和類型
其次DLNA定義了設備工作架構(圖31),其中UpnP是實現設備設備發現、連接、控制的重要協議層(參考文章),而媒體數據的傳輸則是使用HTTP傳輸協議或者是RTP協議。
圖31 DLNA系統架構圖
AirPlay是蘋果公司實現的在蘋果產品或是其認證產品之間傳輸媒體信息的一套解決方案。AirPlay技術可以實現產品之間自動地互相發現,並且輕松地互相傳輸音樂、圖片及視頻文件。
AirPlay以組播DNS(Multicast DomainName Server—mDNS)協議和DNS服務發現(DNS Service Discovery,簡稱DNS-SD)協議為基礎,它們是IETFn Zeroconf工作組提出的用於自動尋找設備及服務的網絡協議,蘋果公司以這兩個協議為基礎,實現了蘋果公司數字家庭網絡框架。
AirPlay協議消息發送格式及規則基於mDNS協議,mDNS協議基於組播技術,定義了家庭各個設備之間的消息的基本格式和接收/發送規則。該協議以DNS協議為基礎,並對其消息格式和消息收發順序作出了一些修改。例如對DNS消息包頭進行了簡化,使其專注於實現家庭設備的互相發現;另外,考慮到使用組播技術,mDNS在降低網絡擁塞和消息冗余方面也作出了很多改進,使得局域網內設備和服務的發現不會引起過多的消息交互。
在mDNS協議的基礎上,DNS-SD協議規定了一個服務宣告及使用的完整過程。即設備必須發送什麼樣的mDNS消息才能完整地宣告並描述自己服務。DNS-SD協議使用PTR、SRV和TXT三種類型的記錄全面描述了一個服務的類型,名稱以及所在主機的IP和端口號等。
當使用DNS-SD協議實現了對設備及服務的發現和描述後,蘋果公司的AirPlay協議規定了圖片、音頻及視頻的傳輸和控制消息格式,從而實現了智能設備之間的媒體共享和協同動作。在通過DNS-SD獲得了其他設備及服務的信息(即設備或服務的IP地址及端口號)之後,AirPlay使用HTTP消息實現了圖片和視頻的傳輸及控制,使用RSTP協議實現了音頻的傳輸和控制
AirPlay工作模型和WiFiDisplay技術和DLNA技術基本一致,只不過它是蘋果公司的私有方案,因此沒有公開的規范資料(非官方協議協議標准)。
ScaleType表示ImageView的縮放類型,決定了一張圖片在ImageView控件內如何縮放和顯示。ScaleType的官方文檔:https://develope
優點:擺脫原始的Crash界面處理缺點:無法自定義界面實現自定義Ui介紹:“Recovery”幫助你自動處理程序在運行時的Crash,它含有以下幾
前面的文章已經實現相關的布局,本文接著進行相關的功能實現讀取系統聯系人當點擊“選擇聯系人”按鈕後,彈出聯系人列表,讀取系統聯系人分如下幾個步驟:系統聯系人提供了一個內容提
本文實例講述了Android中Service用法。分享給大家供大家參考,具體如下:關於Service的講解網上已經很多了,這裡是關於自己通過寫代碼Service的一點體會