"exec_record_started" event and "on_record_started" notification added fired when the system starts the recording process

This commit is contained in:
Diego Stamigni 2017-02-08 18:44:44 +00:00
parent 9c71ce6761
commit 6b8155cf3b
6 changed files with 239 additions and 0 deletions

1
.gitignore vendored
View file

@ -2,3 +2,4 @@
/.settings
/.project
/.cproject
/.vscode

View file

@ -35,6 +35,7 @@ Table of Contents
* [exec_play](#exec_play)
* [exec_play_done](#exec_play_done)
* [exec_publish_done](#exec_publish_done)
* [exec_record_started](#exec_record_started)
* [exec_record_done](#exec_record_done)
* [Live](#live)
* [live](#live)
@ -76,6 +77,7 @@ Table of Contents
* [on_done](#on_done)
* [on_play_done](#on_play_done)
* [on_publish_done](#on_publish_done)
* [on_record_started](#on_record_started)
* [on_record_done](#on_record_done)
* [on_update](#on_update)
* [notify_update_timeout](#notify_update_timeout)
@ -479,6 +481,18 @@ Specifies external command with arguments to be executed on
publish_done event. Return code is not analyzed. Substitution list
is the same as for `exec_publish`.
#### exec_record_started
Syntax: `exec_record_started command arg*`
Context: rtmp, server, application, recorder
Specifies external command with arguments to be executed when
recording is started.
* `recorder` - recorder name
* `path` - recorded file path (`/tmp/rec/mystream-1389499351.flv`)
* `filename` - path with directory omitted (`mystream-1389499351.flv`)
* `basename` - file name with extension omitted (`mystream-1389499351`)
* `dirname` - directory path (`/tmp/rec`)
#### exec_record_done
Syntax: `exec_record_done command arg*`
Context: rtmp, server, application, recorder
@ -1106,6 +1120,16 @@ Context: rtmp, server, application
Same behavior as `on_done` but only for publish end event.
#### on_record_started
syntax: `on_record_started url`
context: rtmp, server, application, recorder
Set record_started callback. In addition to common HTTP callback
variables it receives the following values
* recorder - recorder name in config or empty string for inline recorder
* path - recording file path
#### on_record_done
syntax: `on_record_done url`
context: rtmp, server, application, recorder

View file

@ -20,6 +20,7 @@
static ngx_rtmp_publish_pt next_publish;
static ngx_rtmp_play_pt next_play;
static ngx_rtmp_close_stream_pt next_close_stream;
static ngx_rtmp_record_started_pt next_record_started;
static ngx_rtmp_record_done_pt next_record_done;
#endif
@ -55,6 +56,7 @@ enum {
NGX_RTMP_EXEC_PUBLISH_DONE,
NGX_RTMP_EXEC_PLAY,
NGX_RTMP_EXEC_PLAY_DONE,
NGX_RTMP_EXEC_RECORD_STARTED,
NGX_RTMP_EXEC_RECORD_DONE,
NGX_RTMP_EXEC_MAX,
@ -208,6 +210,15 @@ static ngx_command_t ngx_rtmp_exec_commands[] = {
NGX_RTMP_EXEC_PLAY_DONE * sizeof(ngx_array_t),
NULL },
{ ngx_string("exec_record_started"),
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_RTMP_REC_CONF|
NGX_CONF_1MORE,
ngx_rtmp_exec_conf,
NGX_RTMP_APP_CONF_OFFSET,
offsetof(ngx_rtmp_exec_app_conf_t, conf) +
NGX_RTMP_EXEC_RECORD_STARTED * sizeof(ngx_array_t),
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,
@ -1307,6 +1318,64 @@ next:
}
static ngx_int_t
ngx_rtmp_exec_record_started(ngx_rtmp_session_t *s, ngx_rtmp_record_started_t *v)
{
u_char c;
ngx_uint_t ext, dir;
ngx_rtmp_exec_ctx_t *ctx;
ngx_rtmp_exec_app_conf_t *eacf;
if (s->auto_pushed) {
goto next;
}
eacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_exec_module);
if (eacf == NULL || !eacf->active) {
goto next;
}
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_exec_module);
if (ctx == NULL) {
goto next;
}
ctx->recorder = v->recorder;
ctx->path = v->path;
ctx->dirname.data = ctx->path.data;
ctx->dirname.len = 0;
for (dir = ctx->path.len; dir > 0; dir--) {
c = ctx->path.data[dir - 1];
if (c == '/' || c == '\\') {
ctx->dirname.len = dir - 1;
break;
}
}
ctx->filename.data = ctx->path.data + dir;
ctx->filename.len = ctx->path.len - dir;
ctx->basename = ctx->filename;
for (ext = ctx->filename.len; ext > 0; ext--) {
if (ctx->filename.data[ext - 1] == '.') {
ctx->basename.len = ext - 1;
break;
}
}
ngx_rtmp_exec_unmanaged(s, &eacf->conf[NGX_RTMP_EXEC_RECORD_STARTED],
"record_started");
ngx_str_null(&v->recorder);
ngx_str_null(&v->path);
next:
return next_record_started(s, v);
}
static ngx_int_t
ngx_rtmp_exec_record_done(ngx_rtmp_session_t *s, ngx_rtmp_record_done_t *v)
{
@ -1364,6 +1433,7 @@ ngx_rtmp_exec_record_done(ngx_rtmp_session_t *s, ngx_rtmp_record_done_t *v)
next:
return next_record_done(s, v);
}
#endif /* NGX_WIN32 */
@ -1603,6 +1673,9 @@ ngx_rtmp_exec_postconfiguration(ngx_conf_t *cf)
next_record_done = ngx_rtmp_record_done;
ngx_rtmp_record_done = ngx_rtmp_exec_record_done;
next_record_started = ngx_rtmp_record_started;
ngx_rtmp_record_started = ngx_rtmp_exec_record_started;
#endif /* NGX_WIN32 */
return NGX_OK;

View file

@ -19,6 +19,7 @@ static ngx_rtmp_disconnect_pt next_disconnect;
static ngx_rtmp_publish_pt next_publish;
static ngx_rtmp_play_pt next_play;
static ngx_rtmp_close_stream_pt next_close_stream;
static ngx_rtmp_record_started_pt next_record_started;
static ngx_rtmp_record_done_pt next_record_done;
static ngx_rtmp_playlist_pt next_playlist;
@ -56,6 +57,7 @@ enum {
NGX_RTMP_NOTIFY_PLAY_DONE,
NGX_RTMP_NOTIFY_PUBLISH_DONE,
NGX_RTMP_NOTIFY_DONE,
NGX_RTMP_NOTIFY_RECORD_STARTED,
NGX_RTMP_NOTIFY_RECORD_DONE,
NGX_RTMP_NOTIFY_UPDATE,
NGX_RTMP_NOTIFY_PLAYLIST,
@ -154,6 +156,14 @@ static ngx_command_t ngx_rtmp_notify_commands[] = {
0,
NULL },
{ ngx_string("on_record_started"),
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_RTMP_REC_CONF|
NGX_CONF_TAKE1,
ngx_rtmp_notify_on_app_event,
NGX_RTMP_APP_CONF_OFFSET,
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,
@ -823,6 +833,69 @@ ngx_rtmp_notify_update_create(ngx_rtmp_session_t *s, void *arg,
}
static ngx_chain_t *
ngx_rtmp_notify_record_started_create(ngx_rtmp_session_t *s, void *arg,
ngx_pool_t *pool)
{
ngx_rtmp_record_started_t *v = arg;
ngx_rtmp_notify_ctx_t *ctx;
ngx_chain_t *pl;
ngx_buf_t *b;
size_t name_len, args_len;
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_notify_module);
pl = ngx_alloc_chain_link(pool);
if (pl == NULL) {
return NULL;
}
name_len = ngx_strlen(ctx->name);
args_len = ngx_strlen(ctx->args);
b = ngx_create_temp_buf(pool,
sizeof("call=record_done") +
sizeof("&recorder=") + v->recorder.len +
sizeof("&name=") + name_len * 3 +
sizeof("&path=") + v->path.len * 3 +
1 + args_len + 1);
if (b == NULL) {
return NULL;
}
pl->buf = b;
pl->next = NULL;
if (args_len) {
b->last = (u_char *) ngx_cpymem(b->last, ctx->args, args_len);
*b->last++ = '&';
}
b->last = ngx_cpymem(b->last, (u_char*) "call=record_started",
sizeof("call=record_started") - 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, NGX_ESCAPE_ARGS);
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,
NGX_ESCAPE_ARGS);
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,
NGX_ESCAPE_ARGS);
*b->last++ = '&';
return ngx_rtmp_notify_create_request(s, pool, NGX_RTMP_NOTIFY_RECORD_STARTED,
pl);
}
static ngx_chain_t *
ngx_rtmp_notify_record_done_create(ngx_rtmp_session_t *s, void *arg,
ngx_pool_t *pool)
@ -1862,6 +1935,39 @@ next:
}
static ngx_int_t
ngx_rtmp_notify_record_started(ngx_rtmp_session_t *s, ngx_rtmp_record_started_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_STARTED] == NULL) {
goto next;
}
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
"notify: record_started recorder=%V path='%V' url='%V'",
&v->recorder, &v->path,
&nacf->url[NGX_RTMP_NOTIFY_RECORD_DONE]->url);
ngx_memzero(&ci, sizeof(ci));
ci.url = nacf->url[NGX_RTMP_NOTIFY_RECORD_STARTED];
ci.create = ngx_rtmp_notify_record_started_create;
ci.arg = v;
ngx_rtmp_netcall_create(s, &ci);
next:
return next_record_started(s, v);
}
static ngx_int_t
ngx_rtmp_notify_record_done(ngx_rtmp_session_t *s, ngx_rtmp_record_done_t *v)
{
@ -2070,6 +2176,10 @@ ngx_rtmp_notify_on_app_event(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
n = NGX_RTMP_NOTIFY_PLAY_DONE;
break;
case sizeof("on_record_started") - 1:
n = NGX_RTMP_NOTIFY_RECORD_STARTED;
break;
case sizeof("on_record_done") - 1:
n = NGX_RTMP_NOTIFY_RECORD_DONE;
break;
@ -2166,6 +2276,9 @@ ngx_rtmp_notify_postconfiguration(ngx_conf_t *cf)
next_close_stream = ngx_rtmp_close_stream;
ngx_rtmp_close_stream = ngx_rtmp_notify_close_stream;
next_record_started = ngx_rtmp_record_started;
ngx_rtmp_record_started = ngx_rtmp_notify_record_started;
next_record_done = ngx_rtmp_record_done;
ngx_rtmp_record_done = ngx_rtmp_notify_record_done;

View file

@ -13,6 +13,7 @@
#include "ngx_rtmp_record_module.h"
ngx_rtmp_record_started_pt ngx_rtmp_record_started;
ngx_rtmp_record_done_pt ngx_rtmp_record_done;
@ -660,6 +661,7 @@ ngx_rtmp_record_start(ngx_rtmp_session_t *s)
ngx_rtmp_record_app_conf_t *racf;
ngx_rtmp_record_rec_ctx_t *rctx;
ngx_rtmp_record_ctx_t *ctx;
ngx_rtmp_record_started_t v;
ngx_uint_t n;
racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_record_module);
@ -682,6 +684,11 @@ ngx_rtmp_record_start(ngx_rtmp_session_t *s)
}
ngx_rtmp_record_node_open(s, rctx);
}
v.recorder = racf->id;
ngx_rtmp_record_make_path(s, rctx, &v.path);
ngx_rtmp_record_started(s, &v);
}
@ -1201,6 +1208,12 @@ ngx_rtmp_record_node_avd(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx,
}
static ngx_int_t
ngx_rtmp_record_started_init(ngx_rtmp_session_t *s, ngx_rtmp_record_started_t *v)
{
return NGX_OK;
}
static ngx_int_t
ngx_rtmp_record_done_init(ngx_rtmp_session_t *s, ngx_rtmp_record_done_t *v)
{
@ -1301,6 +1314,8 @@ ngx_rtmp_record_postconfiguration(ngx_conf_t *cf)
ngx_rtmp_core_main_conf_t *cmcf;
ngx_rtmp_handler_pt *h;
ngx_rtmp_record_started = ngx_rtmp_record_started_init;
ngx_rtmp_record_done = ngx_rtmp_record_done_init;
cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module);

View file

@ -84,10 +84,23 @@ typedef struct {
} ngx_rtmp_record_done_t;
typedef struct {
ngx_str_t recorder;
ngx_str_t path;
} ngx_rtmp_record_started_t;
typedef ngx_int_t (*ngx_rtmp_record_started_pt)(ngx_rtmp_session_t *s,
ngx_rtmp_record_started_t *v);
typedef ngx_int_t (*ngx_rtmp_record_done_pt)(ngx_rtmp_session_t *s,
ngx_rtmp_record_done_t *v);
extern ngx_rtmp_record_started_pt ngx_rtmp_record_started;
extern ngx_rtmp_record_done_pt ngx_rtmp_record_done;