RTMP使用者控制訊息事件
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
}
}
相關文章
- OCX 控制元件主動傳送訊息給 MFC 視窗訊息控制元件
- 訊息資料庫Message DB:PostgreSQL的事件儲存和訊息儲存 - Eventide Blog資料庫SQL事件IDE
- 訊息佇列 RocketMQ 5.0:從訊息服務到雲原生事件流平臺佇列MQ事件
- 訊息代理與事件代理:何時使用它們事件
- 阿里雲訊息佇列 RocketMQ 5.0 全新升級:訊息、事件、流融合處理平臺阿里佇列MQ事件
- node事件迴圈和訊息佇列簡單分析事件佇列
- “訊息驅動、事件驅動、流 ”基礎概念解析事件
- (原創) odoo17中在訊息主題(mail.thread)中傳送訊息時,是否通知訊息作者進行控制OdooAIthread
- 好訊息 OR 壞訊息
- 事件訊息生產消費中介軟體-OSS.DataFlow事件
- Twitter漏洞,或造成使用者私密訊息洩露
- 使用者介面通知訊息的七個特徵 - modernanalyst特徵NaN
- 深入分析Node.js事件迴圈與訊息佇列Node.js事件佇列
- 訊息中介軟體客戶端消費控制實踐客戶端
- 如何在linux中傳送訊息給別的控制檯Linux
- 重繪DevExpress的XtraMessageBox訊息提示框控制元件devExpress控制元件
- 訊息機制篇——初識訊息與訊息佇列佇列
- RocketMQ 訊息整合:多型別業務訊息-普通訊息MQ多型型別
- RocketMQ 訊息整合:多型別業務訊息——定時訊息MQ多型型別
- 訊息通知(Notification)/使用者觸達系統設計
- FolkMQ v1.3.2 釋出(訊息中介軟體、事件匯流排)MQ事件
- MFC vc++ 中CTreeContrl如何自定義實現滑鼠單擊或雙擊響應事件 ,即重寫類似於控制元件的響應事件或訊息C++事件控制元件
- iNeuOS工業互聯平臺,釋出:訊息管理、子使用者許可權管理、元件移動事件、聯動控制和油表餅狀圖,v3.4版本元件事件
- 利用redis的hash結構搭建訊息服務(發訊息,訂閱訊息,消費訊息,退訂)Redis
- RocketMQ 原理:訊息儲存、高可用、訊息重試、訊息冪等性MQ
- 訊息中介軟體—RocketMQ訊息消費(三)(訊息消費重試)MQ
- 使用easywechat給關注公眾號使用者發訊息
- 從事件驅動程式設計模型分析Handler訊息傳遞機制事件程式設計模型
- dotnet 讀 WPF 原始碼筆記 從 WM_POINTER 訊息到 Touch 事件原始碼筆記事件
- MQTT-保留訊息和遺囑訊息MQQT
- 訊息中介軟體—RocketMQ訊息傳送MQ
- RabbitMQ訊息佇列(五):Routing 訊息路由MQ佇列路由
- 解析 RocketMQ 業務訊息——“事務訊息”MQ
- 解析 RocketMQ 業務訊息--“順序訊息”MQ
- vue---元件間傳遞訊息(父子傳遞訊息,兄弟傳遞訊息)Vue元件
- Flash 訊息
- EventBridge訊息路由|高效構建訊息路由能力路由
- 直播原始碼網站,訊息圖示在收到訊息時展示訊息條數原始碼網站