RTMP协议规定:
第一步,建立一个网络连接(NetConnection):客户端和服务端的基础连通关系
第二步:建立一个网络流(NetStream)发送多媒体的通道(只能建立一个网络连接,可以建立多个网络流)
网络连接与网络流的关系如下图所示:
具体而言,在ngx_rmtp中如何实现呢?
客户端收到服务端的"connect"消息后(如前文所讲),会启动connect协议交流。但在此之前需要将处理消息的回调进行注册上,收消息回调为ngx_rtmp_recv,发送消息的回调为ngx_rtmp_send。示例代码如下:
void ngx_rtmp_cycle(ngx_rtmp_session_t *s)
{
ngx_connection_t *c;
c = s->connection;
c->read->handler = ngx_rtmp_recv;
c->write->handler = ngx_rtmp_send;
s->ping_evt.data = c;
s->ping_evt.log = c->log;
s->ping_evt.handler = ngx_rtmp_ping;
ngx_rtmp_reset_ping(s);
ngx_rtmp_recv(c->read);
}
当收到对方发来的消息时:
- 解析消息头
/* parse headers /
if (b->pos == b->start) {
p = b->pos;
/ chunk basic header /
fmt = (p >> 6) & 0x03;
csid = p++ & 0x3f;
if (csid == 0) {
if (b->last - p < 1)
continue;
csid = 64;
csid += (uint8_t)p++;
} else if (csid == 1) {
if (b->last - p < 2)
continue;
csid = 64;
csid += (uint8_t)p++;
csid += (uint32_t)256 * ((uint8_t)p++);
}
/ link orphan /
if (s->in_csid == 0) {
/ unlink from stream #0 /
st->in = st->in->next;
/ link to new stream /
s->in_csid = csid;
st = &s->in_streams[csid];
if (st->in == NULL) {
in->next = in;
} else {
in->next = st->in->next;
st->in->next = in;
}
st->in = in;
h = &st->hdr;
h->csid = csid;
}
ext = st->ext;
timestamp = st->dtime;
if (fmt <= 2 ) {
if (b->last - p < 3)
continue;
/ timestamp:
* big-endian 3b -> little-endian 4b /
pp = (u_char)×tamp;
pp[2] = p++;
pp[1] = p++;
pp[0] = p++;
pp[3] = 0;
ext = (timestamp == 0x00ffffff);
if (fmt <= 1) {
if (b->last - p < 4)
continue;
/ size:
* big-endian 3b -> little-endian 4b
* type:
* 1b -> 1b/
pp = (u_char)&h->mlen;
pp[2] = *p++;
pp[1] = *p++;
pp[0] = p++;
pp[3] = 0;
h->type = (uint8_t)p++;
if (fmt == 0) {
if (b->last - p < 4)
continue;
/ stream:
* little-endian 4b -> little-endian 4b /
pp = (u_char)&h->msid;
pp[0] = *p++;
pp[1] = *p++;
pp[2] = *p++;
pp[3] = p++;
}
}
}
/ extended header /
if (ext) {
if (b->last - p < 4)
continue;
pp = (u_char)×tamp;
pp[3] = *p++;
pp[2] = *p++;
pp[1] = *p++;
pp[0] = p++;
}
/ header done */
b->pos = p;
} - 判断类型,如果是"connect"的cmd消息时,其调用回调ngx_rtmp_cmd_connect_init.具体如下:
- 将ack_size发送对方给对方,ngx_rtmp_send_ack_size
- 将bandwdth发送给对方,ngx_rtmp_send_bandwidth
- 将chunk_size发送给对方,ngx_rtmp_send_chunk_size
- 将connect协议回应消息发送给对方,ngx_rtmp_send_amf,具体如下:
static ngx_rtmp_amf_elt_t out_inf[] = {
{ NGX_RTMP_AMF_STRING,
ngx_string("level"),
"status", 0 },
{ NGX_RTMP_AMF_STRING,
ngx_string("code"),
"NetConnection.Connect.Success", 0 },
{ NGX_RTMP_AMF_STRING,
ngx_string("description"),
"Connection succeeded.", 0 },
{ NGX_RTMP_AMF_NUMBER,
ngx_string("objectEncoding"),
&object_encoding, 0 }
};
- netconnection状态
- "NetConnection.Connect.Success" --- 服务器连接成功
- "NetConnection.Connect.Closed" --- 连接中断
- "NetConnection.Connect.Failed" --- 连接失败
- "NetConnection.Connect.Rejected" --- 没有权限
网友评论