RTMPユーザ制御メッセージイベント

7499 ワード

Handle_Control
本明細書では、RTMPにおけるユーザ制御メッセージイベントを記録し、クライアントおよびサーバは、エンドユーザ制御イベントを通知するためにこのメッセージを送信する
次のユーザー制御イベントタイプをサポートします.
  • Stream Begin(=0):サーバは、このイベントを送信して、クライアントにストリームが準備され、通信に使用できることを通知する.デフォルトでは、このイベントは、クライアントのアプリケーション接続コマンドを正常に受信後、ID0で送信され、このイベントデータは、準備完了ストリーム4を表すIDバイトである.
  • Stream EOF(=1):サーバは、クライアントが要求したストリームの再生データが終了したことを通知するために、このイベントを送信する.追加のコマンドを送信する前に、データは送信されません.クライアントは、このストリームを受信したメッセージを破棄します.このイベントデータは、再生終了ストリームのストリーム4を表すIDバイトである.
  • Stream Dry(=2):サーバ側は、データがないことをクライアントに通知するために、このイベントを送信する.サーバ側が一定期間メッセージを検出しなかった場合.関連クライアントに現在のストリームにデータがないことを通知できます.このイベントデータは4バイトである、既にないストリームのストリームIDを表す.
  • SetBuffer Length(=3):クライアントは、バッファストリーム内の任意のデータのキャッシュサイズ(ミリ秒単位)をサーバ側に通知するために、このイベントを送信する.このイベントは、サービス側がストリームの処理を開始する前に送信されます.このイベントデータの最初の4バイトは、ストリームIDの後の4バイトは、ミリ秒単位のキャッシュの長さを表す.
  • StreamIs Recorded(=4):サービス側は、クライアントに現在のストリームが録画ストリームであることを通知するために、このイベントを送信する.このイベントデータは4バイトであり、録画ストリームのストリームID
  • を表す.
  • PingRequest(=6):サービス側は、クライアントに送信できるかどうかをテストするために、このイベントを送信する.イベントデータは、4バイトのTimeStampであり、サービス側がこのコマンドを送信したときのサーバローカル時間を表す.クライアントは、このメッセージを受信と、直ちにPingResponseの返信を送信する.

  • 次のコードの場合librtmpユーザ制御メッセージの処理について
    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
        }
    }