我们介绍最简单的rtmp直播流程
概括
- 通过ngx_rtmp_module中的配置ngx_rtmp_block函数去建立对应的ngx_listening_t对象,并且将回调设置为ngx_rtmp_init_connection函数
- 在ngx_rtmp_init_connection接受到回调后开始调用ngx_rtmp_handshake握手,更改连接读的回调:ngx_rtmp_handshake_recv,写回调:ngx_rtmp_handshake_send,开始进行rtmp握手协议。
- 握手完毕后调用ngx_rtmp_cycle,开始进入接受rtmp的message阶段,读回调设置为ngx_rtmp_recv,写回调设置为ngx_rtmp_send。
- 收到一个rtmp的message进如ngx_rtmp_recv,收到不同的chunk后封装成message。调用ngx_rtmp_receive_message处理一个完整的ngx_rtmp_receive_message。在ngx_rtmp_receive_message中根据message的类型调用不同模块各自收到的回调
- (我们这边就讲音视频的回调,别的都是类似的)在ngx_rtmp_live_module中设置了一个音视频接受的回调ngx_rtmp_live_av,接收到音视频的数据后会调用这个函数。通过ngx_rtmp_prepare_message将一个message进行拆成一个一个chunk。最后调用ngx_rtmp_send将所有订阅一个一个传入。这样就结束了接受到发送的流程。
- 在一个用户需要播放的情况下,在解析到cmd是play的时候,回调用cmd的play回调链。同样也是在ngx_rtmp_live_module模块中。把播放的连接放入到对应的流stream后面。
开始监听
rtmp在一开始解析配置的时候会调用ngx_rtmp_optimize_servers函数用于向event中放入需要监听ip和端口,如果向具体了解一个链接怎么建立的可以参考上一篇文章nginx各个模块的监听怎么建立。设置了回调为ngx_rtmp_init_connection函数。
while (i < last) {
/* 省略无关代码 */
/*这里外层有一个循环,为所有配置创建一个对应的监听*/
ls = ngx_create_listening(cf, addr[i].sockaddr, addr[i].socklen);
if (ls == NULL) {
return NGX_CONF_ERROR;
}
ls->addr_ntop = 1;
ls->handler = ngx_rtmp_init_connection;
}
握手
当接受到一个链接时候回调用ngx_rtmp_init_connection,并且把连接传入ngx_connection_t。把ngx_connection_t封装成一个ngx_rtmp_session_t后,开始调用rtmp协议的握手ngx_rtmp_handshake函数,这里把连接的读取和写入函数都改成了握手对应的函数,握手分为很多步骤,可以详细了解rtmp协议。
void
ngx_rtmp_handshake(ngx_rtmp_session_t *s)
{
ngx_connection_t *c;
c = s->connection;
/*修改读写的回调*/
c->read->handler = ngx_rtmp_handshake_recv;
c->write->handler = ngx_rtmp_handshake_send;
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"handshake: start server handshake");
s->hs_buf = ngx_rtmp_alloc_handshake_buffer(s);
s->hs_stage