resolved merge conflict

This commit is contained in:
Roman Arutyunyan
2013-01-20 16:38:56 +04:00
4 changed files with 509 additions and 143 deletions

View File

@ -125,6 +125,8 @@ ngx_rtmp_play_create_app_conf(ngx_conf_t *cf)
return NULL; return NULL;
} }
pacf->nbuckets = 1024;
return pacf; return pacf;
} }
@ -138,10 +140,83 @@ ngx_rtmp_play_merge_app_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_str_value(conf->root, prev->root, ""); ngx_conf_merge_str_value(conf->root, prev->root, "");
ngx_conf_merge_str_value(conf->temp_path, prev->temp_path, "/tmp"); ngx_conf_merge_str_value(conf->temp_path, prev->temp_path, "/tmp");
conf->ctx = ngx_pcalloc(cf->pool, sizeof(void *) * conf->nbuckets);
if (conf->ctx == NULL) {
return NGX_CONF_ERROR;
}
return NGX_CONF_OK; return NGX_CONF_OK;
} }
static ngx_int_t
ngx_rtmp_play_join(ngx_rtmp_session_t *s)
{
ngx_rtmp_play_ctx_t *ctx, **pctx;
ngx_rtmp_play_app_conf_t *pacf;
ngx_uint_t h;
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"play: join");
pacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_play_module);
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module);
if (ctx == NULL || ctx->next) {
return NGX_ERROR;
}
h = ngx_hash_key(ctx->name, ngx_strlen(ctx->name));
pctx = &pacf->ctx[h % pacf->nbuckets];
while (*pctx) {
if (!ngx_strncmp((*pctx)->name, ctx->name, NGX_RTMP_MAX_NAME)) {
break;
}
pctx = &(*pctx)->next;
}
ctx->next = *pctx;
*pctx = ctx;
return NGX_OK;
}
static ngx_int_t
ngx_rtmp_play_leave(ngx_rtmp_session_t *s)
{
ngx_rtmp_play_ctx_t *ctx, **pctx;
ngx_rtmp_play_app_conf_t *pacf;
ngx_uint_t h;
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"play: leave");
pacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_play_module);
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module);
if (ctx == NULL || ctx->next) {
return NGX_ERROR;
}
h = ngx_hash_key(ctx->name, ngx_strlen(ctx->name));
pctx = &pacf->ctx[h % pacf->nbuckets];
while (*pctx && *pctx != ctx) {
pctx = &(*pctx)->next;
}
if (*pctx == NULL) {
return NGX_ERROR;
}
*pctx = (*pctx)->next;
return NGX_OK;
}
static void static void
ngx_rtmp_play_send(ngx_event_t *e) ngx_rtmp_play_send(ngx_event_t *e)
{ {
@ -356,6 +431,8 @@ ngx_rtmp_play_close_stream(ngx_rtmp_session_t *s, ngx_rtmp_close_stream_t *v)
"Stop video on demand"); "Stop video on demand");
} }
ngx_rtmp_play_leave(s);
next: next:
return next_close_stream(s, v); return next_close_stream(s, v);
} }
@ -487,6 +564,7 @@ ngx_rtmp_play_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v)
ngx_memzero(ctx, sizeof(*ctx)); ngx_memzero(ctx, sizeof(*ctx));
ctx->session = s;
ctx->file.log = s->connection->log; ctx->file.log = s->connection->log;
name.len = ngx_strlen(v->name); name.len = ngx_strlen(v->name);
@ -528,6 +606,8 @@ ngx_rtmp_play_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v)
goto next; goto next;
} }
ngx_memcpy(ctx->name, name.data, name.len);
ctx->file.fd = NGX_INVALID_FILE; ctx->file.fd = NGX_INVALID_FILE;
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
@ -544,17 +624,21 @@ ngx_rtmp_play_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v)
sfx = &nosfx; sfx = &nosfx;
} }
if (ngx_rtmp_play_join(s) != NGX_OK) {
return NGX_ERROR;
}
/* remote? */ /* remote? */
if (pacf->url) { if (pacf->url) {
ctx->name.data = ngx_palloc(s->connection->pool, name.len + sfx->len); ctx->fname.data = ngx_palloc(s->connection->pool, name.len + sfx->len);
if (ctx->name.data == NULL) { if (ctx->fname.data == NULL) {
return NGX_ERROR; return NGX_ERROR;
} }
p = ngx_sprintf(ctx->name.data, "%V%V", &name, sfx); p = ngx_sprintf(ctx->fname.data, "%V%V", &name, sfx);
*p = 0; *p = 0;
ctx->name.len = p - ctx->name.data; ctx->fname.len = p - ctx->fname.data;
return ngx_rtmp_play_open_remote(s, v); return ngx_rtmp_play_open_remote(s, v);
} }
@ -654,7 +738,7 @@ ngx_rtmp_play_remote_create(ngx_rtmp_session_t *s, void *arg, ngx_pool_t *pool)
args_len = ngx_strlen(v->args); args_len = ngx_strlen(v->args);
addr_text = &s->connection->addr_text; addr_text = &s->connection->addr_text;
len = pacf->url->uri.len + 1 + ctx->name.len + len = pacf->url->uri.len + 1 + ctx->fname.len +
sizeof("?addr=") + addr_text->len * 3 + sizeof("?addr=") + addr_text->len * 3 +
1 + args_len; 1 + args_len;
@ -671,7 +755,7 @@ ngx_rtmp_play_remote_create(ngx_rtmp_session_t *s, void *arg, ngx_pool_t *pool)
*p++ = '/'; *p++ = '/';
} }
p = ngx_cpymem(p, ctx->name.data, ctx->name.len); p = ngx_cpymem(p, ctx->fname.data, ctx->fname.len);
p = ngx_cpymem(p, (u_char*)"?addr=", sizeof("&addr=") -1); p = ngx_cpymem(p, (u_char*)"?addr=", sizeof("&addr=") -1);
p = (u_char*)ngx_escape_uri(p, addr_text->data, addr_text->len, p = (u_char*)ngx_escape_uri(p, addr_text->data, addr_text->len,
NGX_ESCAPE_ARGS); NGX_ESCAPE_ARGS);

View File

@ -8,6 +8,7 @@
#include "ngx_rtmp.h" #include "ngx_rtmp.h"
#include "ngx_rtmp_cmd_module.h"
typedef ngx_int_t (*ngx_rtmp_play_init_pt) (ngx_rtmp_session_t *s, typedef ngx_int_t (*ngx_rtmp_play_init_pt) (ngx_rtmp_session_t *s,
@ -38,20 +39,28 @@ typedef struct {
} ngx_rtmp_play_fmt_t; } ngx_rtmp_play_fmt_t;
typedef struct { typedef struct ngx_rtmp_play_ctx_s ngx_rtmp_play_ctx_t;
struct ngx_rtmp_play_ctx_s {
ngx_rtmp_session_t *session;
ngx_file_t file; ngx_file_t file;
ngx_rtmp_play_fmt_t *fmt; ngx_rtmp_play_fmt_t *fmt;
ngx_event_t send_evt; ngx_event_t send_evt;
unsigned playing:1; unsigned playing:1;
ngx_uint_t ncrs; ngx_uint_t ncrs;
ngx_str_t name; u_char name[NGX_RTMP_MAX_NAME];
} ngx_rtmp_play_ctx_t; ngx_str_t fname;
ngx_rtmp_play_ctx_t *next;
};
typedef struct { typedef struct {
ngx_str_t root; ngx_str_t root;
ngx_str_t temp_path; ngx_str_t temp_path;
ngx_url_t *url; ngx_url_t *url;
ngx_uint_t nbuckets;
ngx_rtmp_play_ctx_t **ctx;
} ngx_rtmp_play_app_conf_t; } ngx_rtmp_play_app_conf_t;

View File

@ -8,6 +8,7 @@
#include "ngx_rtmp.h" #include "ngx_rtmp.h"
#include "ngx_rtmp_live_module.h" #include "ngx_rtmp_live_module.h"
#include "ngx_rtmp_play_module.h"
#include "ngx_rtmp_codec_module.h" #include "ngx_rtmp_codec_module.h"
@ -15,15 +16,29 @@ static ngx_int_t ngx_rtmp_stat_postconfiguration(ngx_conf_t *cf);
static void * ngx_rtmp_stat_create_loc_conf(ngx_conf_t *cf); static void * ngx_rtmp_stat_create_loc_conf(ngx_conf_t *cf);
static char * ngx_rtmp_stat_merge_loc_conf(ngx_conf_t *cf, static char * ngx_rtmp_stat_merge_loc_conf(ngx_conf_t *cf,
void *parent, void *child); void *parent, void *child);
static ngx_int_t ngx_rtmp_stat_init_process(ngx_cycle_t *cycle);
static void ngx_rtmp_stat_main(ngx_pool_t *pool, ngx_chain_t ***lll);
static time_t start_time; static time_t start_time;
static ngx_str_t shm_name = ngx_string("rtmp_stat");
static ngx_shm_zone_t *shm_zone;
static ngx_slab_pool_t *shm_pool;
static ngx_buf_t *shm_map;
static ngx_event_t shm_evt;
static ngx_connection_t shm_dummy_conn;
static size_t shm_size = 1024 * 1024; /*TODO:tune*/
#define shm_map_size (sizeof(ngx_buf_t) * NGX_MAX_PROCESSES)
#define shm_update_timeout 1000
#define NGX_RTMP_STAT_ALL 0xff #define NGX_RTMP_STAT_ALL 0xff
#define NGX_RTMP_STAT_GLOBAL 0x01 #define NGX_RTMP_STAT_GLOBAL 0x01
#define NGX_RTMP_STAT_LIVE 0x02 #define NGX_RTMP_STAT_LIVE 0x02
#define NGX_RTMP_STAT_CLIENTS 0x04 #define NGX_RTMP_STAT_CLIENTS 0x04
#define NGX_RTMP_STAT_PLAY 0x08
/* /*
* global: stat-{bufs-{total,free,used}, total bytes in/out, bw in/out} - cscf * global: stat-{bufs-{total,free,used}, total bytes in/out, bw in/out} - cscf
@ -87,7 +102,7 @@ ngx_module_t ngx_rtmp_stat_module = {
NGX_HTTP_MODULE, /* module type */ NGX_HTTP_MODULE, /* module type */
NULL, /* init master */ NULL, /* init master */
NULL, /* init module */ NULL, /* init module */
NULL, /* init process */ ngx_rtmp_stat_init_process, /* init process */
NULL, /* init thread */ NULL, /* init thread */
NULL, /* exit thread */ NULL, /* exit thread */
NULL, /* exit process */ NULL, /* exit process */
@ -96,6 +111,123 @@ ngx_module_t ngx_rtmp_stat_module = {
}; };
static void
ngx_rtmp_stat_update(ngx_event_t *ev)
{
ngx_buf_t *b;
ngx_pool_t *pool;
ngx_chain_t *l, *cl, **ll, ***lll;
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, ev->log, 0,
"stat: updating slot %d",
(ngx_int_t) ngx_process_slot);
b = &shm_map[ngx_process_slot];
b->pos = b->last = b->start;
pool = ngx_create_pool(4096, ev->log);
if (pool == NULL) {
return;
}
cl = NULL;
ll = &cl;
lll = ≪
ngx_rtmp_stat_main(pool, lll);
for (l = cl; l; l = l->next) {
if (b->end - b->last < l->buf->last - l->buf->end) {
b->last = b->pos;
ngx_log_error(NGX_LOG_ERR, ev->log, 0,
"stat: not enough space for worker stat");
goto next;
}
b->last = ngx_cpymem(b->last, l->buf->pos,
(size_t) (l->buf->last - l->buf->pos));
}
next:
ngx_destroy_pool(pool);
ngx_add_timer(ev, shm_update_timeout);
}
static ngx_int_t
ngx_rtmp_stat_init_process(ngx_cycle_t *cycle)
{
ngx_buf_t *b;
size_t size;
ngx_core_conf_t *ccf;
start_time = ngx_cached_time->sec;
ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
if (ccf->worker_processes == 1) {
return NGX_OK;
}
if (shm_map == NULL) {
ngx_log_error(NGX_LOG_ERR, cycle->log, 0,
"stat: NULL shm_map");
return NGX_ERROR;
}
b = &shm_map[ngx_process_slot];
if (b->start) {
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, cycle->log, 0,
"stat: slot %d already allocated",
(ngx_int_t) ngx_process_slot);
goto schedule;
}
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, cycle->log, 0,
"stat: allocating slot %d",
(ngx_int_t) ngx_process_slot);
size = ((shm_size - shm_map_size) / ccf->worker_processes) &
~(ngx_pagesize - 1);
b->start= ngx_slab_alloc(shm_pool, size);
if (b->start == NULL) {
ngx_log_error(NGX_LOG_ERR, cycle->log, 0,
"stat: error allocating %d slot",
ngx_process_slot);
return NGX_ERROR;
}
b->end = b->start + size;
schedule:
b->pos = b->last = b->start;
shm_evt.log = cycle->log;
shm_evt.data = &shm_dummy_conn;
shm_evt.handler = ngx_rtmp_stat_update;
ngx_add_timer(&shm_evt, shm_update_timeout);
return NGX_OK;
}
static ngx_int_t
ngx_rtmp_stat_shm_init(ngx_shm_zone_t *shm_zone, void *data)
{
shm_pool = (ngx_slab_pool_t *) shm_zone->shm.addr;
shm_map = ngx_slab_alloc(shm_pool, shm_map_size);
if (shm_map == NULL) {
return NGX_ERROR;
}
ngx_memzero(shm_map, shm_map_size);
return NGX_OK;
}
#define NGX_RTMP_STAT_BUFSIZE 256 #define NGX_RTMP_STAT_BUFSIZE 256
@ -104,7 +236,7 @@ ngx_module_t ngx_rtmp_stat_module = {
* which are bad for xslt */ * which are bad for xslt */
static void * static void *
ngx_rtmp_stat_escape(ngx_http_request_t *r, void *data, size_t len) ngx_rtmp_stat_escape(ngx_pool_t *pool, void *data, size_t len)
{ {
u_char *p, *np; u_char *p, *np;
void *new_data; void *new_data;
@ -122,7 +254,7 @@ ngx_rtmp_stat_escape(ngx_http_request_t *r, void *data, size_t len)
return data; return data;
} }
new_data = ngx_palloc(r->pool, len); new_data = ngx_palloc(pool, len);
if (new_data == NULL) { if (new_data == NULL) {
return NULL; return NULL;
} }
@ -139,7 +271,7 @@ ngx_rtmp_stat_escape(ngx_http_request_t *r, void *data, size_t len)
static void static void
ngx_rtmp_stat_output(ngx_http_request_t *r, ngx_chain_t ***lll, ngx_rtmp_stat_output(ngx_pool_t *pool, ngx_chain_t ***lll,
void *data, size_t len, ngx_uint_t escape) void *data, size_t len, ngx_uint_t escape)
{ {
ngx_chain_t *cl; ngx_chain_t *cl;
@ -151,7 +283,7 @@ ngx_rtmp_stat_output(ngx_http_request_t *r, ngx_chain_t ***lll,
} }
if (escape) { if (escape) {
data = ngx_rtmp_stat_escape(r, data, len); data = ngx_rtmp_stat_escape(pool, data, len);
if (data == NULL) { if (data == NULL) {
return; return;
} }
@ -167,11 +299,11 @@ ngx_rtmp_stat_output(ngx_http_request_t *r, ngx_chain_t ***lll,
} }
if (**lll == NULL) { if (**lll == NULL) {
cl = ngx_alloc_chain_link(r->pool); cl = ngx_alloc_chain_link(pool);
if (cl == NULL) { if (cl == NULL) {
return; return;
} }
b = ngx_create_temp_buf(r->pool, b = ngx_create_temp_buf(pool,
ngx_max(NGX_RTMP_STAT_BUFSIZE, real_len)); ngx_max(NGX_RTMP_STAT_BUFSIZE, real_len));
if (b == NULL || b->pos == NULL) { if (b == NULL || b->pos == NULL) {
return; return;
@ -192,14 +324,16 @@ ngx_rtmp_stat_output(ngx_http_request_t *r, ngx_chain_t ***lll,
/* These shortcuts assume 2 variables exist in current context: /* These shortcuts assume 2 variables exist in current context:
* ngx_http_request_t *r * ngx_pool_t *pool
* ngx_chain_t ***lll */ * ngx_chain_t ***lll */
/* plain data */ /* plain data */
#define NGX_RTMP_STAT(data, len) ngx_rtmp_stat_output(r, lll, data, len, 0) #define NGX_RTMP_STAT(data, len) ngx_rtmp_stat_output(pool, lll, data, len,\
0)
/* escaped data */ /* escaped data */
#define NGX_RTMP_STAT_E(data, len) ngx_rtmp_stat_output(r, lll, data, len, 1) #define NGX_RTMP_STAT_E(data, len) ngx_rtmp_stat_output(pool, lll, data, len,\
1)
/* literal */ /* literal */
#define NGX_RTMP_STAT_L(s) NGX_RTMP_STAT((s), sizeof(s) - 1) #define NGX_RTMP_STAT_L(s) NGX_RTMP_STAT((s), sizeof(s) - 1)
@ -218,7 +352,7 @@ ngx_rtmp_stat_output(ngx_http_request_t *r, ngx_chain_t ***lll,
static void static void
ngx_rtmp_stat_bw(ngx_http_request_t *r, ngx_chain_t ***lll, ngx_rtmp_stat_bw(ngx_pool_t *pool, ngx_chain_t ***lll,
ngx_rtmp_bandwidth_t *bw_in, ngx_rtmp_bandwidth_t *bw_out) ngx_rtmp_bandwidth_t *bw_in, ngx_rtmp_bandwidth_t *bw_out)
{ {
u_char buf[NGX_OFF_T_LEN + 1]; u_char buf[NGX_OFF_T_LEN + 1];
@ -272,8 +406,8 @@ ngx_rtmp_stat_get_pool_size(ngx_pool_t *pool, ngx_uint_t *nlarge,
static void static void
ngx_rtmp_stat_dump_pool(ngx_http_request_t *r, ngx_chain_t ***lll, ngx_rtmp_stat_dump_pool(ngx_pool_t *pool, ngx_chain_t ***lll,
ngx_pool_t *pool) ngx_pool_t *p)
{ {
ngx_uint_t nlarge; ngx_uint_t nlarge;
size_t size; size_t size;
@ -281,7 +415,7 @@ ngx_rtmp_stat_dump_pool(ngx_http_request_t *r, ngx_chain_t ***lll,
size = 0; size = 0;
nlarge = 0; nlarge = 0;
ngx_rtmp_stat_get_pool_size(pool, &nlarge, &size); ngx_rtmp_stat_get_pool_size(p, &nlarge, &size);
NGX_RTMP_STAT_L("<pool><nlarge>"); NGX_RTMP_STAT_L("<pool><nlarge>");
NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf),
"%ui", nlarge) - buf); "%ui", nlarge) - buf);
@ -294,7 +428,51 @@ ngx_rtmp_stat_dump_pool(ngx_http_request_t *r, ngx_chain_t ***lll,
static void static void
ngx_rtmp_stat_live(ngx_http_request_t *r, ngx_chain_t ***lll, ngx_rtmp_stat_client(ngx_pool_t *pool, ngx_chain_t ***lll,
ngx_rtmp_session_t *s)
{
u_char buf[NGX_OFF_T_LEN + 1];
#ifdef NGX_RTMP_POOL_DEBUG
ngx_rtmp_stat_dump_pool(pool, lll, s->connection->pool);
#endif
NGX_RTMP_STAT_L("<id>");
NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), "%ui",
(ngx_uint_t) s->connection->number)
- buf);
NGX_RTMP_STAT_L("</id>");
NGX_RTMP_STAT_L("<address>");
NGX_RTMP_STAT_S(&s->connection->addr_text);
NGX_RTMP_STAT_L("</address>");
NGX_RTMP_STAT_L("<time>");
NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), "%M",
ngx_current_msec - s->epoch) - buf);
NGX_RTMP_STAT_L("</time>");
if (s->flashver.len) {
NGX_RTMP_STAT_L("<flashver>");
NGX_RTMP_STAT_ES(&s->flashver);
NGX_RTMP_STAT_L("</flashver>");
}
if (s->page_url.len) {
NGX_RTMP_STAT_L("<pageurl>");
NGX_RTMP_STAT_ES(&s->page_url);
NGX_RTMP_STAT_L("</pageurl>");
}
if (s->swf_url.len) {
NGX_RTMP_STAT_L("<swfurl>");
NGX_RTMP_STAT_ES(&s->swf_url);
NGX_RTMP_STAT_L("</swfurl>");
}
}
static void
ngx_rtmp_stat_live(ngx_pool_t *pool, ngx_chain_t ***lll,
ngx_rtmp_live_app_conf_t *lacf) ngx_rtmp_live_app_conf_t *lacf)
{ {
ngx_rtmp_live_stream_t *stream; ngx_rtmp_live_stream_t *stream;
@ -304,10 +482,11 @@ ngx_rtmp_stat_live(ngx_http_request_t *r, ngx_chain_t ***lll,
ngx_int_t n; ngx_int_t n;
size_t nclients, total_nclients; size_t nclients, total_nclients;
u_char buf[NGX_OFF_T_LEN + 1]; u_char buf[NGX_OFF_T_LEN + 1];
ngx_rtmp_stat_loc_conf_t *slcf;
u_char *cname; u_char *cname;
slcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_stat_module); if (!lacf->live) {
return;
}
NGX_RTMP_STAT_L("<live>\r\n"); NGX_RTMP_STAT_L("<live>\r\n");
@ -325,77 +504,41 @@ ngx_rtmp_stat_live(ngx_http_request_t *r, ngx_chain_t ***lll,
"%M", ngx_current_msec - stream->epoch) - buf); "%M", ngx_current_msec - stream->epoch) - buf);
NGX_RTMP_STAT_L("</time>"); NGX_RTMP_STAT_L("</time>");
ngx_rtmp_stat_bw(r, lll, &stream->bw_in, &stream->bw_out); ngx_rtmp_stat_bw(pool, lll, &stream->bw_in, &stream->bw_out);
nclients = 0; nclients = 0;
codec = NULL; codec = NULL;
for (ctx = stream->ctx; ctx; ctx = ctx->next, ++nclients) { for (ctx = stream->ctx; ctx; ctx = ctx->next, ++nclients) {
s = ctx->session; s = ctx->session;
if (slcf->stat & NGX_RTMP_STAT_CLIENTS) {
NGX_RTMP_STAT_L("<client>");
#ifdef NGX_RTMP_POOL_DEBUG NGX_RTMP_STAT_L("<client>");
ngx_rtmp_stat_dump_pool(r, lll, s->connection->pool);
#endif ngx_rtmp_stat_client(pool, lll, s);
NGX_RTMP_STAT_L("<id>");
NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), "%ui", NGX_RTMP_STAT_L("<dropped>");
(ngx_uint_t) s->connection->number) NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf),
"%uD", ctx->ndropped) - buf);
NGX_RTMP_STAT_L("</dropped>");
NGX_RTMP_STAT_L("<avsync>");
if (!lacf->interleave) {
NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf),
"%L", (int64_t) ctx->cs[1].timestamp -
(int64_t) ctx->cs[0].timestamp)
- buf); - buf);
NGX_RTMP_STAT_L("</id>");
NGX_RTMP_STAT_L("<address>");
NGX_RTMP_STAT_S(&s->connection->addr_text);
NGX_RTMP_STAT_L("</address>");
NGX_RTMP_STAT_L("<time>");
NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), "%M",
ngx_current_msec - s->epoch)
- buf);
NGX_RTMP_STAT_L("</time>");
NGX_RTMP_STAT_L("<dropped>");
NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), "%uD",
ctx->ndropped)
- buf);
NGX_RTMP_STAT_L("</dropped>");
NGX_RTMP_STAT_L("<avsync>");
if (!lacf->interleave) {
NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf),
"%L", (int64_t) ctx->cs[1].timestamp -
(int64_t) ctx->cs[0].timestamp)
- buf);
}
NGX_RTMP_STAT_L("</avsync>");
if (s->flashver.len) {
NGX_RTMP_STAT_L("<flashver>");
NGX_RTMP_STAT_ES(&s->flashver);
NGX_RTMP_STAT_L("</flashver>");
}
if (s->page_url.len) {
NGX_RTMP_STAT_L("<pageurl>");
NGX_RTMP_STAT_ES(&s->page_url);
NGX_RTMP_STAT_L("</pageurl>");
}
if (s->swf_url.len) {
NGX_RTMP_STAT_L("<swfurl>");
NGX_RTMP_STAT_ES(&s->swf_url);
NGX_RTMP_STAT_L("</swfurl>");
}
if (ctx->publishing) {
NGX_RTMP_STAT_L("<publishing/>");
}
if (ctx->active) {
NGX_RTMP_STAT_L("<active/>");
}
NGX_RTMP_STAT_L("</client>\r\n");
} }
NGX_RTMP_STAT_L("</avsync>");
if (ctx->publishing) {
NGX_RTMP_STAT_L("<publishing/>");
}
if (ctx->active) {
NGX_RTMP_STAT_L("<active/>");
}
NGX_RTMP_STAT_L("</client>\r\n");
if (ctx->publishing) { if (ctx->publishing) {
codec = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); codec = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module);
} }
@ -465,29 +608,87 @@ ngx_rtmp_stat_live(ngx_http_request_t *r, ngx_chain_t ***lll,
static void static void
ngx_rtmp_stat_application(ngx_http_request_t *r, ngx_chain_t ***lll, ngx_rtmp_stat_play(ngx_pool_t *pool, ngx_chain_t ***lll,
ngx_rtmp_play_app_conf_t *pacf)
{
ngx_rtmp_play_ctx_t *ctx, *sctx;
ngx_rtmp_session_t *s;
ngx_uint_t n;
size_t nclients, total_nclients;
u_char buf[NGX_OFF_T_LEN + 1];
if (pacf->root.len == 0 && pacf->url == NULL) {
return;
}
NGX_RTMP_STAT_L("<play>\r\n");
total_nclients = 0;
for (n = 0; n < pacf->nbuckets; ++n) {
for (ctx = pacf->ctx[n]; ctx; ) {
NGX_RTMP_STAT_L("<stream>\r\n");
NGX_RTMP_STAT_L("<name>");
NGX_RTMP_STAT_ECS(ctx->name);
NGX_RTMP_STAT_L("</name>\r\n");
nclients = 0;
sctx = ctx;
for (; ctx; ctx = ctx->next) {
if (ngx_strcmp(ctx->name, sctx->name)) {
break;
}
++nclients;
s = ctx->session;
NGX_RTMP_STAT_L("<client>");
ngx_rtmp_stat_client(pool, lll, s);
NGX_RTMP_STAT_L("</client>\r\n");
}
total_nclients += nclients;
NGX_RTMP_STAT_L("<active/>");
NGX_RTMP_STAT_L("<nclients>");
NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf),
"%uz", nclients) - buf);
NGX_RTMP_STAT_L("</nclients>\r\n");
NGX_RTMP_STAT_L("</stream>\r\n");
}
}
NGX_RTMP_STAT_L("<nclients>");
NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf),
"%uz", total_nclients) - buf);
NGX_RTMP_STAT_L("</nclients>\r\n");
NGX_RTMP_STAT_L("</play>\r\n");
}
static void
ngx_rtmp_stat_application(ngx_pool_t *pool, ngx_chain_t ***lll,
ngx_rtmp_core_app_conf_t *cacf) ngx_rtmp_core_app_conf_t *cacf)
{ {
ngx_rtmp_stat_loc_conf_t *slcf;
NGX_RTMP_STAT_L("<application>\r\n"); NGX_RTMP_STAT_L("<application>\r\n");
NGX_RTMP_STAT_L("<name>"); NGX_RTMP_STAT_L("<name>");
NGX_RTMP_STAT_ES(&cacf->name); NGX_RTMP_STAT_ES(&cacf->name);
NGX_RTMP_STAT_L("</name>\r\n"); NGX_RTMP_STAT_L("</name>\r\n");
slcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_stat_module); ngx_rtmp_stat_live(pool, lll,
cacf->app_conf[ngx_rtmp_live_module.ctx_index]);
if (slcf->stat & NGX_RTMP_STAT_LIVE) { ngx_rtmp_stat_play(pool, lll,
ngx_rtmp_stat_live(r, lll, cacf->app_conf[ngx_rtmp_play_module.ctx_index]);
cacf->app_conf[ngx_rtmp_live_module.ctx_index]);
}
NGX_RTMP_STAT_L("</application>\r\n"); NGX_RTMP_STAT_L("</application>\r\n");
} }
static void static void
ngx_rtmp_stat_server(ngx_http_request_t *r, ngx_chain_t ***lll, ngx_rtmp_stat_server(ngx_pool_t *pool, ngx_chain_t ***lll,
ngx_rtmp_core_srv_conf_t *cscf) ngx_rtmp_core_srv_conf_t *cscf)
{ {
ngx_rtmp_core_app_conf_t **cacf; ngx_rtmp_core_app_conf_t **cacf;
@ -496,29 +697,93 @@ ngx_rtmp_stat_server(ngx_http_request_t *r, ngx_chain_t ***lll,
NGX_RTMP_STAT_L("<server>\r\n"); NGX_RTMP_STAT_L("<server>\r\n");
#ifdef NGX_RTMP_POOL_DEBUG #ifdef NGX_RTMP_POOL_DEBUG
ngx_rtmp_stat_dump_pool(r, lll, cscf->pool); ngx_rtmp_stat_dump_pool(pool, lll, cscf->pool);
#endif #endif
cacf = cscf->applications.elts; cacf = cscf->applications.elts;
for (n = 0; n < cscf->applications.nelts; ++n, ++cacf) { for (n = 0; n < cscf->applications.nelts; ++n, ++cacf) {
ngx_rtmp_stat_application(r, lll, *cacf); ngx_rtmp_stat_application(pool, lll, *cacf);
} }
NGX_RTMP_STAT_L("</server>\r\n"); NGX_RTMP_STAT_L("</server>\r\n");
} }
static void
ngx_rtmp_stat_main(ngx_pool_t *pool, ngx_chain_t ***lll)
{
ngx_rtmp_core_main_conf_t *cmcf = ngx_rtmp_core_main_conf;
ngx_rtmp_core_srv_conf_t **cscf;
size_t n;
static u_char nbuf[NGX_OFF_T_LEN + 1];
static u_char tbuf[NGX_TIME_T_LEN + 1];
NGX_RTMP_STAT_L("<uptime>");
NGX_RTMP_STAT(tbuf, ngx_snprintf(tbuf, sizeof(tbuf),
"%T", ngx_cached_time->sec - start_time) - tbuf);
NGX_RTMP_STAT_L("</uptime>\r\n");
NGX_RTMP_STAT_L("<pid>");
NGX_RTMP_STAT(nbuf, ngx_snprintf(nbuf, sizeof(nbuf),
"%ui", (ngx_uint_t) ngx_getpid()) - nbuf);
NGX_RTMP_STAT_L("</pid>\r\n");
ngx_rtmp_stat_bw(pool, lll, &ngx_rtmp_bw_in, &ngx_rtmp_bw_out);
cscf = cmcf->servers.elts;
for (n = 0; n < cmcf->servers.nelts; ++n, ++cscf) {
ngx_rtmp_stat_server(pool, lll, *cscf);
}
}
static void
ngx_rtmp_stat_get(ngx_pool_t *pool, ngx_chain_t ***lll)
{
ngx_buf_t *b;
ngx_uint_t n;
static u_char nbuf[NGX_OFF_T_LEN + 1];
b = &shm_map[ngx_process_slot];
if (b->start == NULL) {
/* single-worker */
NGX_RTMP_STAT_L("<worker>\r\n");
ngx_rtmp_stat_main(pool, lll);
NGX_RTMP_STAT_L("</worker>\r\n");
return;
}
/* multi-worker */
b = &shm_map[0];
for (n = 0; n < NGX_MAX_PROCESSES; ++n, ++b) {
if (b->start == NULL) {
continue;
}
NGX_RTMP_STAT_L("<worker>\r\n");
NGX_RTMP_STAT_L("<n>");
NGX_RTMP_STAT(nbuf, ngx_snprintf(nbuf, sizeof(nbuf), "%ui", n + 1)
- nbuf);
NGX_RTMP_STAT_L("</n>\r\n");
NGX_RTMP_STAT(b->pos, b->last - b->pos);
NGX_RTMP_STAT_L("</worker>\r\n");
}
}
static ngx_int_t static ngx_int_t
ngx_rtmp_stat_handler(ngx_http_request_t *r) ngx_rtmp_stat_handler(ngx_http_request_t *r)
{ {
ngx_rtmp_stat_loc_conf_t *slcf; ngx_rtmp_stat_loc_conf_t *slcf;
ngx_rtmp_core_main_conf_t *cmcf;
ngx_rtmp_core_srv_conf_t **cscf;
ngx_chain_t *cl, *l, **ll, ***lll; ngx_chain_t *cl, *l, **ll, ***lll;
size_t n; ngx_pool_t *pool;
off_t len; off_t len;
static u_char tbuf[NGX_TIME_T_LEN + 1];
static u_char nbuf[NGX_OFF_T_LEN + 1]; pool = r->pool;
r->keepalive = 0; r->keepalive = 0;
slcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_stat_module); slcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_stat_module);
@ -526,8 +791,7 @@ ngx_rtmp_stat_handler(ngx_http_request_t *r)
return NGX_DECLINED; return NGX_DECLINED;
} }
cmcf = ngx_rtmp_core_main_conf; if (ngx_rtmp_core_main_conf == NULL) {
if (cmcf == NULL) {
goto error; goto error;
} }
@ -553,22 +817,7 @@ ngx_rtmp_stat_handler(ngx_http_request_t *r)
#endif #endif
NGX_RTMP_STAT_L("<built>" __DATE__ " " __TIME__ "</built>\r\n"); NGX_RTMP_STAT_L("<built>" __DATE__ " " __TIME__ "</built>\r\n");
NGX_RTMP_STAT_L("<pid>"); ngx_rtmp_stat_get(r->pool, lll);
NGX_RTMP_STAT(nbuf, ngx_snprintf(nbuf, sizeof(nbuf),
"%ui", (ngx_uint_t) ngx_getpid()) - nbuf);
NGX_RTMP_STAT_L("</pid>\r\n");
NGX_RTMP_STAT_L("<uptime>");
NGX_RTMP_STAT(tbuf, ngx_snprintf(tbuf, sizeof(tbuf),
"%T", ngx_cached_time->sec - start_time) - tbuf);
NGX_RTMP_STAT_L("</uptime>\r\n");
ngx_rtmp_stat_bw(r, lll, &ngx_rtmp_bw_in, &ngx_rtmp_bw_out);
cscf = cmcf->servers.elts;
for (n = 0; n < cmcf->servers.nelts; ++n, ++cscf) {
ngx_rtmp_stat_server(r, lll, *cscf);
}
NGX_RTMP_STAT_L("</rtmp>\r\n"); NGX_RTMP_STAT_L("</rtmp>\r\n");
@ -633,8 +882,15 @@ ngx_rtmp_stat_postconfiguration(ngx_conf_t *cf)
} }
*h = ngx_rtmp_stat_handler; *h = ngx_rtmp_stat_handler;
start_time = ngx_cached_time->sec; if (shm_zone == NULL) {
shm_zone = ngx_shared_memory_add(cf, &shm_name, shm_size +
ngx_pagesize, &ngx_rtmp_stat_module);
if (shm_zone == NULL) {
return NGX_ERROR;
}
shm_zone->init = ngx_rtmp_stat_shm_init;
}
return NGX_OK; return NGX_OK;
} }

View File

@ -13,7 +13,6 @@
<hr/> <hr/>
Generated by <a href='https://github.com/arut/nginx-rtmp-module'>NGINX RTMP module</a>, Generated by <a href='https://github.com/arut/nginx-rtmp-module'>NGINX RTMP module</a>,
<a href="http://nginx.com">NGINX</a>&#160;<xsl:value-of select="/rtmp/version"/>, <a href="http://nginx.com">NGINX</a>&#160;<xsl:value-of select="/rtmp/version"/>,
pid <xsl:value-of select="/rtmp/pid"/>,
built <xsl:value-of select="/rtmp/built"/>&#160;<xsl:value-of select="/rtmp/compiler"/> built <xsl:value-of select="/rtmp/built"/>&#160;<xsl:value-of select="/rtmp/compiler"/>
</body> </body>
</html> </html>
@ -35,23 +34,28 @@
<th>State</th> <th>State</th>
<th>Time</th> <th>Time</th>
</tr> </tr>
<tr> <xsl:apply-templates select="worker"/>
<td colspan="2"/>
<td><xsl:value-of select="in"/></td>
<td><xsl:value-of select="out"/></td>
<td><xsl:value-of select="round(bwin div 1024)"/></td>
<td><xsl:value-of select="round(bwout div 1024)"/></td>
<td colspan="5"/>
<td>
<xsl:call-template name="showtime">
<xsl:with-param name="time" select="/rtmp/uptime * 1000"/>
</xsl:call-template>
</td>
</tr>
<xsl:apply-templates select="server"/>
</table> </table>
</xsl:template> </xsl:template>
<xsl:template match="worker">
<tr bgcolor="#666666"><td colspan="12"/></tr>
<tr bgcolor="#aaaaaa">
<td colspan="2"><b>Worker #<xsl:value-of select="n"/></b>, pid <xsl:value-of select="pid"/></td>
<td><xsl:value-of select="in"/></td>
<td><xsl:value-of select="out"/></td>
<td><xsl:value-of select="round(bwin div 1024)"/></td>
<td><xsl:value-of select="round(bwout div 1024)"/></td>
<td colspan="5"/>
<td>
<xsl:call-template name="showtime">
<xsl:with-param name="time" select="uptime * 1000"/>
</xsl:call-template>
</td>
</tr>
<xsl:apply-templates select="server"/>
</xsl:template>
<xsl:template match="server"> <xsl:template match="server">
<xsl:apply-templates select="application"/> <xsl:apply-templates select="application"/>
</xsl:template> </xsl:template>
@ -63,6 +67,7 @@
</td> </td>
</tr> </tr>
<xsl:apply-templates select="live"/> <xsl:apply-templates select="live"/>
<xsl:apply-templates select="play"/>
</xsl:template> </xsl:template>
<xsl:template match="live"> <xsl:template match="live">
@ -77,6 +82,18 @@
<xsl:apply-templates select="stream"/> <xsl:apply-templates select="stream"/>
</xsl:template> </xsl:template>
<xsl:template match="play">
<tr bgcolor="#aaaaaa">
<td>
<i>VOD streams</i>
</td>
<td align="middle">
<xsl:value-of select="nclients"/>
</td>
</tr>
<xsl:apply-templates select="stream"/>
</xsl:template>
<xsl:template match="stream"> <xsl:template match="stream">
<tr valign="top"> <tr valign="top">
<xsl:attribute name="bgcolor"> <xsl:attribute name="bgcolor">
@ -88,7 +105,7 @@
<td> <td>
<a href=""> <a href="">
<xsl:attribute name="onclick"> <xsl:attribute name="onclick">
var d=document.getElementById('<xsl:value-of select="../../name"/>-<xsl:value-of select="name"/>'); var d=document.getElementById('<xsl:value-of select="../../../../n"/>-<xsl:value-of select="../../name"/>-<xsl:value-of select="name"/>');
d.style.display=d.style.display=='none'?'':'none'; d.style.display=d.style.display=='none'?'':'none';
return false return false
</xsl:attribute> </xsl:attribute>
@ -120,7 +137,7 @@
</tr> </tr>
<tr style="display:none"> <tr style="display:none">
<xsl:attribute name="id"> <xsl:attribute name="id">
<xsl:value-of select="../../name"/>-<xsl:value-of select="name"/> <xsl:value-of select="../../../../n"/>-<xsl:value-of select="../../name"/>-<xsl:value-of select="name"/>
</xsl:attribute> </xsl:attribute>
<td colspan="12" ngcolor="#eeeeee"> <td colspan="12" ngcolor="#eeeeee">
<table cellspacing="1" cellpadding="5"> <table cellspacing="1" cellpadding="5">