small-package/luci-app-nginx-pingos/modules/nginx-rtmp-module/ngx_live.c

450 lines
11 KiB
C

/*
* Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com
*/
#include "ngx_live.h"
static void *ngx_live_create_conf(ngx_cycle_t *cf);
static char *ngx_live_init_conf(ngx_cycle_t *cycle, void *conf);
static ngx_command_t ngx_live_commands[] = {
{ ngx_string("stream_buckets"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
0,
offsetof(ngx_live_conf_t, stream_buckets),
NULL },
{ ngx_string("server_buckets"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
0,
offsetof(ngx_live_conf_t, server_buckets),
NULL },
ngx_null_command
};
static ngx_core_module_t ngx_live_module_ctx = {
ngx_string("live"),
ngx_live_create_conf, /* create conf */
ngx_live_init_conf /* init conf */
};
ngx_module_t ngx_live_module = {
NGX_MODULE_V1,
&ngx_live_module_ctx, /* module context */
ngx_live_commands, /* module directives */
NGX_CORE_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static void *
ngx_live_create_conf(ngx_cycle_t *cycle)
{
ngx_live_conf_t *lcf;
lcf = ngx_pcalloc(cycle->pool, sizeof(ngx_live_conf_t));
if (lcf == NULL) {
return NULL;
}
lcf->stream_buckets = NGX_CONF_UNSET_SIZE;
lcf->server_buckets = NGX_CONF_UNSET_SIZE;
return lcf;
}
static char *
ngx_live_init_conf(ngx_cycle_t *cycle, void *conf)
{
ngx_live_conf_t *lcf = conf;
lcf->pool = ngx_create_pool(4096, cycle->log);
if (lcf->pool == NULL) {
return NGX_CONF_ERROR;
}
ngx_conf_init_size_value(lcf->stream_buckets, 10007);
ngx_conf_init_size_value(lcf->server_buckets, 1031);
lcf->servers = ngx_pcalloc(lcf->pool,
sizeof(ngx_live_server_t *) * lcf->server_buckets);
if (lcf->servers == NULL) {
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
static ngx_live_server_t **
ngx_live_find_server(ngx_str_t *serverid)
{
ngx_live_conf_t *lcf;
ngx_live_server_t **psrv;
lcf = (ngx_live_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
ngx_live_module);
psrv = &lcf->servers[ngx_hash_key(serverid->data, serverid->len)
% lcf->server_buckets];
for (; *psrv; psrv = &(*psrv)->next) {
if (ngx_strlen((*psrv)->serverid) == serverid->len &&
ngx_memcmp((*psrv)->serverid, serverid->data, serverid->len) == 0)
{
break;
}
}
return psrv;
}
static ngx_live_server_t *
ngx_live_get_server(ngx_str_t *serverid)
{
ngx_live_conf_t *lcf;
ngx_live_server_t *srv;
if (serverid->len > NGX_LIVE_SERVERID_LEN - 1) {
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
"serverid too long: %ui", serverid->len);
return NULL;
}
lcf = (ngx_live_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
ngx_live_module);
srv = lcf->free_server;
if (srv == NULL) {
srv = ngx_pcalloc(lcf->pool, sizeof(ngx_live_server_t));
if (srv == NULL) {
return NULL;
}
srv->streams = ngx_pcalloc(lcf->pool,
sizeof(ngx_live_stream_t *) * lcf->stream_buckets);
if (srv->streams == NULL) {
return NULL;
}
++lcf->alloc_server_count;
} else {
lcf->free_server = srv->next;
--lcf->free_server_count;
}
*ngx_cpymem(srv->serverid, serverid->data, serverid->len) = 0;
srv->deleted = 0;
srv->n_stream = 0;
return srv;
}
static void
ngx_live_put_server(ngx_live_server_t *server)
{
ngx_live_conf_t *lcf;
lcf = (ngx_live_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
ngx_live_module);
server->next = lcf->free_server;
lcf->free_server = server;
++lcf->free_server_count;
}
static ngx_live_stream_t **
ngx_live_find_stream(ngx_live_server_t *server, ngx_str_t *stream)
{
ngx_live_conf_t *lcf;
ngx_live_stream_t **pst;
lcf = (ngx_live_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
ngx_live_module);
pst = &server->streams[ngx_hash_key(stream->data, stream->len)
% lcf->stream_buckets];
for (; *pst; pst = &(*pst)->next) {
if (ngx_strlen((*pst)->name) == stream->len &&
ngx_memcmp((*pst)->name, stream->data, stream->len) == 0)
{
break;
}
}
return pst;
}
static ngx_live_stream_t *
ngx_live_get_stream(ngx_str_t *stream)
{
ngx_live_conf_t *lcf;
ngx_live_stream_t *st;
if (stream->len > NGX_LIVE_STREAM_LEN - 1) {
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
"stream too long: %ui", stream->len);
return NULL;
}
lcf = (ngx_live_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
ngx_live_module);
st = lcf->free_stream;
if (st == NULL) {
st = ngx_pcalloc(lcf->pool, sizeof(ngx_live_stream_t));
++lcf->alloc_stream_count;
} else {
lcf->free_stream = st->next;
--lcf->free_stream_count;
ngx_memzero(st, sizeof(ngx_live_stream_t));
}
*ngx_cpymem(st->name, stream->data, stream->len) = 0;
st->pslot = -1;
st->epoch = ngx_current_msec;
ngx_map_init(&st->pubctx, ngx_map_hash_int, ngx_cmp_int);
return st;
}
static void
ngx_live_put_stream(ngx_live_stream_t *st)
{
ngx_live_conf_t *lcf;
lcf = (ngx_live_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
ngx_live_module);
st->next = lcf->free_stream;
lcf->free_stream = st;
++lcf->free_stream_count;
}
ngx_live_server_t *
ngx_live_create_server(ngx_str_t *serverid)
{
ngx_live_server_t **psrv;
psrv = ngx_live_find_server(serverid);
if (*psrv) {
(*psrv)->deleted = 0;
return *psrv;
}
*psrv = ngx_live_get_server(serverid);
return *psrv;
}
ngx_live_server_t *
ngx_live_fetch_server(ngx_str_t *serverid)
{
ngx_live_server_t **psrv;
psrv = ngx_live_find_server(serverid);
return *psrv;
}
void
ngx_live_delete_server(ngx_str_t *serverid)
{
ngx_live_server_t **psrv, *srv;
psrv = ngx_live_find_server(serverid);
if (*psrv == NULL) {
return;
}
if ((*psrv)->n_stream != 0) {
(*psrv)->deleted = 1;
}
if ((*psrv)->n_stream == 0) {
srv = *psrv;
*psrv = srv->next;
ngx_live_put_server(srv);
}
}
ngx_live_stream_t *
ngx_live_create_stream(ngx_str_t *serverid, ngx_str_t *stream)
{
ngx_live_server_t **psrv;
ngx_live_stream_t **pst;
psrv = ngx_live_find_server(serverid);
if (*psrv == NULL) {
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
"server %V does not exist when create stream", serverid);
return NULL;
}
pst = ngx_live_find_stream(*psrv, stream);
if (*pst) {
return *pst;
}
*pst = ngx_live_get_stream(stream);
++(*psrv)->n_stream;
return *pst;
}
ngx_live_stream_t *
ngx_live_fetch_stream(ngx_str_t *serverid, ngx_str_t *stream)
{
ngx_live_server_t **psrv;
ngx_live_stream_t **pst;
psrv = ngx_live_find_server(serverid);
if (*psrv == NULL) {
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
"server %V does not exist when fetch stream", serverid);
return NULL;
}
pst = ngx_live_find_stream(*psrv, stream);
return *pst;
}
void
ngx_live_delete_stream(ngx_str_t *serverid, ngx_str_t *stream)
{
ngx_live_server_t **psrv;
ngx_live_stream_t **pst, *st;
psrv = ngx_live_find_server(serverid);
if (*psrv == NULL) {
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
"server %V does not exist when delete stream", serverid);
return;
}
pst = ngx_live_find_stream(*psrv, stream);
if (*pst == NULL) {
return;
}
st = *pst;
*pst = st->next;
ngx_live_put_stream(st);
--(*psrv)->n_stream;
if ((*psrv)->deleted && (*psrv)->n_stream == 0) {
ngx_live_delete_server(serverid);
}
}
void
ngx_live_create_ctx(ngx_rtmp_session_t *s, unsigned publishing)
{
ngx_rtmp_core_ctx_t *ctx, **pctx;
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_core_module);
if (ctx == NULL) {
ctx = ngx_pcalloc(s->pool, sizeof(ngx_rtmp_core_ctx_t));
if (ctx == NULL) {
return;
}
ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_core_module);
}
ctx->publishing = publishing;
ctx->session = s;
if (publishing) {
pctx = &s->live_stream->publish_ctx;
} else {
pctx = &s->live_stream->play_ctx;
}
ctx->next = (*pctx);
*pctx = ctx;
}
void
ngx_live_delete_ctx(ngx_rtmp_session_t *s)
{
ngx_rtmp_core_ctx_t *ctx, **pctx;
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_core_module);
if (ctx == NULL) {
return;
}
if (ctx->publishing) {
pctx = &s->live_stream->publish_ctx;
} else {
pctx = &s->live_stream->play_ctx;
}
for (/* void */; *pctx; pctx = &(*pctx)->next) {
if (*pctx == ctx) {
*pctx = ctx->next;
return;
}
}
}
ngx_chain_t *
ngx_live_state(ngx_http_request_t *r)
{
ngx_live_conf_t *lcf;
ngx_chain_t *cl;
ngx_buf_t *b;
size_t len;
lcf = (ngx_live_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
ngx_live_module);
len = sizeof("##########ngx live state##########\n") - 1
+ sizeof("ngx_live nalloc server: \n") - 1 + NGX_OFF_T_LEN
+ sizeof("ngx_live nfree server: \n") - 1 + NGX_OFF_T_LEN
+ sizeof("ngx_live nalloc stream: \n") - 1 + NGX_OFF_T_LEN
+ sizeof("ngx_live nfree stream: \n") - 1 + NGX_OFF_T_LEN;
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NULL;
}
cl->next = NULL;
b = ngx_create_temp_buf(r->pool, len);
if (b == NULL) {
return NULL;
}
cl->buf = b;
b->last = ngx_snprintf(b->last, len,
"##########ngx live state##########\n"
"ngx_live nalloc server: %ui\nngx_live nfree server: %ui\n"
"ngx_live nalloc stream: %ui\nngx_live nfree stream: %ui\n",
lcf->alloc_server_count, lcf->free_server_count,
lcf->alloc_stream_count, lcf->free_stream_count);
return cl;
}