您的位置:首页 > 编程语言

LibRTMP源代码分析6

2015-09-21 15:22 621 查看
前面介绍了建立网络连接(NetConnection)和建立网络流(NetStream),这些命令数据是怎么发送出去的呢?在底层是怎么实现的呢?接下来就要详细分析各种消息的发送过程。
首先大致列举一下消息命令:

发送connect命令 : SendConnectPacket()
发送createStream命令 : RTMP_SendCreateStream()
发送releaseStream命令 : SendReleaseStream()
发送FCSubscribe命令 : SendFCSubscribe()
发送FCPublish命令 : SendFCPublish()
发送FCUnpublish命令 : SendFCUnpublish()
发送Publish命令 : SendPublish()
发送deleteStream命令 : SendDeleteStream()
发送pause命令 : RTMP_SendPause()
发送seek命令 : RTMP_SendSeek()
发送checkbw命令 :SendCheckBW()
发送result命令 : SendCheckBWResult()
发送pong命令 : SendPong()
发送play命令 : SendPlay()
发送playlist命令 : SendPlaylist()
发送用户控制消息 : RTMP_SendCtrl()
发送ServerBW命令(致谢窗口大小) : RTMP_SendServerBW()
发送ClientBW命令(对等端带宽) : RTMP_SendClientBW()
发送致谢命令(接收到的字节数) : SendBytesReceived()
发送secureTokenResponse命令 : SendSecureTokenResponse()
发送NetStream_Authenticate_UsherToken命令 :
SendUsherToken()

以上函数命名有两种规律:RTMP_Send****()或者Send****(),其中****号代表命令的名称。
以上发送命令代码比较相似,其中SendConnectPacket()函数的代码分析已经在前面第5篇文章中已经给出,其他函数也比较相似,就不一一分析,只给出部分函数的代码分析。

/**
* @brief 发送createStream命令.
* 命令消息由命令名,传输ID,和命令对象组成.
* 命令对象由一系列的相关参数组成.
* 可参考rtmp协议:rtmp命令消息--4.1.3节
*/
int RTMP_SendCreateStream(RTMP *r);

/**
* @brief 发送releaseStream命令
* 命令消息由命令名,传输ID,和命令对象组成.
* 命令对象由一系列的相关参数组成.
*/
static int SendReleaseStream(RTMP *r);

/**
* @brief 发送FCPublish命令
* 命令消息由命令名,传输ID,和命令对象组成.
* 命令对象由一系列的相关参数组成.
*/
static int SendFCPublish(RTMP *r);

/**
* @brief 发送FCUnpublish命令
* 命令消息由命令名,传输ID,和命令对象组成.
* 命令对象由一系列的相关参数组成.
*/
static int SendFCUnpublish(RTMP *r);

/**
* @brief 发送Publish命令
* 命令消息由命令名,传输ID,和命令对象组成.
* 命令对象由一系列的相关参数组成.
* 可参考rtmp协议:rtmp命令消息--4.2.6节
*/
static int SendPublish(RTMP *r)
{
RTMPPacket packet;
char pbuf[1024], *pend = pbuf + sizeof(pbuf);
char *enc;

// 块流ID为4
packet.m_nChannel = 0x04;
/* source channel (invoke) */
packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
// 命令消息,类型为20
packet.m_nTimeStamp = 0;
packet.m_nInfoField2 = r->m_stream_id;
// msg stream id
packet.m_hasAbsTimestamp = 0;
packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
// 指向Chunk的负载

enc = packet.m_body;
enc = AMF_EncodeString(enc, pend, &av_publish);
// 对“publish”字符串进行AMF编码
enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
// 传输ID
*enc++ = AMF_NULL;
enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
if (!enc)
return FALSE;

/* FIXME: should we choose
live based on Link.lFlags & RTMP_LF_LIVE? */
enc = AMF_EncodeString(enc, pend, &av_live);
// 编码发布类型,live表示发布直播数据而不录制到文件
if (!enc)
return FALSE;

packet.m_nBodySize = enc - packet.m_body;
return RTMP_SendPacket(r,
&packet, TRUE);
}

/**
* @brief 发送deleteStream命令,其中dStreamId表示要删除的流id.
* 命令消息由命令名,传输ID,和命令对象组成.
* 命令对象由一系列的相关参数组成.
* 可参考rtmp协议:rtmp命令消息--4.2.3节
*/
static int SendDeleteStream(RTMP *r, double dStreamId);

/**
* @brief 发送pause命令
* 可参考rtmp协议:rtmp命令消息--4.2.8节
*
* @param DoPause : 是否暂停,boolean值
* @param iTime : 流暂停或恢复播放的毫秒数
*/
int RTMP_SendPause(RTMP *r, int DoPause, int iTime);

/**
* @brief 发送seek命令
* 可参考rtmp协议:rtmp命令消息--4.2.7节
*/
int RTMP_SendSeek(RTMP *r, int iTime);

/**
* @brief 发送ServerBW命令(致谢窗口大小)
* 可参考rtmp协议:rtmp消息格式 -- 5.5节
*/
int RTMP_SendServerBW(RTMP *r)

{

RTMPPacket packet;
char pbuf[256], *pend = pbuf + sizeof(pbuf);

// 协议控制消息必须有消息流ID 0和块流ID 2,并且有最高的发送优先级
packet.m_nChannel = 0x02;
/* control channel (invoke),块流ID */
packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
packet.m_packetType = RTMP_PACKET_TYPE_SERVER_BW;
// 协议控制消息类型5
packet.m_nTimeStamp = 0;
packet.m_nInfoField2 = 0;
packet.m_hasAbsTimestamp = 0;
packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
packet.m_nBodySize = 4;
// 致谢窗口大小(4字节)

AMF_EncodeInt32(packet.m_body, pend, r->m_nServerBW);
return RTMP_SendPacket(r, &packet, FALSE);

}

/**
* @brief 发送ClientBW命令(对等端带宽)
* 可参考rtmp协议:rtmp消息格式 -- 5.6节
*/
int RTMP_SendClientBW(RTMP *r)
{

RTMPPacket packet;
char pbuf[256], *pend = pbuf + sizeof(pbuf);

// 协议控制消息必须有消息流ID 0和块流ID 2,并且有最高的发送优先级
packet.m_nChannel = 0x02;
/* control channel (invoke),块流ID */
packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
packet.m_packetType = RTMP_PACKET_TYPE_CLIENT_BW;
// 协议控制消息类型6
packet.m_nTimeStamp = 0;
packet.m_nInfoField2 = 0;
packet.m_hasAbsTimestamp = 0;
packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
packet.m_nBodySize = 5;
// 致谢窗口大小(4字节) + 限制类型(1字节)

AMF_EncodeInt32(packet.m_body, pend, r->m_nClientBW);
packet.m_body[4] = r->m_nClientBW2;
// 限制类型:硬(0)、软(1)、或者动态(2)
return RTMP_SendPacket(r, &packet, FALSE);

}

/**
* @brief 发送致谢命令(接收到的字节数)
* 可参考rtmp协议:rtmp消息格式 -- 5.3节
*/
static int SendBytesReceived(RTMP *r)
{

RTMPPacket packet;
char pbuf[256], *pend = pbuf + sizeof(pbuf);

// 协议控制消息必须有消息流ID 0和块流ID 2,并且有最高的发送优先级
packet.m_nChannel = 0x02;
/* control channel (invoke),块流ID */
packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
packet.m_packetType = RTMP_PACKET_TYPE_BYTES_READ_REPORT;
// 协议控制消息类型3
packet.m_nTimeStamp = 0;
packet.m_nInfoField2 = 0;
packet.m_hasAbsTimestamp = 0;
packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
packet.m_nBodySize = 4;
// 序列号(4字节),是到当前时间为止已经接收到的字节数

AMF_EncodeInt32(packet.m_body, pend, r->m_nBytesIn);
/* hard coded for now */
r->m_nBytesInSent = r->m_nBytesIn;
return RTMP_SendPacket(r, &packet, FALSE);

}

/**
* @brief 发送checkbw命令
* 命令消息由命令名,传输ID,和命令对象组成.
* 命令对象由一系列的相关参数组成.
*/
static int SendCheckBW(RTMP *r);

/**
* @brief 发送result命令
*/
static int SendCheckBWResult(RTMP *r, double txn);

/**
* @brief 发送pong命令
*/
static int SendPong(RTMP *r, double txn);

/**
* @brief 发送play命令
* 可参考rtmp协议:rtmp命令消息--4.2.1节
*/
static int SendPlay(RTMP *r);

/**
* @brief 发送playlist命令
*/
static int SendPlaylist(RTMP *r);

/**
* @brief 发送secureTokenResponse命令
*/
static int SendSecureTokenResponse(RTMP *r, AVal *resp);

/**

* @brief 发送用户控制消息命令

*/

int RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime);

以上函数的总体思路是声明一个RTMPPacket类型的结构体,然后设置各种属性值,最后交给RTMP_SendPacket()进行发送。在下一节中我们具体来分析该函数的实现。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: