Merge branch 'master' into exec-static

This commit is contained in:
Roman Arutyunyan 2013-02-01 17:23:12 +04:00
commit 2741432356
18 changed files with 1522 additions and 132 deletions

5
TODO
View file

@ -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
View file

@ -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"

View file

@ -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) {

View file

@ -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 {

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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
View 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;
}

View file

@ -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");

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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)
{

View file

@ -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;
};