基於DLNA實現iOS,Android投屏:訂閱事件通知

BrikerMan發表於2016-04-26

基於DLNA實現iOS,Android投屏:訂閱事件通知

服務執行時,可能改變有些狀態資訊變數的值,這是需要及時地更新給控制點。因此控制點可以通過訂閱操作,讓服務通過傳送事件訊息來發布更新。

事件訊息包括一個或多個狀態變數以及他們的當前數值。這些訊息也是採用 XML 格式,遵循通用事件通知體系 GENA 規定。

服務執行過程中,該服務的 服務描述檔案SDD狀態變數 <stateVariable> 發生了變化並且該變數的 <sendEvents> 屬性為 yes 時,將會產生一個事件(Event)訊息。如該狀態變數的 <multicast> 屬性為 yes ,則該服務把這個事件訊息向整個網進行多播(Multicast)。如果為 no 或者不存在這個屬性,則通過單播(Unicast)給訂閱者傳送訊息。

單播事件訊息的訂閱及推送是遵循通用事件通知結構(General Event Notification Architecture,GENA)協議。協議中,控制點通常是個訂閱者(Subscriber),它向服務提供者(通常是某個裝置上的服務)傳送訂閱訊息(SUBSCRIBE),建立訂閱關係,然後可以繼續更新訂閱訊息(Renewal),或者最後退訂訊息(Cancel)。另外,UPnP對GENA進行了一些擴充套件,如在事件訊息中增加了一個key,來表示事件的順序。

事件訂閱和通知過程如下。
UPnP事件訂閱流程

訂閱

事件訂閱說白了就是給某個服務的 訂閱 URL<eventSubURL> 傳送一條包含 回撥 URL<Callback URL>訂閱期限 <duration> 的訂閱請求。

裝置描述文件 DDD 中描述 AVTransport 服務的片段例,預設其 HOST: 192.168.1.243:46201

訂閱請求

上述服務的訂閱請求如下,其中注意點就是 回撥URL CALLBACK 必須帶有 <> 否則回撥不成功。為了接受回撥還需要手機上執行一個 HTTP Server,具體實現請看下一部分。

訂閱響應

成功響應

如果訂閱成功,則服務 30s 內返回如下的響應。其中 SID 為訂閱識別符號,必須以uuid開頭。訂閱成功後需要儲存,後續續訂和取消訂閱均需要提供該識別符號。此外還需要儲存訂閱期限 TIMEOUT: Second-3600

訂閱失敗

若訂閱失敗,釋出者必須返回一個訂閱失敗響應。格式如下:

iOS實現

用Swift實現的訂閱請求如下

續訂

如果需要續訂某個服務,則必須在訂閱期限過期前,將續訂訊息發往伺服器進行續訂。

續訂請求

取消訂閱

不需要在關注特定服務的事件時,需要向伺服器傳送取消訂閱訊息。

取消訂閱請求

單播事件訊息

當伺服器上的狀態變數發生變數時,通過單播給訂閱者傳送通知。單播通過 HTTP 協議傳送。需要在本地執行一個 HTTP Server 來接受請求。接收事件訊息成功後,只需要簡單返回一個 HTTP/1.1 200 OK 作為迴應即刻。

坑:有些裝置返回的xml中 < > 被轉義,導致解析時候出錯。所以需要先反轉義,然後再解析。
單播訊息格式如下

播放訊息

忽略頭部的停止播放訊息

停止播放訊息

忽略頭部的停止播放訊息

iOS實現

iOS實現我用到了一下開源庫

  1. GCDWebServer – 輕量 iOS/OSX GCD的伺服器框架
  2. AEXML – 輕量 XML 解析庫

建立 HTTP Server

首先需要利用 GCDWebServer 建立一個 HTTP server 接受事件訊息回撥。具體程式碼如下

建立 webServer 後,可以通過 webServer.serverURL 獲取 serverURL 。 這時把 "<\(webServer.serverURL)dlna/callback>" 作為回撥 URL 。按照前文給出程式碼進行訂閱就可以收到事件訊息了。

解析訊息

接收到通知訊息後,利用 GCDWebServer 解析 XML,獲取具體的動作。目前只對播放狀態做了處理。

相關文章