mirror of
https://github.com/zotanmew/nginx-rtmp-module.git
synced 2024-05-16 08:41:08 +02:00
Merge branch 'master' into exec-static
This commit is contained in:
commit
2741432356
5
TODO
5
TODO
|
@ -1,12 +1,11 @@
|
|||
- access log
|
||||
- improve session epoch variable
|
||||
|
||||
- rooms (+force pull)
|
||||
- exec_init
|
||||
|
||||
- fix auto-pushing to cache manager
|
||||
|
||||
- HDS
|
||||
|
||||
|
||||
- DNS round-robin url
|
||||
|
||||
- multiple streams per connection
|
||||
|
|
2
config
2
config
|
@ -17,6 +17,7 @@ CORE_MODULES="$CORE_MODULES
|
|||
ngx_rtmp_auto_push_module \
|
||||
ngx_rtmp_enotify_module \
|
||||
ngx_rtmp_notify_module \
|
||||
ngx_rtmp_log_module \
|
||||
"
|
||||
|
||||
|
||||
|
@ -70,6 +71,7 @@ NGX_ADDON_SRCS="$NGX_ADDON_SRCS \
|
|||
$ngx_addon_dir/ngx_rtmp_auto_push_module.c \
|
||||
$ngx_addon_dir/ngx_rtmp_enotify_module.c \
|
||||
$ngx_addon_dir/ngx_rtmp_notify_module.c \
|
||||
$ngx_addon_dir/ngx_rtmp_log_module.c \
|
||||
"
|
||||
CFLAGS="$CFLAGS -I$ngx_addon_dir"
|
||||
|
||||
|
|
|
@ -43,7 +43,13 @@ ngx_rtmp_hls_av_log_callback(void* avcl, int level, const char* fmt,
|
|||
}
|
||||
}
|
||||
|
||||
ngx_log_error_core(NGX_LOG_ERR, ngx_rtmp_hls_log, 0, "hls: av: %s", buf);
|
||||
if (level <= AV_LOG_ERROR) {
|
||||
ngx_log_error_core(NGX_LOG_ERR, ngx_rtmp_hls_log, 0, "hls: av: %s",
|
||||
buf);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, ngx_rtmp_hls_log, 0, "hls: av: %s", buf);
|
||||
}
|
||||
|
||||
|
||||
|
@ -88,6 +94,7 @@ typedef struct {
|
|||
ngx_msec_t sync;
|
||||
ngx_msec_t playlen;
|
||||
size_t nfrags;
|
||||
ngx_flag_t continuous;
|
||||
ngx_rtmp_hls_ctx_t **ctx;
|
||||
ngx_uint_t nbuckets;
|
||||
ngx_str_t path;
|
||||
|
@ -138,6 +145,12 @@ static ngx_command_t ngx_rtmp_hls_commands[] = {
|
|||
offsetof(ngx_rtmp_hls_app_conf_t, sync),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("hls_continuous"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_flag_slot,
|
||||
NGX_RTMP_APP_CONF_OFFSET,
|
||||
offsetof(ngx_rtmp_hls_app_conf_t, continuous),
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
@ -418,6 +431,7 @@ retry:
|
|||
p = ngx_snprintf(buffer, sizeof(buffer),
|
||||
"#EXTM3U\r\n"
|
||||
"#EXT-X-TARGETDURATION:%i\r\n"
|
||||
"#EXT-X-ALLOW-CACHE:NO\r\n"
|
||||
"#EXT-X-MEDIA-SEQUENCE:%i\r\n\r\n",
|
||||
/*TODO: float*/(ngx_int_t)(hacf->fraglen / 1000), ffrag);
|
||||
n = write(fd, buffer, p - buffer);
|
||||
|
@ -796,6 +810,71 @@ ngx_rtmp_hls_restart(ngx_rtmp_session_t *s)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_rtmp_hls_restore_frag(ngx_rtmp_session_t *s)
|
||||
{
|
||||
ngx_rtmp_hls_ctx_t *ctx;
|
||||
ngx_file_t file;
|
||||
ngx_file_info_t fi;
|
||||
ssize_t ret;
|
||||
u_char *p, *last;
|
||||
u_char buffer[sizeof("-.ts\r\n") +
|
||||
NGX_OFF_T_LEN];
|
||||
|
||||
/* try to restore frag from previously stored playlist */
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module);
|
||||
|
||||
ngx_memzero(&file, sizeof(file));
|
||||
|
||||
file.log = s->connection->log;
|
||||
|
||||
file.fd = ngx_open_file(ctx->playlist.data, NGX_FILE_RDONLY, NGX_FILE_OPEN,
|
||||
0);
|
||||
if (file.fd == NGX_INVALID_FILE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngx_fd_info(file.fd, &fi)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = ngx_read_file(&file, buffer, sizeof(buffer),
|
||||
fi.st_size > (off_t) sizeof(buffer) ?
|
||||
fi.st_size - sizeof(buffer) : 0);
|
||||
if (ret <= 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* last line example:
|
||||
* mystream-14.ts\r\n */
|
||||
|
||||
if (ret < (ssize_t) sizeof(".ts\r\n")) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret -= (sizeof(".ts\r\n") - 1);
|
||||
|
||||
last = buffer + ret;
|
||||
p = last;
|
||||
while (p > buffer && *(p - 1) != '-') {
|
||||
--p;
|
||||
}
|
||||
|
||||
if (p == buffer) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ctx->frag = ngx_atoi(p, (size_t) (last - p)) + 1;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"hls: restored frag=%i", ctx->frag);
|
||||
|
||||
done:
|
||||
ngx_close_file(file.fd);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_hls_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
|
||||
{
|
||||
|
@ -866,6 +945,10 @@ ngx_rtmp_hls_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
|
|||
"hls: playlist='%V' playlist_bak='%V' stream_pattern='%V'",
|
||||
&ctx->playlist, &ctx->playlist_bak, &ctx->stream);
|
||||
|
||||
if (hacf->continuous) {
|
||||
ngx_rtmp_hls_restore_frag(s);
|
||||
}
|
||||
|
||||
/* schedule restart event */
|
||||
ctx->publishing = 1;
|
||||
ctx->frag_start = ngx_current_msec - hacf->fraglen - 1;
|
||||
|
@ -1164,6 +1247,7 @@ ngx_rtmp_hls_create_app_conf(ngx_conf_t *cf)
|
|||
conf->muxdelay = NGX_CONF_UNSET;
|
||||
conf->sync = NGX_CONF_UNSET;
|
||||
conf->playlen = NGX_CONF_UNSET;
|
||||
conf->continuous = NGX_CONF_UNSET;
|
||||
conf->nbuckets = 1024;
|
||||
|
||||
return conf;
|
||||
|
@ -1179,9 +1263,10 @@ ngx_rtmp_hls_merge_app_conf(ngx_conf_t *cf, void *parent, void *child)
|
|||
ngx_conf_merge_value(conf->hls, prev->hls, 0);
|
||||
ngx_conf_merge_msec_value(conf->fraglen, prev->fraglen, 5000);
|
||||
ngx_conf_merge_msec_value(conf->muxdelay, prev->muxdelay, 700);
|
||||
ngx_conf_merge_msec_value(conf->sync, prev->sync, 0);
|
||||
ngx_conf_merge_msec_value(conf->sync, prev->sync, 300);
|
||||
ngx_conf_merge_msec_value(conf->playlen, prev->playlen, 30000);
|
||||
ngx_conf_merge_str_value(conf->path, prev->path, "");
|
||||
ngx_conf_merge_value(conf->continuous, prev->continuous, 0);
|
||||
conf->ctx = ngx_pcalloc(cf->pool,
|
||||
sizeof(ngx_rtmp_hls_ctx_t *) * conf->nbuckets);
|
||||
if (conf->ctx == NULL) {
|
||||
|
|
|
@ -214,6 +214,7 @@ typedef struct {
|
|||
/* auto-pushed? */
|
||||
unsigned auto_pushed:1;
|
||||
unsigned relay:1;
|
||||
unsigned static_relay:1;
|
||||
|
||||
/* input stream 0 (reserved by RTMP spec)
|
||||
* is used as free chain link */
|
||||
|
@ -232,6 +233,7 @@ typedef struct {
|
|||
|
||||
/* circular buffer of RTMP message pointers */
|
||||
ngx_msec_t timeout;
|
||||
uint32_t out_bytes;
|
||||
size_t out_pos, out_last;
|
||||
ngx_chain_t *out_chain;
|
||||
u_char *out_bpos;
|
||||
|
@ -309,7 +311,7 @@ typedef struct {
|
|||
typedef struct {
|
||||
ngx_str_t *client;
|
||||
ngx_rtmp_session_t *session;
|
||||
} ngx_rtmp_log_ctx_t;
|
||||
} ngx_rtmp_error_log_ctx_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -401,7 +401,7 @@ ngx_rtmp_auto_push_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
|
|||
ngx_rtmp_auto_push_conf_t *apcf;
|
||||
ngx_rtmp_auto_push_ctx_t *ctx;
|
||||
|
||||
if (s->auto_pushed || s->relay) {
|
||||
if (s->auto_pushed || (s->relay && !s->static_relay)) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,21 +10,51 @@
|
|||
#define NGX_RTMP_CAPABILITIES 31
|
||||
|
||||
|
||||
ngx_rtmp_connect_pt ngx_rtmp_connect;
|
||||
ngx_rtmp_create_stream_pt ngx_rtmp_create_stream;
|
||||
ngx_rtmp_close_stream_pt ngx_rtmp_close_stream;
|
||||
ngx_rtmp_delete_stream_pt ngx_rtmp_delete_stream;
|
||||
ngx_rtmp_publish_pt ngx_rtmp_publish;
|
||||
ngx_rtmp_play_pt ngx_rtmp_play;
|
||||
ngx_rtmp_seek_pt ngx_rtmp_seek;
|
||||
ngx_rtmp_pause_pt ngx_rtmp_pause;
|
||||
static ngx_int_t ngx_rtmp_cmd_connect(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_connect_t *v);
|
||||
static ngx_int_t ngx_rtmp_cmd_create_stream(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_create_stream_t *v);
|
||||
static ngx_int_t ngx_rtmp_cmd_close_stream(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_close_stream_t *v);
|
||||
static ngx_int_t ngx_rtmp_cmd_delete_stream(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_delete_stream_t *v);
|
||||
static ngx_int_t ngx_rtmp_cmd_publish(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_publish_t *v);
|
||||
static ngx_int_t ngx_rtmp_cmd_play(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_play_t *v);
|
||||
static ngx_int_t ngx_rtmp_cmd_seek(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_seek_t *v);
|
||||
static ngx_int_t ngx_rtmp_cmd_pause(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_pause_t *v);
|
||||
|
||||
|
||||
ngx_rtmp_stream_begin_pt ngx_rtmp_stream_begin;
|
||||
ngx_rtmp_stream_eof_pt ngx_rtmp_stream_eof;
|
||||
ngx_rtmp_stream_dry_pt ngx_rtmp_stream_dry;
|
||||
ngx_rtmp_recorded_pt ngx_rtmp_recorded;
|
||||
ngx_rtmp_set_buflen_pt ngx_rtmp_set_buflen;
|
||||
static ngx_int_t ngx_rtmp_cmd_stream_begin(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_stream_begin_t *v);
|
||||
static ngx_int_t ngx_rtmp_cmd_stream_eof(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_stream_eof_t *v);
|
||||
static ngx_int_t ngx_rtmp_cmd_stream_dry(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_stream_dry_t *v);
|
||||
static ngx_int_t ngx_rtmp_cmd_recorded(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_recorded_t *v);
|
||||
static ngx_int_t ngx_rtmp_cmd_set_buflen(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_set_buflen_t *v);
|
||||
|
||||
|
||||
ngx_rtmp_connect_pt ngx_rtmp_connect = ngx_rtmp_cmd_connect;
|
||||
ngx_rtmp_create_stream_pt ngx_rtmp_create_stream = ngx_rtmp_cmd_create_stream;
|
||||
ngx_rtmp_close_stream_pt ngx_rtmp_close_stream = ngx_rtmp_cmd_close_stream;
|
||||
ngx_rtmp_delete_stream_pt ngx_rtmp_delete_stream = ngx_rtmp_cmd_delete_stream;
|
||||
ngx_rtmp_publish_pt ngx_rtmp_publish = ngx_rtmp_cmd_publish;
|
||||
ngx_rtmp_play_pt ngx_rtmp_play = ngx_rtmp_cmd_play;
|
||||
ngx_rtmp_seek_pt ngx_rtmp_seek = ngx_rtmp_cmd_seek;
|
||||
ngx_rtmp_pause_pt ngx_rtmp_pause = ngx_rtmp_cmd_pause;
|
||||
|
||||
|
||||
ngx_rtmp_stream_begin_pt ngx_rtmp_stream_begin = ngx_rtmp_cmd_stream_begin;
|
||||
ngx_rtmp_stream_eof_pt ngx_rtmp_stream_eof = ngx_rtmp_cmd_stream_eof;
|
||||
ngx_rtmp_stream_dry_pt ngx_rtmp_stream_dry = ngx_rtmp_cmd_stream_dry;
|
||||
ngx_rtmp_recorded_pt ngx_rtmp_recorded = ngx_rtmp_cmd_recorded;
|
||||
ngx_rtmp_set_buflen_pt ngx_rtmp_set_buflen = ngx_rtmp_cmd_set_buflen;
|
||||
|
||||
|
||||
static ngx_int_t ngx_rtmp_cmd_postconfiguration(ngx_conf_t *cf);
|
||||
|
@ -134,8 +164,8 @@ ngx_rtmp_cmd_connect(ngx_rtmp_session_t *s, ngx_rtmp_connect_t *v)
|
|||
ngx_rtmp_core_srv_conf_t *cscf;
|
||||
ngx_rtmp_core_app_conf_t **cacfp;
|
||||
ngx_uint_t n;
|
||||
size_t len;
|
||||
ngx_rtmp_header_t h;
|
||||
u_char *p;
|
||||
|
||||
static double trans;
|
||||
static double capabilities = NGX_RTMP_CAPABILITIES;
|
||||
|
@ -229,16 +259,19 @@ ngx_rtmp_cmd_connect(ngx_rtmp_session_t *s, ngx_rtmp_connect_t *v)
|
|||
|
||||
#undef NGX_RTMP_SET_STRPAR
|
||||
|
||||
p = ngx_strlchr(s->app.data, s->app.data + s->app.len, '?');
|
||||
if (p) {
|
||||
s->app.len = (p - s->app.data);
|
||||
}
|
||||
|
||||
s->acodecs = v->acodecs;
|
||||
s->vcodecs = v->vcodecs;
|
||||
|
||||
/* find application & set app_conf */
|
||||
len = ngx_strlen(v->app);
|
||||
|
||||
cacfp = cscf->applications.elts;
|
||||
for(n = 0; n < cscf->applications.nelts; ++n, ++cacfp) {
|
||||
if ((*cacfp)->name.len == len
|
||||
&& !ngx_strncmp((*cacfp)->name.data, v->app, len))
|
||||
if ((*cacfp)->name.len == s->app.len &&
|
||||
ngx_strncmp((*cacfp)->name.data, s->app.data, s->app.len) == 0)
|
||||
{
|
||||
/* found app! */
|
||||
s->app_conf = (*cacfp)->app_conf;
|
||||
|
@ -248,7 +281,7 @@ ngx_rtmp_cmd_connect(ngx_rtmp_session_t *s, ngx_rtmp_connect_t *v)
|
|||
|
||||
if (s->app_conf == NULL) {
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"connect: application not found: '%s'", v->app);
|
||||
"connect: application not found: '%V'", &s->app);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
|
@ -721,22 +754,5 @@ ngx_rtmp_cmd_postconfiguration(ngx_conf_t *cf)
|
|||
*ch = *bh;
|
||||
}
|
||||
|
||||
/* set initial handlers */
|
||||
|
||||
ngx_rtmp_connect = ngx_rtmp_cmd_connect;
|
||||
ngx_rtmp_create_stream = ngx_rtmp_cmd_create_stream;
|
||||
ngx_rtmp_close_stream = ngx_rtmp_cmd_close_stream;
|
||||
ngx_rtmp_delete_stream = ngx_rtmp_cmd_delete_stream;
|
||||
ngx_rtmp_publish = ngx_rtmp_cmd_publish;
|
||||
ngx_rtmp_play = ngx_rtmp_cmd_play;
|
||||
ngx_rtmp_seek = ngx_rtmp_cmd_seek;
|
||||
ngx_rtmp_pause = ngx_rtmp_cmd_pause;
|
||||
|
||||
ngx_rtmp_stream_begin = ngx_rtmp_cmd_stream_begin;
|
||||
ngx_rtmp_stream_eof = ngx_rtmp_cmd_stream_eof;
|
||||
ngx_rtmp_stream_dry = ngx_rtmp_cmd_stream_dry;
|
||||
ngx_rtmp_recorded = ngx_rtmp_cmd_recorded;
|
||||
ngx_rtmp_set_buflen = ngx_rtmp_cmd_set_buflen;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,8 @@ static ngx_int_t ngx_rtmp_flv_postconfiguration(ngx_conf_t *cf);
|
|||
static void ngx_rtmp_flv_read_meta(ngx_rtmp_session_t *s, ngx_file_t *f);
|
||||
static ngx_int_t ngx_rtmp_flv_timestamp_to_offset(ngx_rtmp_session_t *s,
|
||||
ngx_file_t *f, ngx_int_t timestamp);
|
||||
static ngx_int_t ngx_rtmp_flv_init(ngx_rtmp_session_t *s, ngx_file_t *f);
|
||||
static ngx_int_t ngx_rtmp_flv_init(ngx_rtmp_session_t *s, ngx_file_t *f,
|
||||
ngx_int_t aindex, ngx_int_t vindex);
|
||||
static ngx_int_t ngx_rtmp_flv_start(ngx_rtmp_session_t *s, ngx_file_t *f);
|
||||
static ngx_int_t ngx_rtmp_flv_seek(ngx_rtmp_session_t *s, ngx_file_t *f,
|
||||
ngx_uint_t offset);
|
||||
|
@ -548,7 +549,8 @@ next:
|
|||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_flv_init(ngx_rtmp_session_t *s, ngx_file_t *f)
|
||||
ngx_rtmp_flv_init(ngx_rtmp_session_t *s, ngx_file_t *f, ngx_int_t aindex,
|
||||
ngx_int_t vindex)
|
||||
{
|
||||
ngx_rtmp_flv_ctx_t *ctx;
|
||||
|
||||
|
|
|
@ -521,6 +521,7 @@ ngx_rtmp_send(ngx_event_t *wev)
|
|||
return;
|
||||
}
|
||||
|
||||
s->out_bytes += n;
|
||||
s->ping_reset = 1;
|
||||
ngx_rtmp_update_bandwidth(&ngx_rtmp_bw_out, n);
|
||||
s->out_bpos += n;
|
||||
|
|
|
@ -133,7 +133,7 @@ ngx_rtmp_init_session(ngx_connection_t *c, ngx_rtmp_addr_conf_t *addr_conf)
|
|||
{
|
||||
ngx_rtmp_session_t *s;
|
||||
ngx_rtmp_core_srv_conf_t *cscf;
|
||||
ngx_rtmp_log_ctx_t *ctx;
|
||||
ngx_rtmp_error_log_ctx_t *ctx;
|
||||
|
||||
s = ngx_pcalloc(c->pool, sizeof(ngx_rtmp_session_t) +
|
||||
sizeof(ngx_chain_t *) * ((ngx_rtmp_core_srv_conf_t *)
|
||||
|
@ -152,7 +152,7 @@ ngx_rtmp_init_session(ngx_connection_t *c, ngx_rtmp_addr_conf_t *addr_conf)
|
|||
c->data = s;
|
||||
s->connection = c;
|
||||
|
||||
ctx = ngx_palloc(c->pool, sizeof(ngx_rtmp_log_ctx_t));
|
||||
ctx = ngx_palloc(c->pool, sizeof(ngx_rtmp_error_log_ctx_t));
|
||||
if (ctx == NULL) {
|
||||
ngx_rtmp_close_connection(c);
|
||||
return NULL;
|
||||
|
@ -202,9 +202,9 @@ ngx_rtmp_init_session(ngx_connection_t *c, ngx_rtmp_addr_conf_t *addr_conf)
|
|||
static u_char *
|
||||
ngx_rtmp_log_error(ngx_log_t *log, u_char *buf, size_t len)
|
||||
{
|
||||
u_char *p;
|
||||
ngx_rtmp_session_t *s;
|
||||
ngx_rtmp_log_ctx_t *ctx;
|
||||
u_char *p;
|
||||
ngx_rtmp_session_t *s;
|
||||
ngx_rtmp_error_log_ctx_t *ctx;
|
||||
|
||||
if (log->action) {
|
||||
p = ngx_snprintf(buf, len, " while %s", log->action);
|
||||
|
@ -239,6 +239,10 @@ ngx_rtmp_close_connection(ngx_connection_t *c)
|
|||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, c->log, 0, "close connection");
|
||||
|
||||
#if (NGX_STAT_STUB)
|
||||
(void) ngx_atomic_fetch_add(ngx_stat_active, -1);
|
||||
#endif
|
||||
|
||||
pool = c->pool;
|
||||
ngx_close_connection(c);
|
||||
ngx_destroy_pool(pool);
|
||||
|
|
|
@ -179,7 +179,7 @@ ngx_rtmp_live_merge_app_conf(ngx_conf_t *cf, void *parent, void *child)
|
|||
ngx_conf_merge_value(conf->wait_key, prev->wait_key, 0);
|
||||
ngx_conf_merge_value(conf->wait_video, prev->wait_video, 0);
|
||||
ngx_conf_merge_value(conf->publish_notify, prev->publish_notify, 0);
|
||||
ngx_conf_merge_value(conf->play_restart, prev->play_restart, 1);
|
||||
ngx_conf_merge_value(conf->play_restart, prev->play_restart, 0);
|
||||
|
||||
conf->pool = ngx_create_pool(4096, &cf->cycle->new_log);
|
||||
if (conf->pool == NULL) {
|
||||
|
|
988
ngx_rtmp_log_module.c
Normal file
988
ngx_rtmp_log_module.c
Normal file
|
@ -0,0 +1,988 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Roman Arutyunyan
|
||||
*/
|
||||
|
||||
|
||||
#include "ngx_rtmp_cmd_module.h"
|
||||
|
||||
|
||||
static ngx_rtmp_publish_pt next_publish;
|
||||
static ngx_rtmp_play_pt next_play;
|
||||
|
||||
|
||||
static ngx_int_t ngx_rtmp_log_postconfiguration(ngx_conf_t *cf);
|
||||
static void *ngx_rtmp_log_create_main_conf(ngx_conf_t *cf);
|
||||
static void * ngx_rtmp_log_create_app_conf(ngx_conf_t *cf);
|
||||
static char * ngx_rtmp_log_merge_app_conf(ngx_conf_t *cf,
|
||||
void *parent, void *child);
|
||||
static char * ngx_rtmp_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
static char * ngx_rtmp_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
static char * ngx_rtmp_log_compile_format(ngx_conf_t *cf, ngx_array_t *ops,
|
||||
ngx_array_t *args, ngx_uint_t s);
|
||||
|
||||
|
||||
typedef struct ngx_rtmp_log_op_s ngx_rtmp_log_op_t;
|
||||
|
||||
|
||||
typedef size_t (*ngx_rtmp_log_op_getlen_pt)(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_log_op_t *op);
|
||||
typedef u_char * (*ngx_rtmp_log_op_getdata_pt)(ngx_rtmp_session_t *s,
|
||||
u_char *buf, ngx_rtmp_log_op_t *log);
|
||||
|
||||
|
||||
struct ngx_rtmp_log_op_s {
|
||||
ngx_rtmp_log_op_getlen_pt getlen;
|
||||
ngx_rtmp_log_op_getdata_pt getdata;
|
||||
ngx_str_t value;
|
||||
ngx_uint_t offset;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t name;
|
||||
ngx_rtmp_log_op_getlen_pt getlen;
|
||||
ngx_rtmp_log_op_getdata_pt getdata;
|
||||
ngx_uint_t offset;
|
||||
} ngx_rtmp_log_var_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t name;
|
||||
ngx_array_t *ops; /* ngx_rtmp_log_op_t */
|
||||
} ngx_rtmp_log_fmt_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_open_file_t *file;
|
||||
time_t disk_full_time;
|
||||
time_t error_log_time;
|
||||
ngx_rtmp_log_fmt_t *format;
|
||||
} ngx_rtmp_log_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_array_t *logs; /* ngx_rtmp_log_t */
|
||||
ngx_uint_t off;
|
||||
} ngx_rtmp_log_app_conf_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_array_t formats; /* ngx_rtmp_log_fmt_t */
|
||||
ngx_uint_t combined_used;
|
||||
} ngx_rtmp_log_main_conf_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
unsigned play:1;
|
||||
unsigned publish:1;
|
||||
u_char name[NGX_RTMP_MAX_NAME];
|
||||
u_char args[NGX_RTMP_MAX_ARGS];
|
||||
} ngx_rtmp_log_ctx_t;
|
||||
|
||||
|
||||
static ngx_str_t ngx_rtmp_access_log = ngx_string(NGX_HTTP_LOG_PATH);
|
||||
|
||||
|
||||
static ngx_command_t ngx_rtmp_log_commands[] = {
|
||||
|
||||
{ ngx_string("access_log"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE12,
|
||||
ngx_rtmp_log_set_log,
|
||||
NGX_RTMP_APP_CONF_OFFSET,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
{ ngx_string("log_format"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_2MORE,
|
||||
ngx_rtmp_log_set_format,
|
||||
NGX_RTMP_MAIN_CONF_OFFSET,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
||||
static ngx_rtmp_module_t ngx_rtmp_log_module_ctx = {
|
||||
NULL, /* preconfiguration */
|
||||
ngx_rtmp_log_postconfiguration, /* postconfiguration */
|
||||
ngx_rtmp_log_create_main_conf, /* create main configuration */
|
||||
NULL, /* init main configuration */
|
||||
NULL, /* create server configuration */
|
||||
NULL, /* merge server configuration */
|
||||
ngx_rtmp_log_create_app_conf, /* create app configuration */
|
||||
ngx_rtmp_log_merge_app_conf /* merge app configuration */
|
||||
};
|
||||
|
||||
|
||||
ngx_module_t ngx_rtmp_log_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_rtmp_log_module_ctx, /* module context */
|
||||
ngx_rtmp_log_commands, /* module directives */
|
||||
NGX_RTMP_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 ngx_str_t ngx_rtmp_combined_fmt =
|
||||
ngx_string("$remote_addr [$time_local] $command "
|
||||
"\"$app\" \"$name\" \"$args\" - "
|
||||
"$bytes_received $bytes_sent "
|
||||
"\"$pageurl\" \"$flashver\" ($session_readable_time)");
|
||||
|
||||
|
||||
static size_t
|
||||
ngx_rtmp_log_var_default_getlen(ngx_rtmp_session_t *s, ngx_rtmp_log_op_t *op)
|
||||
{
|
||||
return op->value.len;
|
||||
}
|
||||
|
||||
|
||||
static u_char *
|
||||
ngx_rtmp_log_var_default_getdata(ngx_rtmp_session_t *s, u_char *buf,
|
||||
ngx_rtmp_log_op_t *op)
|
||||
{
|
||||
return ngx_cpymem(buf, op->value.data, op->value.len);
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
ngx_rtmp_log_var_number_getlen(ngx_rtmp_session_t *s, ngx_rtmp_log_op_t *op)
|
||||
{
|
||||
return NGX_OFF_T_LEN;
|
||||
}
|
||||
|
||||
static u_char *
|
||||
ngx_rtmp_log_var_connection_getdata(ngx_rtmp_session_t *s, u_char *buf,
|
||||
ngx_rtmp_log_op_t *op)
|
||||
{
|
||||
return ngx_sprintf(buf, "%O", (off_t) s->connection->number);
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
ngx_rtmp_log_var_remote_addr_getlen(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_log_op_t *op)
|
||||
{
|
||||
return s->connection->addr_text.len;
|
||||
}
|
||||
|
||||
|
||||
static u_char *
|
||||
ngx_rtmp_log_var_remote_addr_getdata(ngx_rtmp_session_t *s, u_char *buf,
|
||||
ngx_rtmp_log_op_t *op)
|
||||
{
|
||||
return ngx_cpymem(buf, s->connection->addr_text.data,
|
||||
s->connection->addr_text.len);
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
ngx_rtmp_log_var_session_string_getlen(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_log_op_t *op)
|
||||
{
|
||||
return ((ngx_str_t *) ((uint8_t *) s + op->offset))->len;
|
||||
}
|
||||
|
||||
|
||||
static u_char *
|
||||
ngx_rtmp_log_var_session_string_getdata(ngx_rtmp_session_t *s, u_char *buf,
|
||||
ngx_rtmp_log_op_t *op)
|
||||
{
|
||||
ngx_str_t *str;
|
||||
|
||||
str = (ngx_str_t *) ((uint8_t *) s + op->offset);
|
||||
|
||||
return ngx_cpymem(buf, str->data, str->len);
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
ngx_rtmp_log_var_command_getlen(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_log_op_t *op)
|
||||
{
|
||||
return sizeof("PLAY+PUBLISH") - 1;
|
||||
}
|
||||
|
||||
|
||||
static u_char *
|
||||
ngx_rtmp_log_var_command_getdata(ngx_rtmp_session_t *s, u_char *buf,
|
||||
ngx_rtmp_log_op_t *op)
|
||||
{
|
||||
ngx_rtmp_log_ctx_t *ctx;
|
||||
ngx_str_t *cmd;
|
||||
ngx_uint_t n;
|
||||
|
||||
static ngx_str_t commands[] = {
|
||||
ngx_string("NONE"),
|
||||
ngx_string("PLAY"),
|
||||
ngx_string("PUBLISH"),
|
||||
ngx_string("PLAY+PUBLISH")
|
||||
};
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_log_module);
|
||||
|
||||
n = ctx ? (ctx->play + ctx->publish * 2) : 0;
|
||||
|
||||
cmd = &commands[n];
|
||||
|
||||
return ngx_cpymem(buf, cmd->data, cmd->len);
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
ngx_rtmp_log_var_context_cstring_getlen(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_log_op_t *op)
|
||||
{
|
||||
return ngx_max(NGX_RTMP_MAX_NAME, NGX_RTMP_MAX_ARGS);
|
||||
}
|
||||
|
||||
|
||||
static u_char *
|
||||
ngx_rtmp_log_var_context_cstring_getdata(ngx_rtmp_session_t *s, u_char *buf,
|
||||
ngx_rtmp_log_op_t *op)
|
||||
{
|
||||
ngx_rtmp_log_ctx_t *ctx;
|
||||
u_char *p;
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_log_module);
|
||||
if (ctx == NULL) {
|
||||
return buf;
|
||||
}
|
||||
|
||||
p = (u_char *) ctx + op->offset;
|
||||
while (*p) {
|
||||
*buf++ = *p++;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
ngx_rtmp_log_var_session_uint32_getlen(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_log_op_t *op)
|
||||
{
|
||||
return NGX_INT32_LEN;
|
||||
}
|
||||
|
||||
|
||||
static u_char *
|
||||
ngx_rtmp_log_var_session_uint32_getdata(ngx_rtmp_session_t *s, u_char *buf,
|
||||
ngx_rtmp_log_op_t *op)
|
||||
{
|
||||
uint32_t *v;
|
||||
|
||||
v = (uint32_t *) ((uint8_t *) s + op->offset);
|
||||
|
||||
return ngx_sprintf(buf, "%uD", *v);
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
ngx_rtmp_log_var_time_local_getlen(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_log_op_t *op)
|
||||
{
|
||||
return ngx_cached_http_log_time.len;
|
||||
}
|
||||
|
||||
|
||||
static u_char *
|
||||
ngx_rtmp_log_var_time_local_getdata(ngx_rtmp_session_t *s, u_char *buf,
|
||||
ngx_rtmp_log_op_t *op)
|
||||
{
|
||||
return ngx_cpymem(buf, ngx_cached_http_log_time.data,
|
||||
ngx_cached_http_log_time.len);
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
ngx_rtmp_log_var_session_time_getlen(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_log_op_t *op)
|
||||
{
|
||||
return NGX_INT64_LEN;
|
||||
}
|
||||
|
||||
|
||||
static u_char *
|
||||
ngx_rtmp_log_var_session_time_getdata(ngx_rtmp_session_t *s, u_char *buf,
|
||||
ngx_rtmp_log_op_t *op)
|
||||
{
|
||||
return ngx_sprintf(buf, "%L",
|
||||
(int64_t) (ngx_current_msec - s->epoch) / 1000);
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
ngx_rtmp_log_var_session_readable_time_getlen(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_log_op_t *op)
|
||||
{
|
||||
return NGX_OFF_T_LEN + sizeof("d 23h 59m 59s") - 1;
|
||||
}
|
||||
|
||||
|
||||
static u_char *
|
||||
ngx_rtmp_log_var_session_readable_time_getdata(ngx_rtmp_session_t *s,
|
||||
u_char *buf, ngx_rtmp_log_op_t *op)
|
||||
{
|
||||
int64_t v;
|
||||
ngx_uint_t days, hours, minutes, seconds;
|
||||
|
||||
v = (ngx_current_msec - s->epoch) / 1000;
|
||||
|
||||
days = (ngx_uint_t) (v / (60 * 60 * 24));
|
||||
hours = (ngx_uint_t) (v / (60 * 60) % 24);
|
||||
minutes = (ngx_uint_t) (v / 60 % 60);
|
||||
seconds = (ngx_uint_t) (v % 60);
|
||||
|
||||
if (days) {
|
||||
buf = ngx_sprintf(buf, "%uid ", days);
|
||||
}
|
||||
|
||||
if (days || hours) {
|
||||
buf = ngx_sprintf(buf, "%uih ", hours);
|
||||
}
|
||||
|
||||
if (days || hours || minutes) {
|
||||
buf = ngx_sprintf(buf, "%uim ", minutes);
|
||||
}
|
||||
|
||||
buf = ngx_sprintf(buf, "%uis", seconds);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
static ngx_rtmp_log_var_t ngx_rtmp_log_vars[] = {
|
||||
{ ngx_string("connection"),
|
||||
ngx_rtmp_log_var_number_getlen,
|
||||
ngx_rtmp_log_var_connection_getdata,
|
||||
0 },
|
||||
|
||||
{ ngx_string("remote_addr"),
|
||||
ngx_rtmp_log_var_remote_addr_getlen,
|
||||
ngx_rtmp_log_var_remote_addr_getdata,
|
||||
0 },
|
||||
|
||||
{ ngx_string("app"),
|
||||
ngx_rtmp_log_var_session_string_getlen,
|
||||
ngx_rtmp_log_var_session_string_getdata,
|
||||
offsetof(ngx_rtmp_session_t, app) },
|
||||
|
||||
{ ngx_string("flashver"),
|
||||
ngx_rtmp_log_var_session_string_getlen,
|
||||
ngx_rtmp_log_var_session_string_getdata,
|
||||
offsetof(ngx_rtmp_session_t, flashver) },
|
||||
|
||||
{ ngx_string("swfurl"),
|
||||
ngx_rtmp_log_var_session_string_getlen,
|
||||
ngx_rtmp_log_var_session_string_getdata,
|
||||
offsetof(ngx_rtmp_session_t, swf_url) },
|
||||
|
||||
{ ngx_string("tcurl"),
|
||||
ngx_rtmp_log_var_session_string_getlen,
|
||||
ngx_rtmp_log_var_session_string_getdata,
|
||||
offsetof(ngx_rtmp_session_t, tc_url) },
|
||||
|
||||
{ ngx_string("pageurl"),
|
||||
ngx_rtmp_log_var_session_string_getlen,
|
||||
ngx_rtmp_log_var_session_string_getdata,
|
||||
offsetof(ngx_rtmp_session_t, page_url) },
|
||||
|
||||
{ ngx_string("command"),
|
||||
ngx_rtmp_log_var_command_getlen,
|
||||
ngx_rtmp_log_var_command_getdata,
|
||||
0 },
|
||||
|
||||
{ ngx_string("name"),
|
||||
ngx_rtmp_log_var_context_cstring_getlen,
|
||||
ngx_rtmp_log_var_context_cstring_getdata,
|
||||
offsetof(ngx_rtmp_log_ctx_t, name) },
|
||||
|
||||
{ ngx_string("args"),
|
||||
ngx_rtmp_log_var_context_cstring_getlen,
|
||||
ngx_rtmp_log_var_context_cstring_getdata,
|
||||
offsetof(ngx_rtmp_log_ctx_t, args) },
|
||||
|
||||
{ ngx_string("bytes_sent"),
|
||||
ngx_rtmp_log_var_session_uint32_getlen,
|
||||
ngx_rtmp_log_var_session_uint32_getdata,
|
||||
offsetof(ngx_rtmp_session_t, out_bytes) },
|
||||
|
||||
{ ngx_string("bytes_received"),
|
||||
ngx_rtmp_log_var_session_uint32_getlen,
|
||||
ngx_rtmp_log_var_session_uint32_getdata,
|
||||
offsetof(ngx_rtmp_session_t, in_bytes) },
|
||||
|
||||
{ ngx_string("time_local"),
|
||||
ngx_rtmp_log_var_time_local_getlen,
|
||||
ngx_rtmp_log_var_time_local_getdata,
|
||||
0 },
|
||||
|
||||
{ ngx_string("session_time"),
|
||||
ngx_rtmp_log_var_session_time_getlen,
|
||||
ngx_rtmp_log_var_session_time_getdata,
|
||||
0 },
|
||||
|
||||
{ ngx_string("session_readable_time"),
|
||||
ngx_rtmp_log_var_session_readable_time_getlen,
|
||||
ngx_rtmp_log_var_session_readable_time_getdata,
|
||||
0 },
|
||||
|
||||
{ ngx_null_string, NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
|
||||
static void *
|
||||
ngx_rtmp_log_create_main_conf(ngx_conf_t *cf)
|
||||
{
|
||||
ngx_rtmp_log_main_conf_t *lmcf;
|
||||
ngx_rtmp_log_fmt_t *fmt;
|
||||
|
||||
lmcf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_log_main_conf_t));
|
||||
if (lmcf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ngx_array_init(&lmcf->formats, cf->pool, 4, sizeof(ngx_rtmp_log_fmt_t))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fmt = ngx_array_push(&lmcf->formats);
|
||||
if (fmt == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ngx_str_set(&fmt->name, "combined");
|
||||
|
||||
fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_rtmp_log_op_t));
|
||||
if (fmt->ops == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return lmcf;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_rtmp_log_create_app_conf(ngx_conf_t *cf)
|
||||
{
|
||||
ngx_rtmp_log_app_conf_t *lacf;
|
||||
|
||||
lacf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_log_app_conf_t));
|
||||
if (lacf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return lacf;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_rtmp_log_merge_app_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
{
|
||||
ngx_rtmp_log_app_conf_t *prev = parent;
|
||||
ngx_rtmp_log_app_conf_t *conf = child;
|
||||
ngx_rtmp_log_main_conf_t *lmcf;
|
||||
ngx_rtmp_log_fmt_t *fmt;
|
||||
ngx_rtmp_log_t *log;
|
||||
|
||||
if (conf->logs || conf->off) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
conf->logs = prev->logs;
|
||||
conf->off = prev->off;
|
||||
|
||||
if (conf->logs || conf->off) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
conf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_rtmp_log_t));
|
||||
if (conf->logs == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
log = ngx_array_push(conf->logs);
|
||||
if (log == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
log->file = ngx_conf_open_file(cf->cycle, &ngx_rtmp_access_log);
|
||||
if (log->file == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
log->disk_full_time = 0;
|
||||
log->error_log_time = 0;
|
||||
|
||||
lmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_log_module);
|
||||
fmt = lmcf->formats.elts;
|
||||
|
||||
log->format = &fmt[0];
|
||||
lmcf->combined_used = 1;
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_rtmp_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_rtmp_log_app_conf_t *lacf = conf;
|
||||
|
||||
ngx_rtmp_log_main_conf_t *lmcf;
|
||||
ngx_rtmp_log_fmt_t *fmt;
|
||||
ngx_rtmp_log_t *log;
|
||||
ngx_str_t *value, name;
|
||||
ngx_uint_t n;
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
if (ngx_strcmp(value[1].data, "off") == 0) {
|
||||
lacf->off = 1;
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
if (lacf->logs == NULL) {
|
||||
lacf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_rtmp_log_t));
|
||||
if (lacf->logs == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
log = ngx_array_push(lacf->logs);
|
||||
if (log == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
ngx_memzero(log, sizeof(*log));
|
||||
|
||||
lmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_log_module);
|
||||
|
||||
log->file = ngx_conf_open_file(cf->cycle, &value[1]);
|
||||
if (log->file == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
if (cf->args->nelts == 2) {
|
||||
ngx_str_set(&name, "combined");
|
||||
lmcf->combined_used = 1;
|
||||
|
||||
} else {
|
||||
name = value[2];
|
||||
if (ngx_strcmp(name.data, "combined") == 0) {
|
||||
lmcf->combined_used = 1;
|
||||
}
|
||||
}
|
||||
|
||||
fmt = lmcf->formats.elts;
|
||||
for (n = 0; n < lmcf->formats.nelts; ++n, ++fmt) {
|
||||
if (fmt->name.len == name.len &&
|
||||
ngx_strncasecmp(fmt->name.data, name.data, name.len) == 0)
|
||||
{
|
||||
log->format = fmt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (log->format == NULL) {
|
||||
ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "unknown log format \"%V\"",
|
||||
&name);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_rtmp_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_rtmp_log_main_conf_t *lmcf = conf;
|
||||
ngx_rtmp_log_fmt_t *fmt;
|
||||
ngx_str_t *value;
|
||||
ngx_uint_t i;
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
if (cf->cmd_type != NGX_RTMP_MAIN_CONF) {
|
||||
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
|
||||
"\"log_format\" directive can only be used on "
|
||||
"\"rtmp\" level");
|
||||
}
|
||||
|
||||
fmt = lmcf->formats.elts;
|
||||
for (i = 0; i < lmcf->formats.nelts; i++) {
|
||||
if (fmt[i].name.len == value[1].len &&
|
||||
ngx_strcmp(fmt[i].name.data, value[1].data) == 0)
|
||||
{
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"duplicate \"log_format\" name \"%V\"",
|
||||
&value[1]);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
fmt = ngx_array_push(&lmcf->formats);
|
||||
if (fmt == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
fmt->name = value[1];
|
||||
|
||||
fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_rtmp_log_op_t));
|
||||
if (fmt->ops == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
return ngx_rtmp_log_compile_format(cf, fmt->ops, cf->args, 2);
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_rtmp_log_compile_format(ngx_conf_t *cf, ngx_array_t *ops, ngx_array_t *args,
|
||||
ngx_uint_t s)
|
||||
{
|
||||
size_t i, len;
|
||||
u_char *data, *d, c;
|
||||
ngx_uint_t bracket;
|
||||
ngx_str_t *value, var;
|
||||
ngx_rtmp_log_op_t *op;
|
||||
ngx_rtmp_log_var_t *v;
|
||||
|
||||
value = args->elts;
|
||||
|
||||
for (; s < args->nelts; ++s) {
|
||||
i = 0;
|
||||
|
||||
len = value[s].len;
|
||||
d = value[s].data;
|
||||
|
||||
while (i < len) {
|
||||
|
||||
op = ngx_array_push(ops);
|
||||
if (op == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
ngx_memzero(op, sizeof(*op));
|
||||
|
||||
data = &d[i];
|
||||
|
||||
if (d[i] == '$') {
|
||||
if (++i == len) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
if (d[i] == '{') {
|
||||
bracket = 1;
|
||||
if (++i == len) {
|
||||
goto invalid;
|
||||
}
|
||||
} else {
|
||||
bracket = 0;
|
||||
}
|
||||
|
||||
var.data = &d[i];
|
||||
|
||||
for (var.len = 0; i < len; ++i, ++var.len) {
|
||||
c = d[i];
|
||||
|
||||
if (c == '}' && bracket) {
|
||||
++i;
|
||||
bracket = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((c >= 'A' && c <= 'Z') ||
|
||||
(c >= 'a' && c <= 'z') ||
|
||||
(c >= '0' && c <= '9') ||
|
||||
(c == '_'))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (bracket) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"missing closing bracket in \"%V\"",
|
||||
&var);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
if (var.len == 0) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
for (v = ngx_rtmp_log_vars; v->name.len; ++v) {
|
||||
if (v->name.len == var.len &&
|
||||
ngx_strncmp(v->name.data, var.data, var.len) == 0)
|
||||
{
|
||||
op->getlen = v->getlen;
|
||||
op->getdata = v->getdata;
|
||||
op->offset = v->offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (v->name.len == 0) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"unknown variable \"%V\"", &var);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
++i;
|
||||
|
||||
while (i < len && d[i] != '$') {
|
||||
++i;
|
||||
}
|
||||
|
||||
op->getlen = ngx_rtmp_log_var_default_getlen;
|
||||
op->getdata = ngx_rtmp_log_var_default_getdata;
|
||||
|
||||
op->value.len = &d[i] - data;
|
||||
|
||||
op->value.data = ngx_pnalloc(cf->pool, op->value.len);
|
||||
if (op->value.data == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
ngx_memcpy(op->value.data, data, op->value.len);
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
|
||||
invalid:
|
||||
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%s\"", data);
|
||||
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static ngx_rtmp_log_ctx_t *
|
||||
ngx_rtmp_log_set_names(ngx_rtmp_session_t *s, u_char *name, u_char *args)
|
||||
{
|
||||
ngx_rtmp_log_ctx_t *ctx;
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_log_module);
|
||||
if (ctx == NULL) {
|
||||
ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_rtmp_log_ctx_t));
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_log_module);
|
||||
}
|
||||
|
||||
ngx_memcpy(ctx->name, name, NGX_RTMP_MAX_NAME);
|
||||
ngx_memcpy(ctx->args, args, NGX_RTMP_MAX_ARGS);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_log_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
|
||||
{
|
||||
ngx_rtmp_log_ctx_t *ctx;
|
||||
|
||||
if (s->auto_pushed || s->relay) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
ctx = ngx_rtmp_log_set_names(s, v->name, v->args);
|
||||
if (ctx == NULL) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
ctx->publish = 1;
|
||||
|
||||
next:
|
||||
return next_publish(s, v);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_log_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v)
|
||||
{
|
||||
ngx_rtmp_log_ctx_t *ctx;
|
||||
|
||||
if (s->auto_pushed || s->relay) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
ctx = ngx_rtmp_log_set_names(s, v->name, v->args);
|
||||
if (ctx == NULL) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
ctx->play = 1;
|
||||
|
||||
next:
|
||||
return next_play(s, v);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_rtmp_log_write(ngx_rtmp_session_t *s, ngx_rtmp_log_t *log, u_char *buf,
|
||||
size_t len)
|
||||
{
|
||||
u_char *name;
|
||||
time_t now;
|
||||
ssize_t n;
|
||||
int err;
|
||||
|
||||
err = 0;
|
||||
name = log->file->name.data;
|
||||
n = ngx_write_fd(log->file->fd, buf, len);
|
||||
|
||||
if (n == (ssize_t) len) {
|
||||
return;
|
||||
}
|
||||
|
||||
now = ngx_time();
|
||||
|
||||
if (n == -1) {
|
||||
err = ngx_errno;
|
||||
|
||||
if (err == NGX_ENOSPC) {
|
||||
log->disk_full_time = now;
|
||||
}
|
||||
|
||||
if (now - log->error_log_time > 59) {
|
||||
ngx_log_error(NGX_LOG_ALERT, s->connection->log, err,
|
||||
ngx_write_fd_n " to \"%s\" failed", name);
|
||||
log->error_log_time = now;
|
||||
}
|
||||
}
|
||||
|
||||
if (now - log->error_log_time > 59) {
|
||||
ngx_log_error(NGX_LOG_ALERT, s->connection->log, err,
|
||||
ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
|
||||
name, n, len);
|
||||
log->error_log_time = now;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_log_disconnect(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
||||
ngx_chain_t *in)
|
||||
{
|
||||
ngx_rtmp_log_app_conf_t *lacf;
|
||||
ngx_rtmp_log_t *log;
|
||||
ngx_rtmp_log_op_t *op;
|
||||
ngx_uint_t n;
|
||||
u_char *line, *p;
|
||||
size_t len;
|
||||
|
||||
if (s->auto_pushed || s->relay) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_log_module);
|
||||
if (lacf == NULL || lacf->off || lacf->logs == NULL) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
log = lacf->logs->elts;
|
||||
for (n = 0; n < lacf->logs->nelts; ++n, ++log) {
|
||||
|
||||
if (ngx_time() == log->disk_full_time) {
|
||||
/* FreeBSD full disk protection;
|
||||
* nginx http logger does the same */
|
||||
continue;
|
||||
}
|
||||
|
||||
len = 0;
|
||||
op = log->format->ops->elts;
|
||||
for (n = 0; n < log->format->ops->nelts; ++n, ++op) {
|
||||
len += op->getlen(s, op);
|
||||
}
|
||||
|
||||
len += NGX_LINEFEED_SIZE;
|
||||
|
||||
line = ngx_palloc(s->connection->pool, len);
|
||||
if (line == NULL) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
p = line;
|
||||
op = log->format->ops->elts;
|
||||
for (n = 0; n < log->format->ops->nelts; ++n, ++op) {
|
||||
p = op->getdata(s, p, op);
|
||||
}
|
||||
|
||||
ngx_linefeed(p);
|
||||
|
||||
ngx_rtmp_log_write(s, log, line, p - line);
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_log_postconfiguration(ngx_conf_t *cf)
|
||||
{
|
||||
ngx_rtmp_core_main_conf_t *cmcf;
|
||||
ngx_rtmp_handler_pt *h;
|
||||
ngx_rtmp_log_main_conf_t *lmcf;
|
||||
ngx_array_t a;
|
||||
ngx_rtmp_log_fmt_t *fmt;
|
||||
ngx_str_t *value;
|
||||
|
||||
lmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_log_module);
|
||||
if (lmcf->combined_used) {
|
||||
if (ngx_array_init(&a, cf->pool, 1, sizeof(ngx_str_t)) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
value = ngx_array_push(&a);
|
||||
if (value == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*value = ngx_rtmp_combined_fmt;
|
||||
fmt = lmcf->formats.elts;
|
||||
|
||||
if (ngx_rtmp_log_compile_format(cf, fmt->ops, &a, 0)
|
||||
!= NGX_CONF_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module);
|
||||
|
||||
h = ngx_array_push(&cmcf->events[NGX_RTMP_DISCONNECT]);
|
||||
*h = ngx_rtmp_log_disconnect;
|
||||
|
||||
next_publish = ngx_rtmp_publish;
|
||||
ngx_rtmp_publish = ngx_rtmp_log_publish;
|
||||
|
||||
next_play = ngx_rtmp_play;
|
||||
ngx_rtmp_play = ngx_rtmp_log_play;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
|
@ -9,7 +9,8 @@
|
|||
|
||||
|
||||
static ngx_int_t ngx_rtmp_mp4_postconfiguration(ngx_conf_t *cf);
|
||||
static ngx_int_t ngx_rtmp_mp4_init(ngx_rtmp_session_t *s, ngx_file_t *f);
|
||||
static ngx_int_t ngx_rtmp_mp4_init(ngx_rtmp_session_t *s, ngx_file_t *f,
|
||||
ngx_int_t aindex, ngx_int_t vindex);
|
||||
static ngx_int_t ngx_rtmp_mp4_done(ngx_rtmp_session_t *s, ngx_file_t *f);
|
||||
static ngx_int_t ngx_rtmp_mp4_start(ngx_rtmp_session_t *s, ngx_file_t *f);
|
||||
static ngx_int_t ngx_rtmp_mp4_seek(ngx_rtmp_session_t *s, ngx_file_t *f,
|
||||
|
@ -173,6 +174,9 @@ typedef struct {
|
|||
ngx_uint_t sample_size;
|
||||
ngx_uint_t sample_rate;
|
||||
|
||||
ngx_int_t atracks, vtracks;
|
||||
ngx_int_t aindex, vindex;
|
||||
|
||||
uint32_t start_timestamp, epoch;
|
||||
} ngx_rtmp_mp4_ctx_t;
|
||||
|
||||
|
@ -368,6 +372,26 @@ ngx_rtmp_mp4_parse_trak(ngx_rtmp_session_t *s, u_char *pos, u_char *last)
|
|||
{
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"mp4: adding track %ui", ctx->ntracks);
|
||||
|
||||
if (ctx->track->type == NGX_RTMP_MSG_AUDIO) {
|
||||
if (ctx->atracks++ != ctx->aindex) {
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"mp4: skipping audio track %ui!=%ui",
|
||||
ctx->atracks - 1, ctx->aindex);
|
||||
ctx->track = NULL;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (ctx->vtracks++ != ctx->vindex) {
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"mp4: skipping video track %i!=%i",
|
||||
ctx->vtracks - 1, ctx->vindex);
|
||||
ctx->track = NULL;
|
||||
return NGX_OK;
|
||||
}
|
||||
}
|
||||
|
||||
++ctx->ntracks;
|
||||
|
||||
} else {
|
||||
|
@ -2168,12 +2192,14 @@ next:
|
|||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_mp4_init(ngx_rtmp_session_t *s, ngx_file_t *f)
|
||||
ngx_rtmp_mp4_init(ngx_rtmp_session_t *s, ngx_file_t *f, ngx_int_t aindex,
|
||||
ngx_int_t vindex)
|
||||
{
|
||||
ngx_rtmp_mp4_ctx_t *ctx;
|
||||
uint32_t hdr[2];
|
||||
ssize_t n;
|
||||
size_t offset, page_offset, size;
|
||||
uint64_t extended_size;
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module);
|
||||
|
||||
|
@ -2189,6 +2215,9 @@ ngx_rtmp_mp4_init(ngx_rtmp_session_t *s, ngx_file_t *f)
|
|||
|
||||
ngx_memzero(ctx, sizeof(*ctx));
|
||||
|
||||
ctx->aindex = aindex;
|
||||
ctx->vindex = vindex;
|
||||
|
||||
offset = 0;
|
||||
size = 0;
|
||||
|
||||
|
@ -2204,6 +2233,20 @@ ngx_rtmp_mp4_init(ngx_rtmp_session_t *s, ngx_file_t *f)
|
|||
|
||||
size = ngx_rtmp_r32(hdr[0]);
|
||||
|
||||
if (size == 1) {
|
||||
n = ngx_read_file(f, (u_char *) &extended_size,
|
||||
sizeof(extended_size), offset + sizeof(hdr));
|
||||
|
||||
if (n != sizeof(extended_size)) {
|
||||
ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
|
||||
"mp4: error reading file at offset=%uz "
|
||||
"while searching for moov box", offset + 8);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
size = ngx_rtmp_r64(extended_size);
|
||||
}
|
||||
|
||||
if (hdr[1] == ngx_rtmp_mp4_make_tag('m','o','o','v')) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"mp4: found moov box");
|
||||
|
|
|
@ -208,7 +208,7 @@ ngx_rtmp_play_do_init(ngx_rtmp_session_t *s)
|
|||
}
|
||||
|
||||
if (ctx->fmt && ctx->fmt->init &&
|
||||
ctx->fmt->init(s, &ctx->file) != NGX_OK)
|
||||
ctx->fmt->init(s, &ctx->file, ctx->aindex, ctx->vindex) != NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
@ -433,6 +433,33 @@ next:
|
|||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_play_parse_index(char type, u_char *args)
|
||||
{
|
||||
u_char *p, c;
|
||||
static u_char name[] = "xindex=";
|
||||
|
||||
name[0] = (u_char) type;
|
||||
|
||||
for ( ;; ) {
|
||||
p = (u_char *) ngx_strstr(args, name);
|
||||
if (p == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (p != args) {
|
||||
c = *(p - 1);
|
||||
if (c != '?' && c != '&') {
|
||||
args = p + 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return atoi((char *) p + (sizeof(name) - 1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_play_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v)
|
||||
{
|
||||
|
@ -487,6 +514,9 @@ ngx_rtmp_play_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v)
|
|||
|
||||
ngx_memzero(ctx, sizeof(*ctx));
|
||||
|
||||
ctx->aindex = ngx_rtmp_play_parse_index('a', v->args);
|
||||
ctx->vindex = ngx_rtmp_play_parse_index('v', v->args);
|
||||
|
||||
ctx->file.log = s->connection->log;
|
||||
|
||||
name.len = ngx_strlen(v->name);
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
|
||||
typedef ngx_int_t (*ngx_rtmp_play_init_pt) (ngx_rtmp_session_t *s,
|
||||
ngx_file_t *f);
|
||||
ngx_file_t *f, ngx_int_t aindex, ngx_int_t vindex);
|
||||
typedef ngx_int_t (*ngx_rtmp_play_done_pt) (ngx_rtmp_session_t *s,
|
||||
ngx_file_t *f);
|
||||
typedef ngx_int_t (*ngx_rtmp_play_start_pt) (ngx_rtmp_session_t *s,
|
||||
|
@ -45,6 +45,7 @@ typedef struct {
|
|||
unsigned playing:1;
|
||||
ngx_uint_t ncrs;
|
||||
ngx_str_t name;
|
||||
ngx_int_t aindex, vindex;
|
||||
} ngx_rtmp_play_ctx_t;
|
||||
|
||||
|
||||
|
|
|
@ -89,6 +89,14 @@ static ngx_command_t ngx_rtmp_record_commands[] = {
|
|||
offsetof(ngx_rtmp_record_app_conf_t, unique),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("record_lock"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|
|
||||
NGX_RTMP_REC_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_flag_slot,
|
||||
NGX_RTMP_APP_CONF_OFFSET,
|
||||
offsetof(ngx_rtmp_record_app_conf_t, lock_file),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("record_max_size"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|
|
||||
NGX_RTMP_REC_CONF|NGX_CONF_TAKE1,
|
||||
|
@ -176,6 +184,7 @@ ngx_rtmp_record_create_app_conf(ngx_conf_t *cf)
|
|||
racf->max_frames = NGX_CONF_UNSET;
|
||||
racf->interval = NGX_CONF_UNSET;
|
||||
racf->unique = NGX_CONF_UNSET;
|
||||
racf->lock_file = NGX_CONF_UNSET;
|
||||
racf->notify = NGX_CONF_UNSET;
|
||||
racf->url = NGX_CONF_UNSET_PTR;
|
||||
|
||||
|
@ -199,6 +208,7 @@ ngx_rtmp_record_merge_app_conf(ngx_conf_t *cf, void *parent, void *child)
|
|||
ngx_conf_merge_size_value(conf->max_size, prev->max_size, 0);
|
||||
ngx_conf_merge_size_value(conf->max_frames, prev->max_frames, 0);
|
||||
ngx_conf_merge_value(conf->unique, prev->unique, 0);
|
||||
ngx_conf_merge_value(conf->lock_file, prev->lock_file, 0);
|
||||
ngx_conf_merge_value(conf->notify, prev->notify, 0);
|
||||
ngx_conf_merge_msec_value(conf->interval, prev->interval,
|
||||
(ngx_msec_t) NGX_CONF_UNSET);
|
||||
|
@ -448,6 +458,14 @@ ngx_rtmp_record_node_open(ngx_rtmp_session_t *s,
|
|||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (rracf->lock_file) {
|
||||
err = ngx_lock_fd(rctx->file.fd);
|
||||
if (err) {
|
||||
ngx_log_error(NGX_LOG_CRIT, s->connection->log, err,
|
||||
"record: %V lock failed", &rracf->id);
|
||||
}
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"record: %V opened '%V'", &rracf->id, &path);
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ typedef struct {
|
|||
ngx_msec_t interval;
|
||||
ngx_str_t suffix;
|
||||
ngx_flag_t unique;
|
||||
ngx_flag_t lock_file;
|
||||
ngx_flag_t notify;
|
||||
ngx_url_t *url;
|
||||
|
||||
|
|
|
@ -12,14 +12,18 @@ static ngx_rtmp_play_pt next_play;
|
|||
static ngx_rtmp_delete_stream_pt next_delete_stream;
|
||||
|
||||
|
||||
static ngx_int_t ngx_rtmp_relay_init_process(ngx_cycle_t *cycle);
|
||||
static ngx_int_t ngx_rtmp_relay_postconfiguration(ngx_conf_t *cf);
|
||||
static void * ngx_rtmp_relay_create_app_conf(ngx_conf_t *cf);
|
||||
static char * ngx_rtmp_relay_merge_app_conf(ngx_conf_t *cf,
|
||||
void *parent, void *child);
|
||||
void *parent, void *child);
|
||||
static char * ngx_rtmp_relay_push_pull(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
void *conf);
|
||||
static ngx_int_t ngx_rtmp_relay_publish(ngx_rtmp_session_t *s,
|
||||
ngx_rtmp_publish_t *v);
|
||||
ngx_rtmp_publish_t *v);
|
||||
static ngx_rtmp_relay_ctx_t * ngx_rtmp_relay_create_connection(
|
||||
ngx_rtmp_conf_ctx_t *cctx, ngx_str_t* name,
|
||||
ngx_rtmp_relay_target_t *target);
|
||||
|
||||
|
||||
/* _____
|
||||
|
@ -37,16 +41,25 @@ static ngx_int_t ngx_rtmp_relay_publish(ngx_rtmp_session_t *s,
|
|||
|
||||
|
||||
typedef struct {
|
||||
ngx_array_t pulls; /* ngx_rtmp_relay_target_t * */
|
||||
ngx_array_t pushes; /* ngx_rtmp_relay_target_t * */
|
||||
ngx_log_t *log;
|
||||
ngx_uint_t nbuckets;
|
||||
ngx_msec_t buflen;
|
||||
ngx_msec_t push_reconnect;
|
||||
ngx_rtmp_relay_ctx_t **ctx;
|
||||
ngx_array_t pulls; /* ngx_rtmp_relay_target_t * */
|
||||
ngx_array_t pushes; /* ngx_rtmp_relay_target_t * */
|
||||
ngx_array_t static_pulls; /* ngx_rtmp_relay_target_t * */
|
||||
ngx_array_t static_events; /* ngx_event_t * */
|
||||
ngx_log_t *log;
|
||||
ngx_uint_t nbuckets;
|
||||
ngx_msec_t buflen;
|
||||
ngx_msec_t push_reconnect;
|
||||
ngx_msec_t pull_reconnect;
|
||||
ngx_rtmp_relay_ctx_t **ctx;
|
||||
} ngx_rtmp_relay_app_conf_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_rtmp_conf_ctx_t cctx;
|
||||
ngx_rtmp_relay_target_t *target;
|
||||
} ngx_rtmp_relay_static_t;
|
||||
|
||||
|
||||
#define NGX_RTMP_RELAY_CONNECT_TRANS 1
|
||||
#define NGX_RTMP_RELAY_CREATE_STREAM_TRANS 2
|
||||
|
||||
|
@ -89,6 +102,13 @@ static ngx_command_t ngx_rtmp_relay_commands[] = {
|
|||
NGX_RTMP_APP_CONF_OFFSET,
|
||||
offsetof(ngx_rtmp_relay_app_conf_t, push_reconnect),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("pull_reconnect"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_msec_slot,
|
||||
NGX_RTMP_APP_CONF_OFFSET,
|
||||
offsetof(ngx_rtmp_relay_app_conf_t, pull_reconnect),
|
||||
NULL },
|
||||
|
||||
|
||||
ngx_null_command
|
||||
|
@ -114,7 +134,7 @@ ngx_module_t ngx_rtmp_relay_module = {
|
|||
NGX_RTMP_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
NULL, /* init module */
|
||||
NULL, /* init process */
|
||||
ngx_rtmp_relay_init_process, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
NULL, /* exit process */
|
||||
|
@ -133,14 +153,31 @@ ngx_rtmp_relay_create_app_conf(ngx_conf_t *cf)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
ngx_array_init(&racf->pushes, cf->pool, 1,
|
||||
sizeof(ngx_rtmp_relay_target_t *));
|
||||
ngx_array_init(&racf->pulls, cf->pool, 1,
|
||||
sizeof(ngx_rtmp_relay_target_t *));
|
||||
if (ngx_array_init(&racf->pushes, cf->pool, 1, sizeof(void *)) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ngx_array_init(&racf->pulls, cf->pool, 1, sizeof(void *)) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ngx_array_init(&racf->static_pulls, cf->pool, 1, sizeof(void *))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ngx_array_init(&racf->static_events, cf->pool, 1, sizeof(void *))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
racf->nbuckets = 1024;
|
||||
racf->log = &cf->cycle->new_log;
|
||||
racf->buflen = NGX_CONF_UNSET;
|
||||
racf->push_reconnect = NGX_CONF_UNSET;
|
||||
racf->pull_reconnect = NGX_CONF_UNSET;
|
||||
|
||||
return racf;
|
||||
}
|
||||
|
@ -158,13 +195,40 @@ ngx_rtmp_relay_merge_app_conf(ngx_conf_t *cf, void *parent, void *child)
|
|||
ngx_conf_merge_msec_value(conf->buflen, prev->buflen, 5000);
|
||||
ngx_conf_merge_msec_value(conf->push_reconnect, prev->push_reconnect,
|
||||
3000);
|
||||
ngx_conf_merge_msec_value(conf->pull_reconnect, prev->pull_reconnect,
|
||||
3000);
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_rtmp_relay_reconnect(ngx_event_t *ev)
|
||||
ngx_rtmp_relay_static_pull_reconnect(ngx_event_t *ev)
|
||||
{
|
||||
ngx_rtmp_relay_static_t *rs = ev->data;
|
||||
|
||||
ngx_rtmp_relay_ctx_t *ctx;
|
||||
ngx_rtmp_relay_app_conf_t *racf;
|
||||
|
||||
racf = ngx_rtmp_get_module_app_conf(&rs->cctx, ngx_rtmp_relay_module);
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, racf->log, 0,
|
||||
"relay: reconnecting static pull");
|
||||
|
||||
ctx = ngx_rtmp_relay_create_connection(&rs->cctx, &rs->target->name,
|
||||
rs->target);
|
||||
if (ctx) {
|
||||
ctx->session->static_relay = 1;
|
||||
ctx->static_evt = ev;
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_add_timer(ev, racf->pull_reconnect);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_rtmp_relay_push_reconnect(ngx_event_t *ev)
|
||||
{
|
||||
ngx_rtmp_session_t *s = ev->data;
|
||||
|
||||
|
@ -257,14 +321,14 @@ ngx_rtmp_relay_copy_str(ngx_pool_t *pool, ngx_str_t *dst, ngx_str_t *src)
|
|||
|
||||
|
||||
static ngx_rtmp_relay_ctx_t *
|
||||
ngx_rtmp_relay_create_remote_ctx(ngx_rtmp_session_t *s, ngx_str_t* name,
|
||||
ngx_rtmp_relay_create_connection(ngx_rtmp_conf_ctx_t *cctx, ngx_str_t* name,
|
||||
ngx_rtmp_relay_target_t *target)
|
||||
{
|
||||
ngx_rtmp_relay_app_conf_t *racf;
|
||||
ngx_rtmp_relay_ctx_t *rctx;
|
||||
ngx_rtmp_addr_conf_t *addr_conf;
|
||||
ngx_rtmp_conf_ctx_t *addr_ctx;
|
||||
ngx_rtmp_session_t *rs;
|
||||
ngx_rtmp_relay_app_conf_t *racf;
|
||||
ngx_peer_connection_t *pc;
|
||||
ngx_connection_t *c;
|
||||
ngx_pool_t *pool;
|
||||
|
@ -272,10 +336,10 @@ ngx_rtmp_relay_create_remote_ctx(ngx_rtmp_session_t *s, ngx_str_t* name,
|
|||
ngx_str_t v, *uri;
|
||||
u_char *first, *last, *p;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"relay: create remote context");
|
||||
racf = ngx_rtmp_get_module_app_conf(cctx, ngx_rtmp_relay_module);
|
||||
|
||||
racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_relay_module);
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, racf->log, 0,
|
||||
"relay: create remote context");
|
||||
|
||||
pool = NULL;
|
||||
pool = ngx_create_pool(4096, racf->log);
|
||||
|
@ -288,9 +352,11 @@ ngx_rtmp_relay_create_remote_ctx(ngx_rtmp_session_t *s, ngx_str_t* name,
|
|||
goto clear;
|
||||
}
|
||||
|
||||
if (ngx_rtmp_relay_copy_str(pool, &rctx->name, name) != NGX_OK ||
|
||||
ngx_rtmp_relay_copy_str(pool, &rctx->url, &target->url.url) != NGX_OK)
|
||||
{
|
||||
if (name && ngx_rtmp_relay_copy_str(pool, &rctx->name, name) != NGX_OK) {
|
||||
goto clear;
|
||||
}
|
||||
|
||||
if (ngx_rtmp_relay_copy_str(pool, &rctx->url, &target->url.url) != NGX_OK) {
|
||||
goto clear;
|
||||
}
|
||||
|
||||
|
@ -357,8 +423,6 @@ ngx_rtmp_relay_create_remote_ctx(ngx_rtmp_session_t *s, ngx_str_t* name,
|
|||
}
|
||||
}
|
||||
|
||||
rctx->relay = 1;
|
||||
|
||||
pc = ngx_pcalloc(pool, sizeof(ngx_peer_connection_t));
|
||||
if (pc == NULL) {
|
||||
goto clear;
|
||||
|
@ -395,8 +459,8 @@ ngx_rtmp_relay_create_remote_ctx(ngx_rtmp_session_t *s, ngx_str_t* name,
|
|||
goto clear;
|
||||
}
|
||||
addr_conf->ctx = addr_ctx;
|
||||
addr_ctx->main_conf = s->main_conf;
|
||||
addr_ctx->srv_conf = s->srv_conf;
|
||||
addr_ctx->main_conf = cctx->main_conf;
|
||||
addr_ctx->srv_conf = cctx->srv_conf;
|
||||
ngx_str_set(&addr_conf->addr_text, "ngx-relay");
|
||||
|
||||
rs = ngx_rtmp_init_session(c, addr_conf);
|
||||
|
@ -404,12 +468,16 @@ ngx_rtmp_relay_create_remote_ctx(ngx_rtmp_session_t *s, ngx_str_t* name,
|
|||
/* no need to destroy pool */
|
||||
return NULL;
|
||||
}
|
||||
rs->app_conf = s->app_conf;
|
||||
rs->app_conf = cctx->app_conf;
|
||||
rs->relay = 1;
|
||||
rctx->session = rs;
|
||||
ngx_rtmp_set_ctx(rs, rctx, ngx_rtmp_relay_module);
|
||||
ngx_str_set(&rs->flashver, "ngx-local-relay");
|
||||
|
||||
#if (NGX_STAT_STUB)
|
||||
(void) ngx_atomic_fetch_add(ngx_stat_active, 1);
|
||||
#endif
|
||||
|
||||
ngx_rtmp_client_handshake(rs, 1);
|
||||
return rctx;
|
||||
|
||||
|
@ -421,6 +489,20 @@ clear:
|
|||
}
|
||||
|
||||
|
||||
static ngx_rtmp_relay_ctx_t *
|
||||
ngx_rtmp_relay_create_remote_ctx(ngx_rtmp_session_t *s, ngx_str_t* name,
|
||||
ngx_rtmp_relay_target_t *target)
|
||||
{
|
||||
ngx_rtmp_conf_ctx_t cctx;
|
||||
|
||||
cctx.app_conf = s->app_conf;
|
||||
cctx.srv_conf = s->srv_conf;
|
||||
cctx.main_conf = s->main_conf;
|
||||
|
||||
return ngx_rtmp_relay_create_connection(&cctx, name, target);
|
||||
}
|
||||
|
||||
|
||||
static ngx_rtmp_relay_ctx_t *
|
||||
ngx_rtmp_relay_create_local_ctx(ngx_rtmp_session_t *s, ngx_str_t *name,
|
||||
ngx_rtmp_relay_target_t *target)
|
||||
|
@ -442,7 +524,7 @@ ngx_rtmp_relay_create_local_ctx(ngx_rtmp_session_t *s, ngx_str_t *name,
|
|||
|
||||
ctx->push_evt.data = s;
|
||||
ctx->push_evt.log = s->connection->log;
|
||||
ctx->push_evt.handler = ngx_rtmp_relay_reconnect;
|
||||
ctx->push_evt.handler = ngx_rtmp_relay_push_reconnect;
|
||||
|
||||
if (ctx->publish) {
|
||||
return NULL;
|
||||
|
@ -554,7 +636,7 @@ ngx_rtmp_relay_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
|
|||
}
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module);
|
||||
if (ctx && ctx->relay) {
|
||||
if (ctx && s->relay) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
|
@ -606,7 +688,7 @@ ngx_rtmp_relay_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v)
|
|||
ngx_rtmp_relay_ctx_t *ctx;
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module);
|
||||
if (ctx && ctx->relay) {
|
||||
if (ctx && s->relay) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
|
@ -1022,7 +1104,7 @@ ngx_rtmp_relay_on_result(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module);
|
||||
if (ctx == NULL || !ctx->relay) {
|
||||
if (ctx == NULL || !s->relay) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
@ -1042,7 +1124,7 @@ ngx_rtmp_relay_on_result(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||
return ngx_rtmp_relay_send_create_stream(s);
|
||||
|
||||
case NGX_RTMP_RELAY_CREATE_STREAM_TRANS:
|
||||
if (ctx->publish != ctx) {
|
||||
if (ctx->publish != ctx && !s->static_relay) {
|
||||
if (ngx_rtmp_relay_send_publish(s) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
@ -1105,7 +1187,7 @@ ngx_rtmp_relay_on_error(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module);
|
||||
if (ctx == NULL || !ctx->relay) {
|
||||
if (ctx == NULL || !s->relay) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
@ -1175,7 +1257,7 @@ ngx_rtmp_relay_on_status(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module);
|
||||
if (ctx == NULL || !ctx->relay) {
|
||||
if (ctx == NULL || !s->relay) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
@ -1200,10 +1282,10 @@ static ngx_int_t
|
|||
ngx_rtmp_relay_handshake_done(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
||||
ngx_chain_t *in)
|
||||
{
|
||||
ngx_rtmp_relay_ctx_t *ctx;
|
||||
ngx_rtmp_relay_ctx_t *ctx;
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module);
|
||||
if (ctx == NULL || ctx->publish == NULL) {
|
||||
if (ctx == NULL || !s->relay) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
@ -1221,7 +1303,16 @@ ngx_rtmp_relay_delete_stream(ngx_rtmp_session_t *s, ngx_rtmp_delete_stream_t *v)
|
|||
racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_relay_module);
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module);
|
||||
if (ctx == NULL || ctx->publish == NULL) {
|
||||
if (ctx == NULL) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (s->static_relay) {
|
||||
ngx_add_timer(ctx->static_evt, racf->pull_reconnect);
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (ctx->publish == NULL) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
|
@ -1239,7 +1330,7 @@ ngx_rtmp_relay_delete_stream(ngx_rtmp_session_t *s, ngx_rtmp_delete_stream_t *v)
|
|||
&ctx->app, &ctx->name);
|
||||
|
||||
/* push reconnect */
|
||||
if (ctx->relay && ctx->tag == &ngx_rtmp_relay_module &&
|
||||
if (s->relay && ctx->tag == &ngx_rtmp_relay_module &&
|
||||
!ctx->publish->push_evt.timer_set)
|
||||
{
|
||||
ngx_add_timer(&ctx->publish->push_evt, racf->push_reconnect);
|
||||
|
@ -1255,7 +1346,7 @@ ngx_rtmp_relay_delete_stream(ngx_rtmp_session_t *s, ngx_rtmp_delete_stream_t *v)
|
|||
}
|
||||
#endif
|
||||
|
||||
if (ctx->publish->play == NULL && ctx->publish->relay) {
|
||||
if (ctx->publish->play == NULL && ctx->publish->session->relay) {
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_RTMP,
|
||||
ctx->publish->session->connection->log, 0,
|
||||
"relay: publish disconnect empty app='%V' name='%V'",
|
||||
|
@ -1306,28 +1397,23 @@ ngx_rtmp_relay_push_pull(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
ngx_rtmp_relay_target_t *target, **t;
|
||||
ngx_url_t *u;
|
||||
ngx_uint_t i;
|
||||
ngx_int_t is_pull, is_static;
|
||||
ngx_event_t **ee, *e;
|
||||
ngx_rtmp_relay_static_t *rs;
|
||||
u_char *p;
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
racf = ngx_rtmp_conf_get_module_app_conf(cf, ngx_rtmp_relay_module);
|
||||
|
||||
t = ngx_array_push(value[0].data[3] == 'h'
|
||||
? &racf->pushes /* push */
|
||||
: &racf->pulls /* pull */
|
||||
);
|
||||
|
||||
if (t == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
is_pull = (value[0].data[3] == 'l');
|
||||
is_static = 0;
|
||||
|
||||
target = ngx_pcalloc(cf->pool, sizeof(*target));
|
||||
if (target == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
*t = target;
|
||||
|
||||
target->tag = &ngx_rtmp_relay_module;
|
||||
target->data = target;
|
||||
|
||||
|
@ -1352,57 +1438,169 @@ ngx_rtmp_relay_push_pull(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
value += 2;
|
||||
for (i = 2; i < cf->args->nelts; ++i, ++value) {
|
||||
p = ngx_strlchr(value->data, value->data + value->len, '=');
|
||||
|
||||
if (p == NULL) {
|
||||
return "key=value expected";
|
||||
n = *value;
|
||||
ngx_str_set(&v, "1");
|
||||
|
||||
} else {
|
||||
n.data = value->data;
|
||||
n.len = p - value->data;
|
||||
|
||||
v.data = p + 1;
|
||||
v.len = value->data + value->len - p - 1;
|
||||
}
|
||||
|
||||
if (p == value->data + value->len - 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
n.data = value->data;
|
||||
n.len = p - value->data;
|
||||
|
||||
v.data = p + 1;
|
||||
v.len = value->data + value->len - p - 1;
|
||||
|
||||
#define NGX_RTMP_RELAY_STR_PAR(name, var) \
|
||||
if (n.len == sizeof(#name) - 1 \
|
||||
&& ngx_strncasecmp(n.data, (u_char *)#name, n.len) == 0) \
|
||||
if (n.len == sizeof(name) - 1 \
|
||||
&& ngx_strncasecmp(n.data, (u_char *) name, n.len) == 0) \
|
||||
{ \
|
||||
target->var = v; \
|
||||
continue; \
|
||||
}
|
||||
|
||||
#define NGX_RTMP_RELAY_NUM_PAR(name, var) \
|
||||
if (n.len == sizeof(#name) - 1 \
|
||||
&& ngx_strncasecmp(n.data, (u_char *)#name, n.len) == 0) \
|
||||
if (n.len == sizeof(name) - 1 \
|
||||
&& ngx_strncasecmp(n.data, (u_char *) name, n.len) == 0) \
|
||||
{ \
|
||||
target->var = ngx_atoi(v.data, v.len); \
|
||||
continue; \
|
||||
}
|
||||
|
||||
NGX_RTMP_RELAY_STR_PAR(app, app);
|
||||
NGX_RTMP_RELAY_STR_PAR(name, name);
|
||||
NGX_RTMP_RELAY_STR_PAR(tcUrl, tc_url);
|
||||
NGX_RTMP_RELAY_STR_PAR(pageUrl, page_url);
|
||||
NGX_RTMP_RELAY_STR_PAR(swfUrl, swf_url);
|
||||
NGX_RTMP_RELAY_STR_PAR(flashVer, flash_ver);
|
||||
NGX_RTMP_RELAY_STR_PAR(playPath, play_path);
|
||||
NGX_RTMP_RELAY_NUM_PAR(live, live);
|
||||
NGX_RTMP_RELAY_NUM_PAR(start, start);
|
||||
NGX_RTMP_RELAY_NUM_PAR(stop, stop);
|
||||
NGX_RTMP_RELAY_STR_PAR("app", app);
|
||||
NGX_RTMP_RELAY_STR_PAR("name", name);
|
||||
NGX_RTMP_RELAY_STR_PAR("tcUrl", tc_url);
|
||||
NGX_RTMP_RELAY_STR_PAR("pageUrl", page_url);
|
||||
NGX_RTMP_RELAY_STR_PAR("swfUrl", swf_url);
|
||||
NGX_RTMP_RELAY_STR_PAR("flashVer", flash_ver);
|
||||
NGX_RTMP_RELAY_STR_PAR("playPath", play_path);
|
||||
NGX_RTMP_RELAY_NUM_PAR("live", live);
|
||||
NGX_RTMP_RELAY_NUM_PAR("start", start);
|
||||
NGX_RTMP_RELAY_NUM_PAR("stop", stop);
|
||||
|
||||
#undef NGX_RTMP_RELAY_STR_PAR
|
||||
#undef NGX_RTMP_RELAY_NUM_PAR
|
||||
|
||||
if (n.len == sizeof("static") - 1 &&
|
||||
ngx_strncasecmp(n.data, (u_char *) "static", n.len) == 0 &&
|
||||
ngx_atoi(v.data, v.len))
|
||||
{
|
||||
is_static = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
return "unsuppored parameter";
|
||||
}
|
||||
|
||||
if (is_static) {
|
||||
|
||||
if (!is_pull) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"static push is not allowed");
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
if (target->name.len == 0) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"stream name missing in static pull "
|
||||
"declaration");
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
ee = ngx_array_push(&racf->static_events);
|
||||
if (ee == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
e = ngx_pcalloc(cf->pool, sizeof(ngx_event_t));
|
||||
if (e == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
*ee = e;
|
||||
|
||||
rs = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_relay_static_t));
|
||||
if (rs == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
rs->target = target;
|
||||
|
||||
e->data = rs;
|
||||
e->log = &cf->cycle->new_log;
|
||||
e->handler = ngx_rtmp_relay_static_pull_reconnect;
|
||||
|
||||
t = ngx_array_push(&racf->static_pulls);
|
||||
|
||||
} else if (is_pull) {
|
||||
t = ngx_array_push(&racf->pulls);
|
||||
|
||||
} else {
|
||||
t = ngx_array_push(&racf->pushes);
|
||||
}
|
||||
|
||||
if (t == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
*t = target;
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_relay_init_process(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_rtmp_core_main_conf_t *cmcf = ngx_rtmp_core_main_conf;
|
||||
ngx_rtmp_core_srv_conf_t **pcscf, *cscf;
|
||||
ngx_rtmp_core_app_conf_t **pcacf, *cacf;
|
||||
ngx_rtmp_relay_app_conf_t *racf;
|
||||
ngx_uint_t n, m, k;
|
||||
ngx_rtmp_relay_static_t *rs;
|
||||
ngx_rtmp_listen_t *lst;
|
||||
ngx_event_t **pevent, *event;
|
||||
|
||||
if (cmcf->listen.nelts == 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
/* only first worker does static pulling */
|
||||
|
||||
if (ngx_process_slot) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
lst = cmcf->listen.elts;
|
||||
|
||||
pcscf = cmcf->servers.elts;
|
||||
for (n = 0; n < cmcf->servers.nelts; ++n, ++pcscf) {
|
||||
|
||||
cscf = *pcscf;
|
||||
pcacf = cscf->applications.elts;
|
||||
|
||||
for (m = 0; m < cscf->applications.nelts; ++m, ++pcacf) {
|
||||
|
||||
cacf = *pcacf;
|
||||
racf = cacf->app_conf[ngx_rtmp_relay_module.ctx_index];
|
||||
pevent = racf->static_events.elts;
|
||||
|
||||
for (k = 0; k < racf->static_events.nelts; ++k, ++pevent) {
|
||||
event = *pevent;
|
||||
|
||||
rs = event->data;
|
||||
rs->cctx = *lst->ctx;
|
||||
rs->cctx.app_conf = cacf->app_conf;
|
||||
|
||||
ngx_post_event(event, &ngx_posted_events);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_relay_postconfiguration(ngx_conf_t *cf)
|
||||
{
|
||||
|
|
|
@ -38,7 +38,6 @@ struct ngx_rtmp_relay_ctx_s {
|
|||
ngx_rtmp_relay_ctx_t *publish;
|
||||
ngx_rtmp_relay_ctx_t *play;
|
||||
ngx_rtmp_relay_ctx_t *next;
|
||||
unsigned relay:1;
|
||||
|
||||
ngx_str_t app;
|
||||
ngx_str_t tc_url;
|
||||
|
@ -51,6 +50,7 @@ struct ngx_rtmp_relay_ctx_s {
|
|||
ngx_int_t stop;
|
||||
|
||||
ngx_event_t push_evt;
|
||||
ngx_event_t *static_evt;
|
||||
void *tag;
|
||||
void *data;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue