一文帶你深度解析騰訊雲直播答題方案

歡迎你們前往雲+社區,獲取更多騰訊海量技術實踐乾貨哦~web

做者:騰訊視頻雲json

進入2018年最火的新鮮事物無疑就是「直播答題」了,動輒上百萬的獎金更是吸引了大量用戶的參與。一場直播動輒幾百萬的獎金,每人能夠分到幾十元甚至百萬元,愈來愈多的人但願用本身的智商賺點零花錢。直播答題有多火?小程序

多個直播平臺服務器屢次遭到宕機。實際上,幾百萬人一同在線的確會帶給服務器不小的壓力,更況且是新上線的 App,他們或許尚未想到本身會火得這麼快。微信小程序

近期不少直播答題app出現了我的帳號上顯示獎金額數不對、在線用戶沒法進入遊戲、技術故障致使遊戲被迫臨時取消等狀況。某視頻平臺還出現了系統將正確答案斷定錯誤的狀況,致使百萬人被迫停止遊戲。隔幾天就來一次的數組

技術故障除了說明App準備不足外,也從側面反映了這類遊戲的火爆程度。爲了讓衆多公司及開發者儘快遇上風口浪尖,騰訊雲直播團隊也是第一時間上線了「在線知識競技解決方案」。緩存

效果體驗

iOS平臺(ipa)       Android平臺(apk)            Obs Studio 定製版本(exe)安全

iOS                          Android                            Obs Studio服務器

在線答題室

建立房間便可體驗主持人一端的效果;進入房間便可體驗觀衆端的效果。微信

iPhone 平臺的 Demo 採用了企業簽名方式,請先到「設置-通用-設備管理」裏,添加信任證書。websocket

Demo 僅做演示之用,用來展現騰訊雲的技術能力,不表明最終產品形態,接入請仔細閱讀文檔。

 

體驗方式二:Obs Studio

這種體驗方式是直接使用騰訊雲改造的 Obs Studio 進行推流:

  • 咱們在「工具」菜單欄裏面加了一個「題目分發」按鈕,能夠直接將題目打入直播流中,題目能夠預先編輯在 ini 文件中。
  • 使用 iOS 或者 Android 端的演示App,選擇 答題播放器 功能,就能夠體驗觀衆端題目收取的效果了。
  • OBS Studio 的使用方法,詳見 騰訊雲定製版 Obs Studio 說明書

SDK下載

下載地址

咱們的優點

  • 精準的「音題畫」同步 騰訊雲 SDK 和雲端均支持在直播流中插入 題目 或 時間同步信令,能夠實現聲音、畫面和題目彈出的完美同步。
  • 超低的觀衆端延遲差 騰訊雲 SDK 的 極速播放模式 所支持的延遲修正技術,可讓觀衆與觀衆之間延遲差在 1s 之內,從而讓觀衆的答題同步性獲得保證。
  • 支持微信小程序接入 騰訊雲 SDK 已經默認打包在微信版本中,並以 <live-player> 標籤的形式對外提供,設置 mode 爲 live 模式,並將 min-cache 和 max-cache 都設置爲 1,便可實現很是低延遲的播放效果。

方案解讀

方案一:題目透傳方案

原理描述

  • 消息發送(Obs): 若是你是在演播室使用 Obs 推流,能夠直接使用騰訊雲改造的 Obs Studio 替換現有的 Obs 軟件,-咱們在「工具」菜單欄裏面加了一個「題目分發」按鈕,能夠直接將題目打入直播流中,題目能夠預先編輯在 ini 文件中。
  • 消息發送(APP): 若是想要簡單使用 App 進行推流,可使用騰訊雲終端 SDK 的 TXLivePusher 的 sendMessage 方法,該方案能將一段buffer塞到RTMP流中(buffer的最大長度限制爲10K)。

    // iOS 示例代碼 [_answerPusher sendMessage:[mesg dataUsingEncoding:NSUTF8StringEncoding]];

    //Android 示例代碼 mTXLivePusher.sendMessage(questionInfo.getBytes("UTF-8"));

  • 消息接收: 利用騰訊雲 SDK 的 TXLivePlayer 的 onPlayEvent(PLAY_EVT_GET_MESSAGE : 2012)功能,能夠在播放器播放到指定畫面的時候,同步地將 MESSAGE 通知給您的 APP,從而將題目同步地擴散到海量的觀衆端。

消息接收的接入方案能夠參考咱們的接入文檔(iOS平臺 | Android平臺

方案二:NTP時間同步方案

原理描述

  1. 騰訊雲會每隔 1s 在您的直播流中實時插入通過 NTP 校時的國際標準時間戳。
  2. 演播室的導播員根據主持人的出題節奏,在合適的時間控制發題,發題系統會在每次下發的題目中帶上當時的國際標準時間。
  3. SDK 在播放這種打入時間戳的視頻流的時候,會定時通知您的 APP 當前 SDK 所播放的畫面是在什麼時間錄製下來的(由於導播臺到雲端通常都會有一個固定的延遲,須要您提早作一個偏差校調)。
  4. 您的 APP 能夠根據 SDK 的時間通知(即當前畫面是什麼時間錄製的),按需顯示指定的題目便可。

總結一下:方案二跟方案一的最大區別就在於題目的擴散方式,方案二的核心思路是讓題目先經過IM通道快速送達觀衆端APP,在觀衆端先緩存下來,等待播放器通知了預期的 NTP 時間戳以後,再把題目顯示出來。

方案三:小程序解決方案

方案一和方案二均可以實現「音-話-題」完美同步,可是相比於這種體驗上的小優化,APP的擴散能力則是更加劇要的。小程序偏偏提供給了APP能夠病毒式傳播的能力。

騰訊雲 SDK 已經默認打包在微信版本中,並以 <live-player> 標籤的形式對外提供,若是:

  • 採用 flv 播放地址
  • 設置 mode 爲 live 模式
  • 將 min-cache 和 max-cache 都設置爲 1
  • 推流端 gop 爲 1

那麼就能夠實現很是理想的播放延遲,並可以讓各觀衆之間的延遲偏差在1s之內,雖然沒法作到「音-話-題」分絕不差(在微信打包視頻雲 SDK 的時候,在線答題模式尚未興起,因此不支持在音視頻流中夾帶消息),但也能達到幾乎能夠媲美APP的體驗效果。

剩下的事情,就是經過小程序的 websocket 通道,或者咱們的 webim 解決方案,向小程序發題就能夠了。

接入攻略(方案一)

步驟一:開通騰訊雲直播服務

聯繫咱們開通騰訊雲 直播服務,若是您時間比較急,能夠 400 客服電話咱們加急審覈。

步驟二:獲取推流URL

想要簡單獲取一個推流URL,能夠參考文檔:快速得到地址

想要了解推流地址和直播間ID的關係,能夠參考文檔:後臺自動拼裝

想要了解若是保護本身的推流地址不被盜用,能夠參考文檔:防盜鏈簽名

步驟三:獲取播放URL

播放URL和推流URL是一一映射的,映射規則參考下面的圖示您就能明白了:

請務必使用 FLV 格式的播放地址,RTMP在高併發場景下容易出現卡頓問題。

步驟四:配置推流端

若是您是使用APP進行推流,直接參考文檔(iOS | Android)。

若是您是使用Obs推流,請注意如下幾個重要設置項:

I幀間隔(GOP)

通常演播臺的接入方式有兩種:OBS Studio 推流或者編碼盒推流,這兩種推流工具均有比較成熟的設置接口。建議將 GOP(也叫關鍵幀間隔)設置爲 1s ,這樣可讓觀衆端的延遲差別很是小。

x264 的 gop 設置對編碼效率的影響不是很大,但對延遲的影響很是大:gop越大,服務器緩存越多。因爲 SDK 的延遲修正須要一個修正時間,若是 gop 太大,對於剛進入的觀衆會有很大的影響 。

以下是Obs Studio 設置關鍵幀間隔的圖示:

編碼參數

推薦推薦配置

分辨率

視頻比特率

幀率

聲道數

採樣率

音頻比特率

優先畫質

540x960

1000kbps

25

1

48k

72kbps

優先成本

360x640

600kbps

20

1

48k

72kbps

步驟五:對接播放器

  1. 下載文檔第二部分中列出的 SDK 版本。
  2. 參考接入文檔(iOS | Android)完成播放器的接入。兩個平臺所有完成,大概須要 0.5 天的工做量。
  3. 修改默認配置 因爲 SDK 的默認配置爲普通直播場景,因此須要修改配置,操做方法以下:
//iOS源碼
TXLivePlayConfig *config = [[TXLivePlayConfig alloc] init];
TXLivePlayer *player = [[TXLivePlayer alloc] init];
//
//開啓消息接受,收不到消息的話就是沒打開這個(默認:關)
config.enableMessage = YES;
//
//設置延遲平衡點爲1s(考慮到雲端和推流端引入的延遲,實際延遲爲2s多,SDK推流:2s, obs推流:3-4秒)
config.bAutoAdjustCacheTime = YES;
config.maxAutoAdjustCacheTime = 1;
config.minAutoAdjustCacheTime = 1;
config.cacheTime = 1;
config.connectRetryCount = 3;
config.connectRetryInterval = 3;
config.enableAEC = NO;
//先setConfig再startPlay
[player setConfig:config];
//Android源碼
mTXLivePlayConfig = new TXLivePlayConfig();
mTXLivePlayer = new TXLivePlayer(context);
//
//開啓消息接收,收不到消息的話就是沒打開這個(默認:關)
mTXLivePlayConfig.setEnableMessage(true);
//
//設置延遲平衡點爲1s(考慮到雲端和推流端引入的延遲,實際延遲爲2s多,SDK推流:2s, obs推流:3-4秒)
mTXLivePlayConfig.setAutoAdjustCacheTime(true);
mTXLivePlayConfig.setCacheTime(1.0f);
mTXLivePlayConfig.setMaxAutoAdjustCacheTime(1.0f);
mTXLivePlayConfig.setMinAutoAdjustCacheTime(1.0f);
//
//先setConfig再startPlay
mTXLivePlayer.setConfig(mTXLivePlayConfig);

請務必使用 FLV 格式的播放地址,RTMP在高併發場景下容易出現卡頓問題。

步驟六:題目的擴散

  • 若是是用APP發題,只須要參考TXLivePusher 的 sendMessage 調用方法便可,參考文檔見 (iOS | Android)。
  • 若是是用咱們的定製版 Obs Studio 發題,那麼可使用本地ini文件提早把題目編輯好,由導播員在合適的時間將題目擴散出去。

可靠性評估

有些客戶可能會擔憂:音視頻通道自己不太穩定,那麼萬一卡了或者視頻數據丟了,會不會致使觀衆端看不到題目。

  • 首先,直播的音視頻數據丟幀是肯定的按照gop爲單位來丟幀的,若是gop=1,那麼每次會丟1s的音視頻數據
  • 其次,以騰訊雲目前的節點部署狀況來看,視頻卡頓90%以上都以因爲觀衆端網速不足引發的,這種狀況下其餘的網絡通信也不會很流暢。

因此,解決這個問題的辦法就是每秒鐘(gop設置爲1s的前提條件下)發送一次題目消息,相同的題號在觀衆端剔重,這樣就能夠避免偶爾的音視頻卡頓對題目到達可靠性的影響。

步驟七:接收題目消息

在咱們的推流 APP Demo 以及定製版本的 Obs Studio 中,咱們以 json 格式將題目組織成一段buffer,並將其夾在音視頻流中送出去。

獲取到這個buffer之後,您就能夠將其解析出來,並完成對應的 UI 展現。若是你須要調整json格式以支持更多的定製型,請修改源碼或者聯繫咱們。

  • TXLivePlayConfig 中的 enableMessage 開關置爲 YES。
  • TXLivePlayer 經過 TXLivePlayListener 監聽消息,消息編號:PLAY_EVT_GET_MESSAGE (2012)
// iOS 的代碼
 -(void) onPlayEvent:(int)EvtID withParam:(NSDictionary *)param {
    [self asyncRun:^{
        if (EvtID == PLAY_EVT_GET_MESSAGE) {
            dispatch_async(dispatch_get_main_queue(), ^{ //拋到主線程,避免線程安全問題
                if ([_delegate respondsToSelector:@selector(onPlayerMessage:)]) {
                    [_delegate onPlayerMessage:param[@"EVT_GET_MSG"]];
                }
            });
        }
    }];
}
//Android 示例代碼
mTXLivePlayer.setPlayListener(new ITXLivePlayListener() {
        @Override
        public void onPlayEvent(int event, Bundle param) {
            if (event == TXLiveConstants.PLAY_ERR_NET_DISCONNECT) {
                roomListenerCallback.onDebugLog("[AnswerRoom] 拉流失敗:網絡斷開");
                roomListenerCallback.onError(-1, "網絡斷開,拉流失敗");
            }
            else if (event == TXLiveConstants.PLAY_EVT_GET_MESSAGE) {
                String msg = null;
                try {
                    msg = new String(param.getByteArray(TXLiveConstants.EVT_GET_MSG), "UTF-8");
                    roomListenerCallback.onRecvAnswerMsg(msg);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            }
        }
});

步驟八:開發答題系統

因爲騰訊雲 PAAS 的定位,因此對於跟客戶業務綁定比較緊密的答題和支付系統,咱們就不涉及了,須要您來參與開發。

這裏廣泛採用的方案是:將客戶的答案以 HTTP(S) 請求方式彙總到答題服務器上,只是實現過程須要注意解決瞬間高併發的請求壓力。

有客戶可能會問,IM系統是否適合用來答題,這裏目前看是不適合的,由於 IM 系統的主要能力在於消息擴散,而答題的主要目標是信息的收攏。

步驟九:答題結果顯示

通常題目出來一段時間之後,就會進入閉題狀態。這時,答題系統會將結果進行統計彙總,並將彙總結果下發給觀衆。

若是是用咱們的定製版 Obs Studio 擴散結果,搭一個簡單的服務器,並提供一個 http 接口,而後按照咱們約定的 json 格式跟 Obs 進行題目、答案以及人數的通信。從而實現題目和答案的分發。

這部分協議因爲文檔篇幅限制,暫時不放在文檔中詳細列出,有須要的話請 400 電話聯繫咱們。

接入攻略(方案二)

步驟一:開通騰訊雲直播服務

同方案一,再也不贅述。

步驟二:獲取推流URL & 加註NTP時間戳

參考方案一,與方案一不一樣之處在於,推流 URL 須要額外增長一個參數:

加註NTP時間戳

在推流 URL 以後添加參數 &txAddTimestamp=1 參數,服務器會每隔1s向您的直播流中打入一個帶有國際標準時間(偏差在 100ms 之內)的 SEI 時間戳。若是您使用咱們的播放器播放此視頻流,那麼就會每隔一秒鐘收到一次表明當前畫面 NTP 時間的消息通知。

步驟三:獲取播放URL

同方案一,再也不贅述。

步驟四:配置推流端

同方案一,再也不贅述。

步驟五:對接播放器

參考方案一,與方案一不一樣之處在於,此時獲取的message再也不是一個json,而是一個8字節的64位時間戳。

long timeStamp = byteArrayToInt(param.getByteArray(TXLiveConstants.EVT_GET_MSG));
/**
* 將8字節的byte數組轉成一個long值
*/
public static long byteArrayToInt(byte[] byteArray) {
        byte[] a = new byte[8];
        int i = a.length - 1, j = byteArray.length - 1;
        for (; i >= 0; i--, j--) {// 從b的尾部(即int值的低位)開始copy數據
            if (j >= 0)
                a[i] = byteArray[j];
            else
                a[i] = 0;// 若是b.length不足4,則將高位補0
        }
        // 注意此處和byte數組轉換成int的區別在於,下面的轉換中要將先將數組中的元素轉換成long型再作移位操做,
        // 若直接作位移操做將得不到正確結果,由於Java默認操做數字時,若不加聲明會將數字做爲int型來對待,此處必須注意。
        long v0 = (long) (a[0] & 0xff) << 56;// &0xff將byte值無差別轉成int,避免Java自動類型提高後,會保留高位的符號位
        long v1 = (long) (a[1] & 0xff) << 48;
        long v2 = (long) (a[2] & 0xff) << 40;
        long v3 = (long) (a[3] & 0xff) << 32;
        long v4 = (long) (a[4] & 0xff) << 24;
        long v5 = (long) (a[5] & 0xff) << 16;
        long v6 = (long) (a[6] & 0xff) << 8;
        long v7 = (long) (a[7] & 0xff);
        return v0 + v1 + v2 + v3 + v4 + v5 + v6 + v7;
}

 

步驟六:題目的擴散

若是您使用本身的 IM 系統下發題目,請忽略這一部分,若是想使用騰訊雲 IM 服務發題,請對接以下幾步:

  • 1. 開通 IM 通信服務:開通騰訊雲 雲通訊 服務。
  • 2. 配置 IM 通信服務 :按照文檔進行初始化配置,集成模式請務必選擇獨立模式。
  • 3. 使用 REST API 建立一個 BChatRoom 用於發題 :騰訊雲 IM 的 REST API 是專門提供給服務端接入用的,建立羣組這個操做通常是由您的服務器觸發,因此適合使用 REST API 方案進行接入。 BChatRoom 這種房間類型很是適合用來發題,由於它本來就是用來作系統通知的,因此消息達到率高,消息可靠性好。 建立羣組使用 v4/group_open_http_svc/create_group 能夠實現,測試方法見 SDK 開發包中的 IM後臺RESTAPI使用方法.pdf - 步驟3。
  • 4. 使用 REST API 建立一個 AVChatRoom 用於彈幕 :AVChatRoom 這種房間類型很是適合用來作聊天室的彈幕消息,有比較嚴格的髒字過濾和頻率限制邏輯,專門爲大型聊天室場景優化。 建立羣組使用 v4/group_open_http_svc/create_group 能夠實現,測試方法見 SDK 開發包中的 IM後臺RESTAPI使用方法.pdf - 步驟4。 AVChatroom中默認的頻率控制爲40條/s,若是您須要調整限制請聯繫咱們,由於消息越多,帶寬費用越高。
  • 5. 使用 REST API 在 BChatRoom 裏發送題目廣播: 消息發送可使用 v4/group_open_http_svc/send_group_msg ,測試方法見 SDK 開發包中的 IM後臺RESTAPI使用方法.pdf - 步驟5。
  • 6. 如何實時獲取在線人數? :REST API 是不支持客戶端調用的,但即便是後臺調用,騰訊雲 REST API 的 後臺調用頻率限制也只有 100次/秒, 因此要實時獲取在線人數,就須要先由您的業務後臺經過 REST API 低頻的獲取到在線人數,再經過消息通道,將在線人數下發到客戶端。 1)由您的業務服務器經過 v4/group_open_http_svc/get_group_info 得到羣的在線人數。

2)以後,由您的業務服務器經過 v4/group_open_http_svc/send_group_msg,定時將人數經過羣消息下發給客戶端。定時頻率能夠設定爲 3-5s 一次。

特別注意:REST API 不支持客戶端調用,在客戶端調用會引起私鑰泄漏,進而致使您的雲服務被惡意盜用和扣費。

步驟七:題目接收&彈幕收發

客戶端使用 IM SDK 完成消息的接收和彈幕消息的收發,這裏能夠按照以下步驟對接

  • 1. 集成精簡版 IMSDK 精簡版:IMSDK 位於 SDK開發包 中,zip包中的 「接入指引-IMSDK.pdf」 有詳細的說明。
  • 2.參考源碼完成對接: SDK開發包中有一個叫作 AnswerPlayIMCenter 的源碼文件,封裝了對於 IMSDK 的簡單調用,至關於對於接入文檔的代碼示例,您能夠參考一下,以下是這個類的成員函數說明:

成員函數

做用

initIMCenter

用於初始化,須要填寫您在騰訊雲的 IM 服務相關信息。

loginIMUser

用於登陸,您能夠把 imSDK 當成一個無界面的 QQ,用QQ收發消息確定要登陸,只是將QQ號和登陸密碼換成了您的Userid和您的服務器簽發的UserSig。

joinIMGroup

用於加入在步驟六中由您的後臺服務器經過 REST API 建立的 BChatRoom 和 AVChatRoom。

sendChatMessage

用來發送彈幕評論消息

onRecvChatMessage

用於接收來自 AVChatRoom 的彈幕消息,注意作一下渲染的頻率限制,不要收到一條彈幕消息就刷一次屏幕,手機性能可能扛不住,不少客戶都是在這裏疏忽了,由於測試期間消息很少不易發現。

onRecvIssueMessage

用於接收來自 BChatRoom 的題目消息,按照方案二的設計,每道題目裏面都有它應該顯示的 NTP 國際時間。

  • 3. 題目的顯示時機 :onRecvIssueMessage 收到的題目不要馬上顯示出來,要等來自播放器的 GET_MESSAGE 回調,若是回調的時間 >= 題目的 NTP 國際時間,就能夠把指定的題目顯示出來了。
  • 4. UserSig怎麼算? :UserSig 是 loginIMUser 時須要的一個重要信息,它的做用等同於登陸QQ用的密碼,只是這個密碼由您的服務器爲您的用戶簽發;這裏使用的密碼簽發方案是基於 RSA 非對稱加密實現的,因此安全性很是高。 UserSig 通常是由您的服務器簽發的,簽發方案能夠參考: TLS 後臺 API ,不過爲了可以能讓您快速調試起來,咱們也提供了一個Windows 的簽發小工具,您能夠在後臺同窗加入項目以前就能夠先把終端邏輯調試起來。 注意:小工具裏的公私鑰都只能用來測試,您可千萬別當真的用了。

步驟八:開發答題系統

因爲騰訊雲 PAAS 的定位,因此對於跟客戶業務綁定比較緊密的答題和支付系統,咱們就不涉及了,須要您來參與開發。

這裏廣泛採用的方案是:將客戶的答案以 HTTP(S) 請求方式彙總到答題服務器上,只是實現過程須要注意解決瞬間高併發的請求壓力。

有客戶可能會問,IM系統是否適合用來答題,這裏目前看是不適合的,由於 IM 系統的主要能力在於消息擴散,而答題的主要目標是信息的收攏。

步驟九:答題結果顯示

通常題目出來一段時間之後,就會進入閉題狀態。這時,答題系統會將結果進行統計彙總,並將彙總結果下發給觀衆,結果下發能夠繼續使用 步驟六 中的題目擴散通道。

相關閱讀

webrtc 點對點直播

騰訊雲直播接入說明

直播類業務雲化建設


此文已由做者受權雲加社區發佈,轉載請註明原文出處

相關文章
相關標籤/搜索