RTMP用戶控制消息事件

Handle_Control

本文記錄 RTMP 中的用戶控制消息事件, 客戶端和服務(wù)器發(fā)送這一消息來(lái)通知對(duì)端用戶控制事件

支持以下用戶控制事件類型:

  • Stream Begin(=0) : 服務(wù)器發(fā)送這個(gè)事件來(lái)通知客戶端一個(gè)流已經(jīng)就緒并可以用來(lái)通信。默認(rèn)情況下稠诲,這一事件在成功接收到客戶端的應(yīng)用連接命令之后以ID0發(fā)送奸晴,這一事件數(shù)據(jù)為4字節(jié)启绰,代表了已就緒的流ID.
  • Stream EOF(=1):服務(wù)器發(fā)送這一事件來(lái)通知客戶端請(qǐng)求的流的回放數(shù)據(jù)已經(jīng)結(jié)束号涯。在發(fā)送額外的命令之前不再發(fā)送任何數(shù)據(jù)绕娘。客戶端將丟棄接收到這個(gè)流的消息晓猛。 這一事件數(shù)據(jù)為4字節(jié)饿幅,代表了回放已結(jié)束的流的流ID.
  • Stream Dry(=2):服務(wù)器端發(fā)送這一事件來(lái)通知客戶端當(dāng)前流中以沒(méi)有數(shù)據(jù)。當(dāng)服務(wù)器端在一段時(shí)間內(nèi)沒(méi)有檢測(cè)到任何消息戒职。它可以通知相關(guān)客戶端當(dāng)前流已經(jīng)沒(méi)有數(shù)據(jù)了栗恩。這一事件數(shù)據(jù)為4字節(jié),代表了已沒(méi)有的流的流ID.
  • SetBuffer Length(=3):客戶端發(fā)送這一事件來(lái)通知服務(wù)器端用于緩沖流中任何數(shù)據(jù)的緩存大小(以毫秒為單位)洪燥。這一事件在服務(wù)端開(kāi)始處理流之前就發(fā)送磕秤。這一事件數(shù)據(jù)的前4個(gè)字節(jié)代表了流ID4個(gè)字節(jié)代表了以毫秒為單位的緩存的長(zhǎng)度.
  • StreamIs Recorded(=4):服務(wù)端發(fā)送這一事件來(lái)通知客戶端當(dāng)前流是一個(gè)錄制流。這一事件數(shù)據(jù)為4字節(jié)捧韵,代表了錄制流的流ID
  • PingRequest(=6):服務(wù)端發(fā)送這一事件用來(lái)測(cè)試是否能夠送達(dá)客戶端市咆。事件數(shù)據(jù)為一個(gè)4字節(jié)的TimeStamp,代表了服務(wù)端發(fā)送這一命令時(shí)的服務(wù)器本地時(shí)間纫版。客戶端在接收到這一消息后會(huì)立即發(fā)送PingResponse回復(fù).

下面的代碼時(shí)librtmp關(guān)于用戶控制消息的處理

static void
HandleCtrl(RTMP *r, const RTMPPacket *packet)
{
    short nType = -1;
    unsigned int tmp;
    if (packet->m_body && packet->m_nBodySize >= 2)
        nType = AMF_DecodeInt16(packet->m_body);
    RTMP_Log(RTMP_LOGDEBUG, "%s, received ctrl. type: %d, len: %d", __FUNCTION__, nType,
             packet->m_nBodySize);
    /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */

    if (packet->m_nBodySize >= 6) {
        switch (nType) {
        case 0:
            tmp = AMF_DecodeInt32(packet->m_body + 2);
            RTMP_Log(RTMP_LOGDEBUG, "%s, Stream Begin %d", __FUNCTION__, tmp);
            break;

        case 1:
            tmp = AMF_DecodeInt32(packet->m_body + 2);
            RTMP_Log(RTMP_LOGDEBUG, "%s, Stream EOF %d", __FUNCTION__, tmp);
            if (r->m_pausing == 1)
                r->m_pausing = 2;
            break;

        case 2:
            tmp = AMF_DecodeInt32(packet->m_body + 2);
            RTMP_Log(RTMP_LOGDEBUG, "%s, Stream Dry %d", __FUNCTION__, tmp);
            break;

        case 4:
            tmp = AMF_DecodeInt32(packet->m_body + 2);
            RTMP_Log(RTMP_LOGDEBUG, "%s, Stream IsRecorded %d", __FUNCTION__, tmp);
            break;

        case 6:     /* server ping. reply with pong. */
            tmp = AMF_DecodeInt32(packet->m_body + 2);
            RTMP_Log(RTMP_LOGDEBUG, "%s, Ping %d", __FUNCTION__, tmp);
            RTMP_SendCtrl(r, 0x07, tmp, 0);
            break;

            /* FMS 3.5 servers send the following two controls to let the client
             * know when the server has sent a complete buffer. I.e., when the
             * server has sent an amount of data equal to m_nBufferMS in duration.
             * The server meters its output so that data arrives at the client
             * in realtime and no faster.
             *
             * The rtmpdump program tries to set m_nBufferMS as large as
             * possible, to force the server to send data as fast as possible.
             * In practice, the server appears to cap this at about 1 hour's
             * worth of data. After the server has sent a complete buffer, and
             * sends this BufferEmpty message, it will wait until the play
             * duration of that buffer has passed before sending a new buffer.
             * The BufferReady message will be sent when the new buffer starts.
             * (There is no BufferReady message for the very first buffer;
             * presumably the Stream Begin message is sufficient for that
             * purpose.)
             *
             * If the network speed is much faster than the data bitrate, then
             * there may be long delays between the end of one buffer and the
             * start of the next.
             *
             * Since usually the network allows data to be sent at
             * faster than realtime, and rtmpdump wants to download the data
             * as fast as possible, we use this RTMP_LF_BUFX hack: when we
             * get the BufferEmpty message, we send a Pause followed by an
             * Unpause. This causes the server to send the next buffer immediately
             * instead of waiting for the full duration to elapse. (That's
             * also the purpose of the ToggleStream function, which rtmpdump
             * calls if we get a read timeout.)
             *
             * Media player apps don't need this hack since they are just
             * going to play the data in realtime anyway. It also doesn't work
             * for live streams since they obviously can only be sent in
             * realtime. And it's all moot if the network speed is actually
             * slower than the media bitrate.
             */
        case 31:
            tmp = AMF_DecodeInt32(packet->m_body + 2);
            RTMP_Log(RTMP_LOGDEBUG, "%s, Stream BufferEmpty %d", __FUNCTION__, tmp);
            if (!(r->Link.lFlags & RTMP_LF_BUFX))
                break;
            if (!r->m_pausing) {
                r->m_pauseStamp = r->m_mediaChannel < r->m_channelsAllocatedIn ?
                                  r->m_channelTimestamp[r->m_mediaChannel] : 0;
                RTMP_SendPause(r, TRUE, r->m_pauseStamp);
                r->m_pausing = 1;
            } else if (r->m_pausing == 2) {
                RTMP_SendPause(r, FALSE, r->m_pauseStamp);
                r->m_pausing = 3;
            }
            break;

        case 32:
            tmp = AMF_DecodeInt32(packet->m_body + 2);
            RTMP_Log(RTMP_LOGDEBUG, "%s, Stream BufferReady %d", __FUNCTION__, tmp);
            break;

        default:
            tmp = AMF_DecodeInt32(packet->m_body + 2);
            RTMP_Log(RTMP_LOGDEBUG, "%s, Stream xx %d", __FUNCTION__, tmp);
            break;
        }

    }

    if (nType == 0x1A) {
        RTMP_Log(RTMP_LOGDEBUG, "%s, SWFVerification ping received: ", __FUNCTION__);
        if (packet->m_nBodySize > 2 && packet->m_body[2] > 0x01) {
            RTMP_Log(RTMP_LOGERROR,
                     "%s: SWFVerification Type %d request not supported! Patches welcome...",
                     __FUNCTION__, packet->m_body[2]);
        }
#ifdef CRYPTO
        /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */

        /* respond with HMAC SHA256 of decompressed SWF, key is the 30byte player key, also the last 30 bytes of the server handshake are applied */
        else if (r->Link.SWFSize) {
            RTMP_SendCtrl(r, 0x1B, 0, 0);
        } else {
            RTMP_Log(RTMP_LOGERROR,
                     "%s: Ignoring SWFVerification request, use --swfVfy!",
                     __FUNCTION__);
        }
#else
        RTMP_Log(RTMP_LOGERROR,
                 "%s: Ignoring SWFVerification request, no CRYPTO support!",
                 __FUNCTION__);
#endif
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末客情,一起剝皮案震驚了整個(gè)濱河市其弊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌膀斋,老刑警劉巖梭伐,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異仰担,居然都是意外死亡糊识,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門摔蓝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)赂苗,“玉大人,你說(shuō)我怎么就攤上這事贮尉“枳蹋” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵猜谚,是天一觀的道長(zhǎng)败砂。 經(jīng)常有香客問(wèn)我赌渣,道長(zhǎng),這世上最難降的妖魔是什么昌犹? 我笑而不...
    開(kāi)封第一講書人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任坚芜,我火速辦了婚禮,結(jié)果婚禮上斜姥,老公的妹妹穿的比我還像新娘鸿竖。我一直安慰自己,他們只是感情好疾渴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布千贯。 她就那樣靜靜地躺著,像睡著了一般搞坝。 火紅的嫁衣襯著肌膚如雪搔谴。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,462評(píng)論 1 302
  • 那天桩撮,我揣著相機(jī)與錄音敦第,去河邊找鬼。 笑死店量,一個(gè)胖子當(dāng)著我的面吹牛芜果,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播融师,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼右钾,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了旱爆?” 一聲冷哼從身側(cè)響起舀射,我...
    開(kāi)封第一講書人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎怀伦,沒(méi)想到半個(gè)月后脆烟,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡房待,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年邢羔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片桑孩。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拜鹤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出流椒,到底是詐尸還是另有隱情署惯,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布镣隶,位于F島的核電站极谊,受9級(jí)特大地震影響诡右,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜轻猖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一帆吻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧咙边,春花似錦猜煮、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至市殷,卻和暖如春愕撰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背醋寝。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工搞挣, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人音羞。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓囱桨,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親嗅绰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子舍肠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 實(shí)時(shí)消息協(xié)議---流的分塊 版權(quán)聲明: 版權(quán)(c)2009 Adobe系統(tǒng)有限公司。全權(quán)所有窘面。 摘要: 本備忘錄描...
    一個(gè)人zy閱讀 1,900評(píng)論 0 9
  • 國(guó)家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說(shuō)閱讀 10,967評(píng)論 6 13
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理翠语,服務(wù)發(fā)現(xiàn),斷路器民镜,智...
    卡卡羅2017閱讀 134,656評(píng)論 18 139
  • 個(gè)人翻譯啡专,轉(zhuǎn)載請(qǐng)注明出處险毁,謝謝制圈! Adobe's Real Time Messaging Protocol 摘要 ...
    SniperPan閱讀 2,735評(píng)論 1 17
  • 人生會(huì)面臨無(wú)數(shù)的選擇,不要為你的選擇后悔畔况,既然已經(jīng)選擇就將它走完鲸鹦,不到最后誰(shuí)都不知道結(jié)果不是嗎?
    丌夏閱讀 188評(píng)論 0 0