/* 客户端通知服务端停止或启动播放 */ static ngx_int_t ngx_rtmp_live_pause(ngx_rtmp_session_t *s, ngx_rtmp_pause_t *v) { ngx_rtmp_live_ctx_t *ctx; ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); if (ctx == NULL || ctx->stream == NULL) { goto next; } ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "live: pause=%i timestamp=%f", (ngx_int_t) v->pause, v->position); if (v->pause) { if (ngx_rtmp_send_status(s, "NetStream.Pause.Notify", "status", "Paused live") != NGX_OK) { return NGX_ERROR; } ctx->paused = 1; ngx_rtmp_live_stop(s); } else { if (ngx_rtmp_send_status(s, "NetStream.Unpause.Notify", "status", "Unpaused live") != NGX_OK) { return NGX_ERROR; } ctx->paused = 0; ngx_rtmp_live_start(s); } next: return next_pause(s, v); }
static ngx_int_t ngx_rtmp_live_stream_eof(ngx_rtmp_session_t *s, ngx_rtmp_stream_eof_t *v) { ngx_rtmp_live_ctx_t *ctx; ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); if (ctx == NULL || ctx->stream == NULL || !ctx->publishing) { goto next; } ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "live: stream_eof"); ngx_rtmp_live_stop(s); next: return next_stream_eof(s, v); }
/* 关闭流 */ static ngx_int_t ngx_rtmp_live_close_stream(ngx_rtmp_session_t *s, ngx_rtmp_close_stream_t *v) { ngx_rtmp_session_t *ss; ngx_rtmp_live_ctx_t *ctx; ngx_rtmp_live_ctx_t **cctx; ngx_rtmp_live_ctx_t *pctx; ngx_rtmp_live_stream_t **stream; ngx_rtmp_live_app_conf_t *lacf; lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_live_module); if (lacf == NULL) { goto next; } ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); if (ctx == NULL) { goto next; } if (ctx->stream == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "live: not joined"); goto next; } ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "live: leave '%s'", ctx->stream->name); if (ctx->stream->publishing && ctx->publishing) { ctx->stream->publishing = 0; } /* 从直播流中删除当前播放流 */ for (cctx = &ctx->stream->ctx; *cctx; cctx = &(*cctx)->next) { if (*cctx == ctx) { /* 为当前流,删除,指向当前流指向的下一条流 */ *cctx = ctx->next; break; } } /* 正在发布或者播放,则停止 */ if (ctx->publishing || ctx->stream->active) { ngx_rtmp_live_stop(s); } /* 如果是发布端关闭,需要关闭对应的播放流 */ if (ctx->publishing) { ngx_rtmp_send_status(s, "NetStream.Unpublish.Success", "status", "Stop publishing"); if (!lacf->idle_streams) { for (pctx = ctx->stream->ctx; pctx; pctx = pctx->next) { if (pctx->publishing == 0) { ss = pctx->session; ngx_log_debug0(NGX_LOG_DEBUG_RTMP, ss->connection->log, 0, "live: no publisher"); ngx_rtmp_finalize_session(ss); } } } } if (ctx->stream->ctx) { /* 该rtmp流对应的直播流还有其他rtmp流 */ ctx->stream = NULL; goto next; } ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "live: delete empty stream '%s'", ctx->stream->name); /* 该rtmp流对应的直播流没有其他rtmp流,回收直播流内存 */ stream = ngx_rtmp_live_get_stream(s, ctx->stream->name, 0); if (stream == NULL) { goto next; } *stream = (*stream)->next; /* 暂时无使用 */ ctx->stream->next = lacf->free_streams; /* 将stream 作为头节点加入释放流链链表 */ lacf->free_streams = ctx->stream; /* 更新释放流链表地址 */ ctx->stream = NULL; /* 置NULL,不关联直播流 */ if (!ctx->silent && !ctx->publishing && !lacf->play_restart) { ngx_rtmp_send_status(s, "NetStream.Play.Stop", "status", "Stop live"); } next: return next_close_stream(s, v); }
static ngx_int_t ngx_rtmp_live_close_stream(ngx_rtmp_session_t *s, ngx_rtmp_close_stream_t *v) { ngx_rtmp_session_t *ss; ngx_rtmp_live_ctx_t *ctx, **cctx, *pctx; ngx_rtmp_live_stream_t **stream; ngx_rtmp_live_app_conf_t *lacf; lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_live_module); if (lacf == NULL) { goto next; } ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); if (ctx == NULL) { goto next; } if (ctx->stream == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "live: not joined"); goto next; } ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "live: leave '%s'", ctx->stream->name); if (ctx->stream->publishing && ctx->publishing) { ctx->stream->publishing = 0; } for (cctx = &ctx->stream->ctx; *cctx; cctx = &(*cctx)->next) { if (*cctx == ctx) { *cctx = ctx->next; break; } } if (ctx->publishing || ctx->stream->active) { ngx_rtmp_live_stop(s); } if (ctx->publishing) { ngx_rtmp_send_status(s, "NetStream.Unpublish.Success", "status", "Stop publishing"); if (!lacf->idle_streams) { for (pctx = ctx->stream->ctx; pctx; pctx = pctx->next) { if (pctx->publishing == 0) { ss = pctx->session; ngx_log_debug0(NGX_LOG_DEBUG_RTMP, ss->connection->log, 0, "live: no publisher"); ngx_rtmp_finalize_session(ss); } } } } if (ctx->stream->ctx) { ctx->stream = NULL; goto next; } ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "live: delete empty stream '%s'", ctx->stream->name); stream = ngx_rtmp_live_get_stream(s, ctx->stream->name, 0); if (stream == NULL) { goto next; } *stream = (*stream)->next; ctx->stream->next = lacf->free_streams; lacf->free_streams = ctx->stream; ctx->stream = NULL; if (!ctx->silent && !ctx->publishing && !lacf->play_restart) { ngx_rtmp_send_status(s, "NetStream.Play.Stop", "status", "Stop live"); } next: return next_close_stream(s, v); }
static ngx_int_t ngx_rtmp_live_close_stream(ngx_rtmp_session_t *s, ngx_rtmp_close_stream_t *v) { ngx_rtmp_session_t *ss; ngx_rtmp_live_ctx_t *ctx, **cctx, *pctx; //**rcctx;modify for warning ngx_rtmp_live_stream_t **stream; ngx_rtmp_live_app_conf_t *lacf; lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_live_module); if (lacf == NULL) { goto next; } ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); if (ctx == NULL) { goto next; } if (ctx->stream == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "live: not joined"); goto next; } ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "live: leave '%s', publisher=%i, ctx->stream->publishing=%i", ctx->stream->name, ctx->publishing, ctx->stream->publishing); if (ctx->stream->publishing && ctx->publishing) { ctx->stream->publishing = 0; } for (cctx = &ctx->stream->ctx; *cctx; cctx = &(*cctx)->next) { if (*cctx == ctx) { *cctx = ctx->next; break; } } if (ctx->publishing || ctx->stream->active) { ngx_rtmp_live_stop(s); } if (ctx->publishing) { ngx_rtmp_send_status(s, "NetStream.Unpublish.Success", "status", "Stop publishing"); ctx->stream->bw_in.bandwidth = 0; ctx->stream->bw_real.bandwidth = 0; ctx->stream->bw_out.bandwidth = 0; if (ngx_rtmp_publishing > 0) { --ngx_rtmp_publishing; } if (!lacf->idle_streams) { for (pctx = ctx->stream->ctx; pctx; pctx = pctx->next) { if (pctx->publishing == 0) { ss = pctx->session; ngx_log_debug0(NGX_LOG_DEBUG_RTMP, ss->connection->log, 0, "live: no publisher"); ngx_rtmp_finalize_session(ss); } } } else { ngx_uint_t nplayer = 0; for (pctx = ctx->stream->ctx; pctx; pctx = pctx->next) { if (pctx->publishing == 0) { if (ngx_memcmp(pctx->session->flashver.data, NGX_RTMP_RELAY_NAME, ngx_strlen(NGX_RTMP_RELAY_NAME)) == 0) { ss = pctx->session; ngx_log_error(NGX_LOG_INFO, ss->connection->log, 0, "live: close relay session"); ngx_rtmp_finalize_session(ss); } nplayer++; } } if (nplayer > 0) { ngx_rtmp_live_checking_publish(s, ctx->stream); } } }else { if (ctx->stream->ctx != NULL && ctx->stream->ctx->next == NULL && ctx->stream->ctx->publishing) { ngx_str_t strname; strname.data = ctx->stream->name; strname.len = ngx_strlen(ctx->stream->name); ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, "live: last player close his connection."); ngx_rtmp_relay_player_dry(s, &strname); } if (ngx_rtmp_playing > 0) { --ngx_rtmp_playing; } } if (ctx->stream->ctx) { ctx->stream = NULL; goto next; } ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "live: delete empty stream '%s'", ctx->stream->name); ngx_del_timer(&(ctx->stream->check_evt)); stream = ngx_rtmp_live_get_stream(s, ctx->stream->name, 0); if (stream == NULL) { goto next; } *stream = (*stream)->next; ctx->stream->next = lacf->free_streams; lacf->free_streams = ctx->stream; ctx->stream = NULL; if (!ctx->silent && !ctx->publishing && !lacf->play_restart) { ngx_rtmp_send_status(s, "NetStream.Play.Stop", "status", "Stop live"); } next: return next_close_stream(s, v); }