added on_record_done & exec_record_done for recorder{} blocks; added new-style args to exec_* notifiers

This commit is contained in:
Roman Arutyunyan 2012-09-12 14:57:24 +04:00
parent 6b0dddbcc0
commit 9a31ca9237
5 changed files with 488 additions and 353 deletions

5
config
View file

@ -5,11 +5,11 @@ CORE_MODULES="$CORE_MODULES
ngx_rtmp_core_module \
ngx_rtmp_cmd_module \
ngx_rtmp_access_module \
ngx_rtmp_record_module \
ngx_rtmp_live_module \
ngx_rtmp_play_module \
ngx_rtmp_flv_module \
ngx_rtmp_mp4_module \
ngx_rtmp_record_module \
ngx_rtmp_netcall_module \
ngx_rtmp_relay_module \
ngx_rtmp_exec_module \
@ -33,15 +33,16 @@ NGX_ADDON_SRCS="$NGX_ADDON_SRCS \
$ngx_addon_dir/ngx_rtmp_amf.c \
$ngx_addon_dir/ngx_rtmp_send.c \
$ngx_addon_dir/ngx_rtmp_shared.c \
$ngx_addon_dir/ngx_rtmp_eval.c \
$ngx_addon_dir/ngx_rtmp_receive.c \
$ngx_addon_dir/ngx_rtmp_core_module.c \
$ngx_addon_dir/ngx_rtmp_cmd_module.c \
$ngx_addon_dir/ngx_rtmp_access_module.c \
$ngx_addon_dir/ngx_rtmp_record_module.c \
$ngx_addon_dir/ngx_rtmp_live_module.c \
$ngx_addon_dir/ngx_rtmp_play_module.c \
$ngx_addon_dir/ngx_rtmp_flv_module.c \
$ngx_addon_dir/ngx_rtmp_mp4_module.c \
$ngx_addon_dir/ngx_rtmp_record_module.c \
$ngx_addon_dir/ngx_rtmp_netcall_module.c \
$ngx_addon_dir/ngx_rtmp_stat_module.c \
$ngx_addon_dir/ngx_rtmp_relay_module.c \

View file

@ -7,7 +7,9 @@
#include <ngx_core.h>
#include "ngx_rtmp.h"
#include "ngx_rtmp_eval.h"
#include "ngx_rtmp_cmd_module.h"
#include "ngx_rtmp_record_module.h"
#include <stdlib.h>
#ifdef HAVE_MALLOC_H
@ -22,6 +24,7 @@
static ngx_rtmp_publish_pt next_publish;
static ngx_rtmp_play_pt next_play;
static ngx_rtmp_delete_stream_pt next_delete_stream;
static ngx_rtmp_record_done_pt next_record_done;
static char *ngx_rtmp_enotify_on_event(ngx_conf_t *cf, ngx_command_t *cmd,
@ -36,11 +39,14 @@ static char * ngx_rtmp_enotify_merge_app_conf(ngx_conf_t *cf,
#define NGX_RTMP_ENOTIFY_PLAYING 0x02
#define NGX_RTMP_ENOTIFY_PUBLISH 0
#define NGX_RTMP_ENOTIFY_PLAY 1
#define NGX_RTMP_ENOTIFY_PUBLISH_DONE 2
#define NGX_RTMP_ENOTIFY_PLAY_DONE 3
#define NGX_RTMP_ENOTIFY_MAX 4
enum {
NGX_RTMP_ENOTIFY_PUBLISH,
NGX_RTMP_ENOTIFY_PLAY,
NGX_RTMP_ENOTIFY_PUBLISH_DONE,
NGX_RTMP_ENOTIFY_PLAY_DONE,
NGX_RTMP_ENOTIFY_RECORD_DONE,
NGX_RTMP_ENOTIFY_MAX
};
typedef struct {
@ -50,7 +56,7 @@ typedef struct {
typedef struct {
ngx_rtmp_enotify_conf_t *events[NGX_RTMP_ENOTIFY_MAX];
ngx_rtmp_enotify_conf_t *event[NGX_RTMP_ENOTIFY_MAX];
ngx_flag_t active;
} ngx_rtmp_enotify_app_conf_t;
@ -92,6 +98,14 @@ static ngx_command_t ngx_rtmp_enotify_commands[] = {
0,
NULL },
{ ngx_string("exec_record_done"),
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_RTMP_REC_CONF|
NGX_CONF_1MORE,
ngx_rtmp_enotify_on_event,
NGX_RTMP_APP_CONF_OFFSET,
0,
NULL },
ngx_null_command
};
@ -146,9 +160,8 @@ ngx_rtmp_enotify_merge_app_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_uint_t n;
for (n = 0; n < NGX_RTMP_ENOTIFY_MAX; ++n) {
ngx_conf_merge_ptr_value(conf->events[n], prev->events[n], 0);
if (conf->events[n]) {
ngx_conf_merge_ptr_value(conf->event[n], prev->event[n], 0);
if (conf->event[n]) {
conf->active = 1;
}
}
@ -157,21 +170,13 @@ ngx_rtmp_enotify_merge_app_conf(ngx_conf_t *cf, void *parent, void *child)
}
static char *
ngx_rtmp_exec_prepare_arg(ngx_rtmp_session_t *s, ngx_str_t *arg)
{
/*TODO*/
return (char *) arg->data;
}
static ngx_int_t
ngx_rtmp_enotify_exec(ngx_rtmp_session_t *s, ngx_rtmp_enotify_conf_t *ec)
{
#ifndef NGX_WIN32
ngx_rtmp_enotify_ctx_t *ctx;
int pid;
ngx_str_t *arg;
ngx_str_t a, *arg;
char **args;
ngx_uint_t n;
@ -194,7 +199,8 @@ ngx_rtmp_enotify_exec(ngx_rtmp_session_t *s, ngx_rtmp_enotify_conf_t *ec)
arg = ec->args.elts;
args[0] = (char *)ec->cmd.data;
for (n = 0; n < ec->args.nelts; ++n, ++arg) {
args[n + 1] = ngx_rtmp_exec_prepare_arg(s, arg);
ngx_rtmp_eval(s, arg, ngx_rtmp_eval_session, &a);
args[n + 1] = (char *) a.data;
}
args[n + 1] = NULL;
if (execvp((char *)ec->cmd.data, args) == -1) {
@ -265,7 +271,7 @@ ngx_rtmp_enotify_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
ngx_rtmp_enotify_init(s, v->name, v->args, NGX_RTMP_ENOTIFY_PUBLISHING);
ec = enacf->events[NGX_RTMP_ENOTIFY_PUBLISH];
ec = enacf->event[NGX_RTMP_ENOTIFY_PUBLISH];
if (ec == NULL) {
goto next;
@ -299,7 +305,7 @@ ngx_rtmp_enotify_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v)
ngx_rtmp_enotify_init(s, v->name, v->args, NGX_RTMP_ENOTIFY_PLAYING);
ec = enacf->events[NGX_RTMP_ENOTIFY_PLAY];
ec = enacf->event[NGX_RTMP_ENOTIFY_PLAY];
if (ec == NULL) {
goto next;
@ -342,10 +348,10 @@ ngx_rtmp_enotify_delete_stream(ngx_rtmp_session_t *s, ngx_rtmp_delete_stream_t
"enotify: delete_stream %ui",
ctx->flags);
if (enacf->events[NGX_RTMP_ENOTIFY_PUBLISH_DONE] &&
if (enacf->event[NGX_RTMP_ENOTIFY_PUBLISH_DONE] &&
(ctx->flags & NGX_RTMP_ENOTIFY_PUBLISHING))
{
ec = enacf->events[NGX_RTMP_ENOTIFY_PUBLISH_DONE];
ec = enacf->event[NGX_RTMP_ENOTIFY_PUBLISH_DONE];
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"enotify: publish_done '%V'", &ec->cmd);
@ -353,10 +359,10 @@ ngx_rtmp_enotify_delete_stream(ngx_rtmp_session_t *s, ngx_rtmp_delete_stream_t
ngx_rtmp_enotify_exec(s, ec);
}
if (enacf->events[NGX_RTMP_ENOTIFY_PLAY_DONE] &&
if (enacf->event[NGX_RTMP_ENOTIFY_PLAY_DONE] &&
(ctx->flags & NGX_RTMP_ENOTIFY_PLAYING))
{
ec = enacf->events[NGX_RTMP_ENOTIFY_PLAY_DONE];
ec = enacf->event[NGX_RTMP_ENOTIFY_PLAY_DONE];
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"enotify: play_done '%V'", &ec->cmd);
@ -371,13 +377,41 @@ next:
}
static ngx_int_t
ngx_rtmp_enotify_record_done(ngx_rtmp_session_t *s, ngx_rtmp_record_done_t *v)
{
ngx_rtmp_enotify_app_conf_t *enacf;
ngx_rtmp_enotify_conf_t *ec;
if (s->auto_pushed) {
goto next;
}
enacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_enotify_module);
if (enacf == NULL || enacf->event[NGX_RTMP_ENOTIFY_RECORD_DONE] == NULL) {
goto next;
}
ec = enacf->event[NGX_RTMP_ENOTIFY_RECORD_DONE];
ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"enotify: record_done %V recorder=%V path='%V'",
&ec->cmd, &v->recorder, &v->path);
ngx_rtmp_enotify_exec(s, ec);
next:
return next_record_done(s, v);
}
static char *
ngx_rtmp_enotify_on_event(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_rtmp_enotify_app_conf_t *enacf;
ngx_rtmp_enotify_conf_t *ec;
ngx_str_t *name, *value, *s;
size_t len, nargs;
size_t nargs;
ngx_uint_t n;
value = cf->args->elts;
@ -408,29 +442,31 @@ ngx_rtmp_enotify_on_event(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
enacf = ngx_rtmp_conf_get_module_app_conf(cf, ngx_rtmp_enotify_module);
len = name->len;
n = 0;
switch (name->data[6]) {
case 'l': /* exec_pLay... */
if (len == sizeof("exec_play") - 1) {
n = NGX_RTMP_ENOTIFY_PLAY;
} else {
n = NGX_RTMP_ENOTIFY_PLAY_DONE;
}
switch (name->len) {
case sizeof("exec_play") - 1:
n = NGX_RTMP_ENOTIFY_PLAY;
break;
case 'u': /* exec_pUblish... */
if (len == sizeof("exec_publish") - 1) {
n = NGX_RTMP_ENOTIFY_PUBLISH;
} else {
n = NGX_RTMP_ENOTIFY_PUBLISH_DONE;
}
case sizeof("exec_publish") - 1:
n = NGX_RTMP_ENOTIFY_PUBLISH;
break;
case sizeof("exec_play_done") - 1:
n = NGX_RTMP_ENOTIFY_PLAY_DONE;
break;
case sizeof("exec_record_done") - 1:
n = NGX_RTMP_ENOTIFY_RECORD_DONE;
break;
case sizeof("exec_publish_done") - 1:
n = NGX_RTMP_ENOTIFY_PUBLISH_DONE;
break;
}
enacf->events[n] = ec;
enacf->event[n] = ec;
return NGX_CONF_OK;
}
@ -448,5 +484,8 @@ ngx_rtmp_enotify_postconfiguration(ngx_conf_t *cf)
next_delete_stream = ngx_rtmp_delete_stream;
ngx_rtmp_delete_stream = ngx_rtmp_enotify_delete_stream;
next_record_done = ngx_rtmp_record_done;
ngx_rtmp_record_done = ngx_rtmp_enotify_record_done;
return NGX_OK;
}

View file

@ -9,11 +9,13 @@
#include "ngx_rtmp_cmd_module.h"
#include "ngx_rtmp_netcall_module.h"
#include "ngx_rtmp_record_module.h"
static ngx_rtmp_publish_pt next_publish;
static ngx_rtmp_play_pt next_play;
static ngx_rtmp_delete_stream_pt next_delete_stream;
static ngx_rtmp_record_done_pt next_record_done;
static char *ngx_rtmp_notify_on_event(ngx_conf_t *cf, ngx_command_t *cmd,
@ -29,12 +31,21 @@ static ngx_int_t ngx_rtmp_notify_done(ngx_rtmp_session_t *s, char *cbname,
#define NGX_RTMP_NOTIFY_PUBLISHING 0x01
#define NGX_RTMP_NOTIFY_PLAYING 0x02
enum {
NGX_RTMP_NOTIFY_PLAY,
NGX_RTMP_NOTIFY_PUBLISH,
NGX_RTMP_NOTIFY_PLAY_DONE,
NGX_RTMP_NOTIFY_PUBLISH_DONE,
NGX_RTMP_NOTIFY_DONE,
NGX_RTMP_NOTIFY_RECORD_DONE,
NGX_RTMP_NOTIFY_MAX
};
typedef struct {
ngx_url_t *publish_url;
ngx_url_t *play_url;
ngx_url_t *publish_done_url;
ngx_url_t *play_done_url;
ngx_url_t *done_url;
ngx_url_t *url[NGX_RTMP_NOTIFY_MAX];
ngx_flag_t active;
} ngx_rtmp_notify_app_conf_t;
@ -88,6 +99,14 @@ static ngx_command_t ngx_rtmp_notify_commands[] = {
0,
NULL },
{ ngx_string("on_record_done"),
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_RTMP_REC_CONF|
NGX_CONF_TAKE1,
ngx_rtmp_notify_on_event,
NGX_RTMP_APP_CONF_OFFSET,
0,
NULL },
ngx_null_command
};
@ -139,9 +158,14 @@ ngx_rtmp_notify_merge_app_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_rtmp_notify_app_conf_t *prev = parent;
ngx_rtmp_notify_app_conf_t *conf = child;
ngx_uint_t n;
ngx_conf_merge_ptr_value(conf->publish_url, prev->publish_url, 0);
ngx_conf_merge_ptr_value(conf->play_url, prev->play_url, 0);
for (n = 0; n < NGX_RTMP_NOTIFY_MAX; ++n) {
ngx_conf_merge_ptr_value(conf->url[n], prev->url[n], 0);
if (conf->url[n]) {
conf->active = 1;
}
}
return NGX_CONF_OK;
}
@ -211,8 +235,8 @@ ngx_rtmp_notify_publish_create(ngx_rtmp_session_t *s, void *arg,
}
/* HTTP header */
hl = ngx_rtmp_netcall_http_format_header(nacf->publish_url, pool,
cl->buf->last - cl->buf->pos + (pl->buf->last - pl->buf->pos),
hl = ngx_rtmp_netcall_http_format_header(nacf->url[NGX_RTMP_NOTIFY_PUBLISH],
pool, cl->buf->last - cl->buf->pos + (pl->buf->last - pl->buf->pos),
&ngx_rtmp_netcall_content_type_urlencoded);
if (hl == NULL) {
@ -291,8 +315,8 @@ ngx_rtmp_notify_play_create(ngx_rtmp_session_t *s, void *arg,
}
/* HTTP header */
hl = ngx_rtmp_netcall_http_format_header(nacf->play_url, pool,
cl->buf->last - cl->buf->pos + (pl->buf->last - pl->buf->pos),
hl = ngx_rtmp_netcall_http_format_header(nacf->url[NGX_RTMP_NOTIFY_PLAY],
pool, cl->buf->last - cl->buf->pos + (pl->buf->last - pl->buf->pos),
&ngx_rtmp_netcall_content_type_urlencoded);
if (hl == NULL) {
@ -386,6 +410,94 @@ ngx_rtmp_notify_done_create(ngx_rtmp_session_t *s, void *arg,
}
static ngx_chain_t *
ngx_rtmp_notify_record_done_create(ngx_rtmp_session_t *s, void *arg,
ngx_pool_t *pool)
{
ngx_rtmp_record_done_t *v = arg;
ngx_rtmp_notify_app_conf_t *nacf;
ngx_rtmp_notify_ctx_t *ctx;
ngx_chain_t *hl, *cl, *pl;
ngx_buf_t *b;
ngx_str_t *addr_text;
size_t name_len, args_len;
nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module);
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_notify_module);
/* common variables */
cl = ngx_rtmp_netcall_http_format_session(s, pool);
if (cl == NULL) {
return NULL;
}
/* publish variables */
pl = ngx_alloc_chain_link(pool);
if (pl == NULL) {
return NULL;
}
name_len = ngx_strlen(ctx->name);
args_len = ngx_strlen(ctx->args);
addr_text = &s->connection->addr_text;
b = ngx_create_temp_buf(pool,
sizeof("&call=record_done") +
sizeof("&recorder=") + v->recorder.len +
sizeof("&addr=") + addr_text->len +
sizeof("&name=") + name_len * 3 +
sizeof("&path=") + v->path.len * 3 +
+ 1 + args_len);
if (b == NULL) {
return NULL;
}
pl->buf = b;
b->last = ngx_cpymem(b->last, (u_char*)"&call=record_done",
sizeof("&call=record_done") - 1);
b->last = ngx_cpymem(b->last, (u_char *)"&recorder=",
sizeof("&recorder=") - 1);
b->last = (u_char*)ngx_escape_uri(b->last, v->recorder.data,
v->recorder.len, 0);
b->last = ngx_cpymem(b->last, (u_char*)"&addr=", sizeof("&addr=") -1);
b->last = (u_char*)ngx_escape_uri(b->last, addr_text->data,
addr_text->len, 0);
b->last = ngx_cpymem(b->last, (u_char*)"&name=", sizeof("&name=") - 1);
b->last = (u_char*)ngx_escape_uri(b->last, ctx->name, name_len, 0);
b->last = ngx_cpymem(b->last, (u_char*)"&path=", sizeof("&path=") - 1);
b->last = (u_char*)ngx_escape_uri(b->last, v->path.data, v->path.len, 0);
if (args_len) {
*b->last++ = '&';
b->last = (u_char *)ngx_cpymem(b->last, ctx->args, args_len);
}
/* HTTP header */
hl = ngx_rtmp_netcall_http_format_header(nacf->url[NGX_RTMP_NOTIFY_RECORD_DONE],
pool, cl->buf->last - cl->buf->pos + (pl->buf->last - pl->buf->pos),
&ngx_rtmp_netcall_content_type_urlencoded);
if (hl == NULL) {
return NULL;
}
hl->next = cl;
cl->next = pl;
pl->next = NULL;
return hl;
}
static ngx_int_t
ngx_rtmp_notify_parse_http_retcode(ngx_rtmp_session_t *s,
ngx_chain_t *in)
@ -457,10 +569,7 @@ ngx_rtmp_notify_init(ngx_rtmp_session_t *s,
nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module);
if (nacf->done_url == NULL &&
nacf->play_done_url == NULL &&
nacf->publish_done_url == NULL)
{
if (!nacf->active) {
return;
}
@ -500,16 +609,17 @@ ngx_rtmp_notify_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
ngx_rtmp_notify_init(s, v->name, v->args, NGX_RTMP_NOTIFY_PUBLISHING);
if (nacf->publish_url == NULL) {
if (nacf->url[NGX_RTMP_NOTIFY_PUBLISH] == NULL) {
goto next;
}
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"notify: publish '%V'", &nacf->publish_url->url);
"notify: publish '%V'",
&nacf->url[NGX_RTMP_NOTIFY_PUBLISH]);
ngx_memzero(&ci, sizeof(ci));
ci.url = nacf->publish_url;
ci.url = nacf->url[NGX_RTMP_NOTIFY_PUBLISH];
ci.create = ngx_rtmp_notify_publish_create;
ci.handle = ngx_rtmp_notify_publish_handle;
ci.arg = v;
@ -540,16 +650,17 @@ ngx_rtmp_notify_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v)
ngx_rtmp_notify_init(s, v->name, v->args, NGX_RTMP_NOTIFY_PLAYING);
if (nacf->play_url == NULL) {
if (nacf->url[NGX_RTMP_NOTIFY_PLAY] == NULL) {
goto next;
}
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"notify: play '%V'", &nacf->play_url->url);
"notify: play '%V'",
&nacf->url[NGX_RTMP_NOTIFY_PLAY]);
ngx_memzero(&ci, sizeof(ci));
ci.url = nacf->play_url;
ci.url = nacf->url[NGX_RTMP_NOTIFY_PLAY];
ci.create = ngx_rtmp_notify_play_create;
ci.handle = ngx_rtmp_notify_play_handle;
ci.arg = v;
@ -563,8 +674,8 @@ next:
static ngx_int_t
ngx_rtmp_notify_delete_stream(ngx_rtmp_session_t *s, ngx_rtmp_delete_stream_t
*v)
ngx_rtmp_notify_delete_stream(ngx_rtmp_session_t *s,
ngx_rtmp_delete_stream_t *v)
{
ngx_rtmp_notify_ctx_t *ctx;
ngx_rtmp_notify_app_conf_t *nacf;
@ -585,16 +696,22 @@ ngx_rtmp_notify_delete_stream(ngx_rtmp_session_t *s, ngx_rtmp_delete_stream_t
goto next;
}
if (nacf->publish_done_url && (ctx->flags & NGX_RTMP_NOTIFY_PUBLISHING)) {
ngx_rtmp_notify_done(s, "publish_done", nacf->publish_done_url);
if (nacf->url[NGX_RTMP_NOTIFY_PUBLISH_DONE] &&
(ctx->flags & NGX_RTMP_NOTIFY_PUBLISHING))
{
ngx_rtmp_notify_done(s, "publish_done",
nacf->url[NGX_RTMP_NOTIFY_PUBLISH_DONE]);
}
if (nacf->play_done_url && (ctx->flags & NGX_RTMP_NOTIFY_PLAYING)) {
ngx_rtmp_notify_done(s, "play_done", nacf->play_done_url);
if (nacf->url[NGX_RTMP_NOTIFY_PLAY_DONE] &&
(ctx->flags & NGX_RTMP_NOTIFY_PLAYING))
{
ngx_rtmp_notify_done(s, "play_done",
nacf->url[NGX_RTMP_NOTIFY_PLAY_DONE]);
}
if (nacf->done_url && ctx->flags) {
ngx_rtmp_notify_done(s, "done", nacf->done_url);
if (nacf->url[NGX_RTMP_NOTIFY_DONE] && ctx->flags) {
ngx_rtmp_notify_done(s, "done", nacf->url[NGX_RTMP_NOTIFY_DONE]);
}
ctx->flags = 0;
@ -604,6 +721,39 @@ next:
}
static ngx_int_t
ngx_rtmp_notify_record_done(ngx_rtmp_session_t *s, ngx_rtmp_record_done_t *v)
{
ngx_rtmp_netcall_init_t ci;
ngx_rtmp_notify_app_conf_t *nacf;
if (s->auto_pushed) {
goto next;
}
nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module);
if (nacf == NULL || nacf->url[NGX_RTMP_NOTIFY_RECORD_DONE] == NULL) {
goto next;
}
ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"notify: record_done recorder=%V path='%V' url='%V'",
&v->recorder, &v->path,
&nacf->url[NGX_RTMP_NOTIFY_RECORD_DONE]);
ngx_memzero(&ci, sizeof(ci));
ci.url = nacf->url[NGX_RTMP_NOTIFY_RECORD_DONE];
ci.create = ngx_rtmp_notify_record_done_create;
ci.arg = v;
ngx_rtmp_netcall_create(s, &ci);
next:
return next_record_done(s, v);
}
static ngx_int_t
ngx_rtmp_notify_done(ngx_rtmp_session_t *s, char *cbname, ngx_url_t *url)
{
@ -632,8 +782,9 @@ ngx_rtmp_notify_on_event(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_rtmp_notify_app_conf_t *nacf;
ngx_str_t *url, *name;
ngx_url_t *u;
size_t add, len;
size_t add;
ngx_str_t *value;
ngx_uint_t n;
value = cf->args->elts;
name = &value[0];
@ -665,30 +816,36 @@ ngx_rtmp_notify_on_event(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
nacf = ngx_rtmp_conf_get_module_app_conf(cf, ngx_rtmp_notify_module);
len = name->len;
n = 0;
switch (name->data[4]) {
case 'l': /* on_pLay... */
if (len == sizeof("on_play") - 1) {
nacf->play_url = u;
switch (name->len) {
case sizeof("on_done") - 1: /* and on_play */
if (name->data[3] == 'd') {
n = NGX_RTMP_NOTIFY_DONE;
} else {
nacf->play_done_url = u;
n = NGX_RTMP_NOTIFY_PLAY;
}
break;
case 'u': /* on_pUblish... */
if (len == sizeof("on_publish") - 1) {
nacf->publish_url = u;
} else {
nacf->publish_done_url = u;
}
case sizeof("on_publish") - 1:
n = NGX_RTMP_NOTIFY_PUBLISH;
break;
case 'o': /* on_dOne */
nacf->done_url = u;
case sizeof("on_play_done") - 1:
n = NGX_RTMP_NOTIFY_PLAY_DONE;
break;
case sizeof("on_record_done") - 1:
n = NGX_RTMP_NOTIFY_RECORD_DONE;
break;
case sizeof("on_publish_done") - 1:
n = NGX_RTMP_NOTIFY_PUBLISH_DONE;
break;
}
nacf->url[n] = u;
return NGX_CONF_OK;
}
@ -705,6 +862,8 @@ ngx_rtmp_notify_postconfiguration(ngx_conf_t *cf)
next_delete_stream = ngx_rtmp_delete_stream;
ngx_rtmp_delete_stream = ngx_rtmp_notify_delete_stream;
next_record_done = ngx_rtmp_record_done;
ngx_rtmp_record_done = ngx_rtmp_notify_record_done;
return NGX_OK;
}

View file

@ -12,6 +12,9 @@
#include "ngx_rtmp_record_module.h"
ngx_rtmp_record_done_pt ngx_rtmp_record_done;
static ngx_rtmp_publish_pt next_publish;
static ngx_rtmp_delete_stream_pt next_delete_stream;
@ -25,18 +28,18 @@ static void * ngx_rtmp_record_create_app_conf(ngx_conf_t *cf);
static char * ngx_rtmp_record_merge_app_conf(ngx_conf_t *cf,
void *parent, void *child);
static ngx_int_t ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s,
ngx_rtmp_record_node_ctx_t *rctx,
ngx_rtmp_record_rec_ctx_t *rctx,
ngx_rtmp_header_t *h, ngx_chain_t *in);
static ngx_int_t ngx_rtmp_record_av(ngx_rtmp_session_t *s,
ngx_rtmp_header_t *h, ngx_chain_t *in);
static ngx_int_t ngx_rtmp_record_node_av(ngx_rtmp_session_t *s,
ngx_rtmp_record_node_ctx_t *rctx, ngx_rtmp_header_t *h, ngx_chain_t *in);
ngx_rtmp_record_rec_ctx_t *rctx, ngx_rtmp_header_t *h, ngx_chain_t *in);
static ngx_int_t ngx_rtmp_record_node_open(ngx_rtmp_session_t *s,
ngx_rtmp_record_node_ctx_t *rctx);
ngx_rtmp_record_rec_ctx_t *rctx);
static ngx_int_t ngx_rtmp_record_node_close(ngx_rtmp_session_t *s,
ngx_rtmp_record_node_ctx_t *rctx);
static u_char * ngx_rtmp_record_make_path(ngx_rtmp_session_t *s,
ngx_rtmp_record_node_ctx_t *rctx);
ngx_rtmp_record_rec_ctx_t *rctx);
static void ngx_rtmp_record_make_path(ngx_rtmp_session_t *s,
ngx_rtmp_record_rec_ctx_t *rctx, ngx_str_t *path);
static ngx_int_t ngx_rtmp_record_init(ngx_rtmp_session_t *s);
@ -59,7 +62,7 @@ static ngx_command_t ngx_rtmp_record_commands[] = {
NGX_RTMP_REC_CONF|NGX_CONF_1MORE,
ngx_conf_set_bitmask_slot,
NGX_RTMP_APP_CONF_OFFSET,
offsetof(ngx_rtmp_record_app_conf_t, def.flags),
offsetof(ngx_rtmp_record_app_conf_t, flags),
ngx_rtmp_record_mask },
{ ngx_string("record_path"),
@ -67,7 +70,7 @@ static ngx_command_t ngx_rtmp_record_commands[] = {
NGX_RTMP_REC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_RTMP_APP_CONF_OFFSET,
offsetof(ngx_rtmp_record_app_conf_t, def.path),
offsetof(ngx_rtmp_record_app_conf_t, path),
NULL },
{ ngx_string("record_suffix"),
@ -75,7 +78,7 @@ static ngx_command_t ngx_rtmp_record_commands[] = {
NGX_RTMP_REC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_RTMP_APP_CONF_OFFSET,
offsetof(ngx_rtmp_record_app_conf_t, def.suffix),
offsetof(ngx_rtmp_record_app_conf_t, suffix),
NULL },
{ ngx_string("record_unique"),
@ -83,7 +86,7 @@ static ngx_command_t ngx_rtmp_record_commands[] = {
NGX_RTMP_REC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_flag_slot,
NGX_RTMP_APP_CONF_OFFSET,
offsetof(ngx_rtmp_record_app_conf_t, def.unique),
offsetof(ngx_rtmp_record_app_conf_t, unique),
NULL },
{ ngx_string("record_max_size"),
@ -91,7 +94,7 @@ static ngx_command_t ngx_rtmp_record_commands[] = {
NGX_RTMP_REC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_RTMP_APP_CONF_OFFSET,
offsetof(ngx_rtmp_record_app_conf_t, def.max_size),
offsetof(ngx_rtmp_record_app_conf_t, max_size),
NULL },
{ ngx_string("record_max_frames"),
@ -99,7 +102,7 @@ static ngx_command_t ngx_rtmp_record_commands[] = {
NGX_RTMP_REC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_RTMP_APP_CONF_OFFSET,
offsetof(ngx_rtmp_record_app_conf_t, def.max_frames),
offsetof(ngx_rtmp_record_app_conf_t, max_frames),
NULL },
{ ngx_string("record_interval"),
@ -107,7 +110,7 @@ static ngx_command_t ngx_rtmp_record_commands[] = {
NGX_RTMP_REC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_RTMP_APP_CONF_OFFSET,
offsetof(ngx_rtmp_record_app_conf_t, def.interval),
offsetof(ngx_rtmp_record_app_conf_t, interval),
NULL },
{ ngx_string("on_record_done"),
@ -169,18 +172,15 @@ ngx_rtmp_record_create_app_conf(ngx_conf_t *cf)
return NULL;
}
racf->def.max_size = NGX_CONF_UNSET;
racf->def.max_frames = NGX_CONF_UNSET;
racf->def.interval = NGX_CONF_UNSET;
racf->def.unique = NGX_CONF_UNSET;
racf->def.url = NGX_CONF_UNSET_PTR;
racf->max_size = NGX_CONF_UNSET;
racf->max_frames = NGX_CONF_UNSET;
racf->interval = NGX_CONF_UNSET;
racf->unique = NGX_CONF_UNSET;
racf->url = NGX_CONF_UNSET_PTR;
ngx_str_set(&racf->def.id, "default");
ngx_str_set(&racf->id, "default");
if (ngx_array_init(&racf->nodes, cf->pool, 1,
sizeof(ngx_rtmp_record_node_t *))
!= NGX_OK)
{
if (ngx_array_init(&racf->rec, cf->pool, 1, sizeof(void *)) != NGX_OK) {
return NULL;
}
@ -191,27 +191,27 @@ ngx_rtmp_record_create_app_conf(ngx_conf_t *cf)
static char *
ngx_rtmp_record_merge_app_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_rtmp_record_app_conf_t *prev = parent;
ngx_rtmp_record_app_conf_t *conf = child;
ngx_rtmp_record_node_t **node;
ngx_rtmp_record_app_conf_t *prev = parent;
ngx_rtmp_record_app_conf_t *conf = child;
ngx_rtmp_record_app_conf_t **rracf;
ngx_conf_merge_str_value(conf->def.path, prev->def.path, "");
ngx_conf_merge_str_value(conf->def.suffix, prev->def.suffix, ".flv");
ngx_conf_merge_size_value(conf->def.max_size, prev->def.max_size, 0);
ngx_conf_merge_size_value(conf->def.max_frames, prev->def.max_frames, 0);
ngx_conf_merge_value(conf->def.unique, prev->def.unique, 0);
ngx_conf_merge_msec_value(conf->def.interval, prev->def.interval,
ngx_conf_merge_str_value(conf->path, prev->path, "");
ngx_conf_merge_str_value(conf->suffix, prev->suffix, ".flv");
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_msec_value(conf->interval, prev->interval,
(ngx_msec_t) NGX_CONF_UNSET);
ngx_conf_merge_bitmask_value(conf->def.flags, prev->def.flags, 0);
ngx_conf_merge_ptr_value(conf->def.url, prev->def.url, NULL);
ngx_conf_merge_bitmask_value(conf->flags, prev->flags, 0);
ngx_conf_merge_ptr_value(conf->url, prev->url, NULL);
if (conf->def.flags) {
node = ngx_array_push(&conf->nodes);
if (node == NULL) {
if (conf->flags) {
rracf = ngx_array_push(&conf->rec);
if (rracf == NULL) {
return NGX_CONF_ERROR;
}
*node = &conf->def;
*rracf = conf;
}
return NGX_CONF_OK;
@ -243,11 +243,11 @@ ngx_rtmp_record_write_header(ngx_file_t *file)
}
static ngx_rtmp_record_node_ctx_t *
static ngx_rtmp_record_rec_ctx_t *
ngx_rtmp_record_get_node_ctx(ngx_rtmp_session_t *s, ngx_uint_t n)
{
ngx_rtmp_record_ctx_t *ctx;
ngx_rtmp_record_node_ctx_t *nodes;
ngx_rtmp_record_rec_ctx_t *rctx;
if (ngx_rtmp_record_init(s) != NGX_OK) {
return NULL;
@ -255,20 +255,20 @@ ngx_rtmp_record_get_node_ctx(ngx_rtmp_session_t *s, ngx_uint_t n)
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module);
if (n >= ctx->nodes.nelts) {
if (n >= ctx->rec.nelts) {
return NULL;
}
nodes = ctx->nodes.elts;
rctx = ctx->rec.elts;
return &nodes[n];
return &rctx[n];
}
ngx_int_t
ngx_rtmp_record_open(ngx_rtmp_session_t *s, ngx_uint_t n, u_char **path)
ngx_rtmp_record_open(ngx_rtmp_session_t *s, ngx_uint_t n, ngx_str_t *path)
{
ngx_rtmp_record_node_ctx_t *rctx;
ngx_rtmp_record_rec_ctx_t *rctx;
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"record: #%ui manual open", n);
@ -284,7 +284,7 @@ ngx_rtmp_record_open(ngx_rtmp_session_t *s, ngx_uint_t n, u_char **path)
}
if (path) {
*path = ngx_rtmp_record_make_path(s, rctx);
ngx_rtmp_record_make_path(s, rctx, path);
}
return NGX_OK;
@ -292,9 +292,9 @@ ngx_rtmp_record_open(ngx_rtmp_session_t *s, ngx_uint_t n, u_char **path)
ngx_int_t
ngx_rtmp_record_close(ngx_rtmp_session_t *s, ngx_uint_t n, u_char **path)
ngx_rtmp_record_close(ngx_rtmp_session_t *s, ngx_uint_t n, ngx_str_t *path)
{
ngx_rtmp_record_node_ctx_t *rctx;
ngx_rtmp_record_rec_ctx_t *rctx;
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"record: #%ui manual close", n);
@ -310,7 +310,7 @@ ngx_rtmp_record_close(ngx_rtmp_session_t *s, ngx_uint_t n, u_char **path)
}
if (path) {
*path = ngx_rtmp_record_make_path(s, rctx);
ngx_rtmp_record_make_path(s, rctx, path);
}
return NGX_OK;
@ -318,68 +318,69 @@ ngx_rtmp_record_close(ngx_rtmp_session_t *s, ngx_uint_t n, u_char **path)
/* This funcion returns pointer to a static buffer */
static u_char *
static void
ngx_rtmp_record_make_path(ngx_rtmp_session_t *s,
ngx_rtmp_record_node_ctx_t *rctx)
ngx_rtmp_record_rec_ctx_t *rctx, ngx_str_t *path)
{
ngx_rtmp_record_ctx_t *ctx;
ngx_rtmp_record_app_conf_t *rracf;
u_char *p, *l;
ngx_rtmp_record_node_t *rc;
static u_char buf[NGX_TIME_T_LEN + 1];
static u_char path[NGX_MAX_PATH + 1];
static u_char pbuf[NGX_MAX_PATH + 1];
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module);
rc = rctx->conf;
rracf = rctx->conf;
/* create file path */
p = path;
l = path + sizeof(path) - 1;
p = pbuf;
l = pbuf + sizeof(pbuf) - 1;
p = ngx_cpymem(p, rc->path.data,
ngx_min(rc->path.len, (size_t)(l - p - 1)));
p = ngx_cpymem(p, rracf->path.data,
ngx_min(rracf->path.len, (size_t)(l - p - 1)));
*p++ = '/';
p = (u_char *)ngx_escape_uri(p, ctx->name, ngx_min(ngx_strlen(ctx->name),
(size_t)(l - p)), NGX_ESCAPE_URI_COMPONENT);
/* append timestamp */
if (rc->unique) {
if (rracf->unique) {
p = ngx_cpymem(p, buf, ngx_min(ngx_sprintf(buf, "-%T",
rctx->timestamp) - buf, l - p));
}
p = ngx_cpymem(p, rc->suffix.data,
ngx_min(rc->suffix.len, (size_t)(l - p)));
p = ngx_cpymem(p, rracf->suffix.data,
ngx_min(rracf->suffix.len, (size_t)(l - p)));
*p = 0;
ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"record: %V path: '%s'", &rc->id, path);
path->data = pbuf;
path->len = p - pbuf;
return path;
ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"record: %V path: '%V'", &rracf->id, path);
}
static ngx_int_t
ngx_rtmp_record_node_open(ngx_rtmp_session_t *s,
ngx_rtmp_record_node_ctx_t *rctx)
ngx_rtmp_record_rec_ctx_t *rctx)
{
ngx_rtmp_record_node_t *rc;
ngx_rtmp_record_app_conf_t *rracf;
ngx_err_t err;
u_char *path;
ngx_str_t path;
rc = rctx->conf;
rracf = rctx->conf;
if (rctx->file.fd != NGX_INVALID_FILE) {
return NGX_OK;
}
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"record: %V opening", &rc->id);
"record: %V opening", &rracf->id);
rctx->timestamp = ngx_cached_time->sec;
path = ngx_rtmp_record_make_path(s, rctx);
ngx_rtmp_record_make_path(s, rctx, &path);
rctx->nframes = 0;
@ -388,7 +389,7 @@ ngx_rtmp_record_node_open(ngx_rtmp_session_t *s,
rctx->last = *ngx_cached_time;
rctx->file.offset = 0;
rctx->file.log = s->connection->log;
rctx->file.fd = ngx_open_file(path, NGX_FILE_WRONLY, NGX_FILE_TRUNCATE,
rctx->file.fd = ngx_open_file(path.data, NGX_FILE_WRONLY, NGX_FILE_TRUNCATE,
NGX_FILE_DEFAULT_ACCESS);
if (rctx->file.fd == NGX_INVALID_FILE) {
@ -396,15 +397,15 @@ ngx_rtmp_record_node_open(ngx_rtmp_session_t *s,
if (err != NGX_ENOENT) {
ngx_log_error(NGX_LOG_CRIT, s->connection->log, err,
"record: %V failed to open file '%s'",
&rc->id, path);
"record: %V failed to open file '%V'",
&rracf->id, &path);
}
return NGX_OK;
}
ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"record: %V opened '%s'", &rc->id, path);
"record: %V opened '%V'", &rracf->id, &path);
return NGX_OK;
}
@ -413,10 +414,9 @@ ngx_rtmp_record_node_open(ngx_rtmp_session_t *s,
static ngx_int_t
ngx_rtmp_record_init(ngx_rtmp_session_t *s)
{
ngx_rtmp_record_app_conf_t *racf;
ngx_rtmp_record_app_conf_t *racf, **rracf;
ngx_rtmp_record_rec_ctx_t *rctx;
ngx_rtmp_record_ctx_t *ctx;
ngx_rtmp_record_node_ctx_t *rctx;
ngx_rtmp_record_node_t **node;
ngx_uint_t n;
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module);
@ -427,7 +427,7 @@ ngx_rtmp_record_init(ngx_rtmp_session_t *s)
racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_record_module);
if (racf == NULL || racf->nodes.nelts == 0) {
if (racf == NULL || racf->rec.nelts == 0) {
return NGX_OK;
}
@ -439,25 +439,25 @@ ngx_rtmp_record_init(ngx_rtmp_session_t *s)
ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_record_module);
if (ngx_array_init(&ctx->nodes, s->connection->pool, racf->nodes.nelts,
sizeof(ngx_rtmp_record_node_ctx_t))
!= NGX_OK)
if (ngx_array_init(&ctx->rec, s->connection->pool, racf->rec.nelts,
sizeof(ngx_rtmp_record_rec_ctx_t))
!= NGX_OK)
{
return NGX_ERROR;
}
node = racf->nodes.elts;
rracf = racf->rec.elts;
rctx = ngx_array_push_n(&ctx->nodes, racf->nodes.nelts);
rctx = ngx_array_push_n(&ctx->rec, racf->rec.nelts);
if (rctx == NULL) {
return NGX_ERROR;
}
for (n = 0; n < racf->nodes.nelts; ++n, ++node, ++rctx) {
for (n = 0; n < racf->rec.nelts; ++n, ++rracf, ++rctx) {
ngx_memzero(rctx, sizeof(*rctx));
rctx->conf = *node;
rctx->conf = *rracf;
rctx->file.fd = NGX_INVALID_FILE;
}
@ -472,7 +472,7 @@ ngx_rtmp_record_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
ngx_rtmp_record_ctx_t *ctx;
u_char *p;
ngx_uint_t n;
ngx_rtmp_record_node_ctx_t *rctx;
ngx_rtmp_record_rec_ctx_t *rctx;
if (s->auto_pushed) {
goto next;
@ -480,7 +480,7 @@ ngx_rtmp_record_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_record_module);
if (racf == NULL || racf->nodes.nelts == 0) {
if (racf == NULL || racf->rec.nelts == 0) {
goto next;
}
@ -490,7 +490,7 @@ ngx_rtmp_record_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"record: publish %ui nodes",
racf->nodes.nelts);
racf->rec.nelts);
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module);
@ -508,9 +508,9 @@ ngx_rtmp_record_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
}
}
rctx = ctx->nodes.elts;
rctx = ctx->rec.elts;
for (n = 0; n < ctx->nodes.nelts; ++n, ++rctx) {
for (n = 0; n < ctx->rec.nelts; ++n, ++rctx) {
if (rctx->conf->flags & (NGX_RTMP_RECORD_OFF|NGX_RTMP_RECORD_MANUAL)) {
continue;
}
@ -523,127 +523,17 @@ next:
}
static ngx_chain_t *
ngx_rtmp_record_notify_create(ngx_rtmp_session_t *s, void *arg,
ngx_pool_t *pool)
{
ngx_rtmp_record_node_ctx_t *rctx = arg;
ngx_rtmp_record_node_t *rc;
ngx_rtmp_record_ctx_t *ctx;
ngx_chain_t *hl, *cl, *pl;
ngx_buf_t *b;
ngx_str_t *addr_text;
size_t path_len, name_len, args_len;
u_char *path;
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module);
rc = rctx->conf;
/* common variables */
cl = ngx_rtmp_netcall_http_format_session(s, pool);
if (cl == NULL) {
return NULL;
}
/* publish variables */
pl = ngx_alloc_chain_link(pool);
if (pl == NULL) {
return NULL;
}
path = ngx_rtmp_record_make_path(s, rctx);
path_len = ngx_strlen(path);
name_len = ngx_strlen(ctx->name);
args_len = ngx_strlen(ctx->args);
addr_text = &s->connection->addr_text;
b = ngx_create_temp_buf(pool,
sizeof("&call=record_done") +
sizeof("&recorder=") + rc->id.len +
sizeof("&addr=") + addr_text->len +
sizeof("&name=") + name_len * 3 +
sizeof("&path=") + path_len * 3 +
+ 1 + args_len);
if (b == NULL) {
return NULL;
}
pl->buf = b;
b->last = ngx_cpymem(b->last, (u_char*)"&call=record_done",
sizeof("&call=record_done") - 1);
b->last = ngx_cpymem(b->last, (u_char *)"&recorder=",
sizeof("&recorder=") - 1);
b->last = (u_char*)ngx_escape_uri(b->last, rc->id.data, rc->id.len, 0);
b->last = ngx_cpymem(b->last, (u_char*)"&addr=", sizeof("&addr=") -1);
b->last = (u_char*)ngx_escape_uri(b->last, addr_text->data,
addr_text->len, 0);
b->last = ngx_cpymem(b->last, (u_char*)"&name=", sizeof("&name=") - 1);
b->last = (u_char*)ngx_escape_uri(b->last, ctx->name, name_len, 0);
b->last = ngx_cpymem(b->last, (u_char*)"&path=", sizeof("&path=") - 1);
b->last = (u_char*)ngx_escape_uri(b->last, path, path_len, 0);
if (args_len) {
*b->last++ = '&';
b->last = (u_char *)ngx_cpymem(b->last, ctx->args, args_len);
}
/* HTTP header */
hl = ngx_rtmp_netcall_http_format_header(rctx->conf->url, pool,
cl->buf->last - cl->buf->pos + (pl->buf->last - pl->buf->pos),
&ngx_rtmp_netcall_content_type_urlencoded);
if (hl == NULL) {
return NULL;
}
hl->next = cl;
cl->next = pl;
pl->next = NULL;
return hl;
}
static ngx_int_t
ngx_rtmp_record_notify(ngx_rtmp_session_t *s, ngx_rtmp_record_node_ctx_t *rctx)
{
ngx_rtmp_netcall_init_t ci;
ngx_rtmp_record_node_t *rc;
rc = rctx->conf;
if (rc->url == NULL) {
return NGX_OK;
}
ngx_memzero(&ci, sizeof(ci));
ci.url = rc->url;
ci.create = ngx_rtmp_record_notify_create;
ci.arg = rctx;
return ngx_rtmp_netcall_create(s, &ci);
}
static ngx_int_t
ngx_rtmp_record_node_close(ngx_rtmp_session_t *s,
ngx_rtmp_record_node_ctx_t *rctx)
ngx_rtmp_record_rec_ctx_t *rctx)
{
ngx_rtmp_record_node_t *rc;
ngx_rtmp_record_app_conf_t *rracf;
ngx_err_t err;
void **app_conf;
ngx_int_t rc;
ngx_rtmp_record_done_t v;
rc = rctx->conf;
rracf = rctx->conf;
if (rctx->file.fd == NGX_INVALID_FILE) {
return NGX_OK;
@ -652,15 +542,28 @@ ngx_rtmp_record_node_close(ngx_rtmp_session_t *s,
if (ngx_close_file(rctx->file.fd) == NGX_FILE_ERROR) {
err = ngx_errno;
ngx_log_error(NGX_LOG_CRIT, s->connection->log, err,
"record: %V error closing file", &rc->id);
"record: %V error closing file", &rracf->id);
}
rctx->file.fd = NGX_INVALID_FILE;
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"record: %V closed", &rc->id);
"record: %V closed", &rracf->id);
return ngx_rtmp_record_notify(s, rctx);
app_conf = s->app_conf;
if (rracf->rec_conf) {
s->app_conf = rracf->rec_conf;
}
v.recorder = rracf->id;
ngx_rtmp_record_make_path(s, rctx, &v.path);
rc = ngx_rtmp_record_done(s, &v);
s->app_conf = app_conf;
return rc;
}
@ -669,7 +572,7 @@ ngx_rtmp_record_delete_stream(ngx_rtmp_session_t *s,
ngx_rtmp_delete_stream_t *v)
{
ngx_rtmp_record_ctx_t *ctx;
ngx_rtmp_record_node_ctx_t *rctx;
ngx_rtmp_record_rec_ctx_t *rctx;
ngx_uint_t n;
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module);
@ -680,11 +583,11 @@ ngx_rtmp_record_delete_stream(ngx_rtmp_session_t *s,
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"record: delete_stream %ui nodes",
ctx->nodes.nelts);
ctx->rec.nelts);
rctx = ctx->nodes.elts;
rctx = ctx->rec.elts;
for (n = 0; n < ctx->nodes.nelts; ++n, ++rctx) {
for (n = 0; n < ctx->rec.nelts; ++n, ++rctx) {
ngx_rtmp_record_node_close(s, rctx);
}
@ -695,17 +598,18 @@ next:
static ngx_int_t
ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s,
ngx_rtmp_record_node_ctx_t *rctx,
ngx_rtmp_record_rec_ctx_t *rctx,
ngx_rtmp_header_t *h, ngx_chain_t *in)
{
u_char hdr[11], *p, *ph;
uint32_t timestamp, tag_size;
ngx_rtmp_record_node_t *rc;
ngx_rtmp_record_app_conf_t *rracf;
rc = rctx->conf;
rracf = rctx->conf;
ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"record: %V frame: mlen=%uD", &rc->id, h->mlen);
"record: %V frame: mlen=%uD",
&rracf->id, h->mlen);
timestamp = h->timestamp - rctx->epoch;
@ -775,8 +679,8 @@ ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s,
++rctx->nframes;
/* watch max size */
if ((rc->max_size && rctx->file.offset >= (ngx_int_t) rc->max_size) ||
(rc->max_frames && rctx->nframes >= rc->max_frames))
if ((rracf->max_size && rctx->file.offset >= (ngx_int_t) rracf->max_size) ||
(rracf->max_frames && rctx->nframes >= rracf->max_frames))
{
ngx_rtmp_record_node_close(s, rctx);
}
@ -803,7 +707,7 @@ ngx_rtmp_record_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
ngx_chain_t *in)
{
ngx_rtmp_record_ctx_t *ctx;
ngx_rtmp_record_node_ctx_t *rctx;
ngx_rtmp_record_rec_ctx_t *rctx;
ngx_uint_t n;
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module);
@ -812,9 +716,9 @@ ngx_rtmp_record_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
return NGX_OK;
}
rctx = ctx->nodes.elts;
rctx = ctx->rec.elts;
for (n = 0; n < ctx->nodes.nelts; ++n, ++rctx) {
for (n = 0; n < ctx->rec.nelts; ++n, ++rctx) {
ngx_rtmp_record_node_av(s, rctx, h, in);
}
@ -823,30 +727,30 @@ ngx_rtmp_record_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
static ngx_int_t
ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_node_ctx_t *rctx,
ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx,
ngx_rtmp_header_t *h, ngx_chain_t *in)
{
ngx_time_t next;
ngx_rtmp_header_t ch;
ngx_rtmp_codec_ctx_t *codec_ctx;
ngx_int_t keyframe;
ngx_rtmp_record_node_t *rc;
ngx_rtmp_record_app_conf_t *rracf;
rc = rctx->conf;
rracf = rctx->conf;
if (rc->flags & NGX_RTMP_RECORD_OFF) {
if (rracf->flags & NGX_RTMP_RECORD_OFF) {
ngx_rtmp_record_node_close(s, rctx);
return NGX_OK;
}
keyframe = (ngx_rtmp_get_video_frame_type(in) == NGX_RTMP_VIDEO_KEY_FRAME);
if (keyframe && (rc->flags & NGX_RTMP_RECORD_MANUAL) == 0) {
if (keyframe && (rracf->flags & NGX_RTMP_RECORD_MANUAL) == 0) {
if (rc->interval != (ngx_msec_t) NGX_CONF_UNSET) {
if (rracf->interval != (ngx_msec_t) NGX_CONF_UNSET) {
next = rctx->last;
next.msec += rc->interval;
next.msec += rracf->interval;
next.sec += (next.msec / 1000);
next.msec %= 1000;
@ -868,14 +772,14 @@ ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_node_ctx_t *rctx,
}
if (h->type == NGX_RTMP_MSG_AUDIO &&
(rc->flags & NGX_RTMP_RECORD_AUDIO) == 0)
(rracf->flags & NGX_RTMP_RECORD_AUDIO) == 0)
{
return NGX_OK;
}
if (h->type == NGX_RTMP_MSG_VIDEO &&
(rc->flags & NGX_RTMP_RECORD_VIDEO) == 0 &&
((rc->flags & NGX_RTMP_RECORD_KEYFRAMES) == 0 || !keyframe))
(rracf->flags & NGX_RTMP_RECORD_VIDEO) == 0 &&
((rracf->flags & NGX_RTMP_RECORD_KEYFRAMES) == 0 || !keyframe))
{
return NGX_OK;
}
@ -907,10 +811,10 @@ ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_node_ctx_t *rctx,
}
#endif
/* AAC header */
if (codec_ctx->aac_header && (rc->flags & NGX_RTMP_RECORD_AUDIO))
if (codec_ctx->aac_header && (rracf->flags & NGX_RTMP_RECORD_AUDIO))
{
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"record: %V writing AAC header", &rc->id);
"record: %V writing AAC header", &rracf->id);
ch.type = NGX_RTMP_MSG_AUDIO;
ch.mlen = ngx_rtmp_record_get_chain_mlen(codec_ctx->aac_header);
@ -924,10 +828,11 @@ ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_node_ctx_t *rctx,
/* AVC header */
if (codec_ctx->avc_header &&
(rc->flags & (NGX_RTMP_RECORD_VIDEO|NGX_RTMP_RECORD_KEYFRAMES)))
(rracf->flags & (NGX_RTMP_RECORD_VIDEO|
NGX_RTMP_RECORD_KEYFRAMES)))
{
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"record: %V writing AVC header", &rc->id);
"record: %V writing AVC header", &rracf->id);
ch.type = NGX_RTMP_MSG_VIDEO;
ch.mlen = ngx_rtmp_record_get_chain_mlen(codec_ctx->avc_header);
@ -945,6 +850,13 @@ ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_node_ctx_t *rctx,
}
static ngx_int_t
ngx_rtmp_record_done_init(ngx_rtmp_session_t *s, ngx_rtmp_record_done_t *v)
{
return NGX_OK;
}
static char *
ngx_rtmp_notify_on_record_done(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
@ -983,7 +895,7 @@ ngx_rtmp_notify_on_record_done(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
racf = ngx_rtmp_conf_get_module_app_conf(cf, ngx_rtmp_record_module);
racf->def.url = u;
racf->url = u;
return NGX_CONF_OK;
}
@ -997,10 +909,11 @@ ngx_rtmp_record_recorder(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_str_t *value;
ngx_conf_t save;
ngx_rtmp_module_t *module;
ngx_rtmp_record_app_conf_t *racf, *rracf;
ngx_rtmp_record_node_t **prc, *rc;
ngx_rtmp_record_app_conf_t *racf, **pracf, *rracf;
ngx_rtmp_conf_ctx_t *ctx, *pctx;
value = cf->args->elts;
racf = ngx_rtmp_conf_get_module_app_conf(cf, ngx_rtmp_record_module);
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_conf_ctx_t));
@ -1034,19 +947,17 @@ ngx_rtmp_record_recorder(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
}
prc = ngx_array_push(&racf->nodes);
if (prc == NULL) {
rracf = ctx->app_conf[ngx_rtmp_record_module.ctx_index];
rracf->rec_conf = ctx->app_conf;
rracf->id = value[1];
pracf = ngx_array_push(&racf->rec);
if (pracf == NULL) {
return NGX_CONF_ERROR;
}
rracf = ctx->app_conf[ngx_rtmp_record_module.ctx_index];
rc = &rracf->def;
value = cf->args->elts;
rc->id = value[1];
*prc = rc;
*pracf = rracf;
save = *cf;
cf->ctx = ctx;
@ -1054,9 +965,22 @@ ngx_rtmp_record_recorder(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
rv = ngx_conf_parse(cf, NULL);
rvm = ngx_rtmp_record_merge_app_conf(cf, racf, rracf);
if (rvm != NGX_CONF_OK) {
return rvm;
for (i = 0; ngx_modules[i]; i++) {
if (ngx_modules[i]->type != NGX_RTMP_MODULE) {
continue;
}
module = ngx_modules[i]->ctx;
if (module->merge_app_conf) {
rvm = module->merge_app_conf(cf,
pctx->app_conf[ngx_modules[i]->ctx_index],
ctx->app_conf[ngx_modules[i]->ctx_index]);
if (rvm != NGX_CONF_OK) {
return NGX_CONF_ERROR;
}
}
}
*cf= save;
@ -1071,6 +995,8 @@ ngx_rtmp_record_postconfiguration(ngx_conf_t *cf)
ngx_rtmp_core_main_conf_t *cmcf;
ngx_rtmp_handler_pt *h;
ngx_rtmp_record_done = ngx_rtmp_record_done_init;
cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module);
h = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_AUDIO]);

View file

@ -27,27 +27,24 @@ typedef struct {
ngx_str_t suffix;
ngx_flag_t unique;
ngx_url_t *url;
} ngx_rtmp_record_node_t;
typedef struct {
ngx_rtmp_record_node_t def;
ngx_array_t nodes; /* ngx_rtmp_record_node_t * */
void **rec_conf;
ngx_array_t rec; /* ngx_rtmp_record_app_conf_t * */
} ngx_rtmp_record_app_conf_t;
typedef struct {
ngx_rtmp_record_node_t *conf;
ngx_rtmp_record_app_conf_t *conf;
ngx_file_t file;
ngx_uint_t nframes;
uint32_t epoch;
ngx_time_t last;
time_t timestamp;
} ngx_rtmp_record_node_ctx_t;
} ngx_rtmp_record_rec_ctx_t;
typedef struct {
ngx_array_t nodes; /* ngx_rtmp_record_node_ctx_t */
ngx_array_t rec; /* ngx_rtmp_record_rec_ctx_t */
u_char name[NGX_RTMP_MAX_NAME];
u_char args[NGX_RTMP_MAX_ARGS];
} ngx_rtmp_record_ctx_t;
@ -55,12 +52,25 @@ typedef struct {
/* Manual recording control,
* 'n' is record node index in config array.
* Note: these functions return path as pointer to a static buffer */
* Note: these functions allocate path in static buffer */
ngx_int_t ngx_rtmp_record_open(ngx_rtmp_session_t *s, ngx_uint_t n,
u_char **path);
ngx_str_t *path);
ngx_int_t ngx_rtmp_record_close(ngx_rtmp_session_t *s, ngx_uint_t n,
u_char **path);
ngx_str_t *path);
typedef struct {
ngx_str_t recorder;
ngx_str_t path;
} ngx_rtmp_record_done_t;
typedef ngx_int_t (*ngx_rtmp_record_done_pt)(ngx_rtmp_session_t *s,
ngx_rtmp_record_done_t *v);
extern ngx_rtmp_record_done_pt ngx_rtmp_record_done;
extern ngx_module_t ngx_rtmp_record_module;