mirror of
https://github.com/zotanmew/nginx-rtmp-module.git
synced 2024-06-29 08:18:58 +02:00
merged master into sync
o sync # Please enter a commit message to explain why this merge is necessary, # especially if it merges an updated upstream into a topic branch. # # Lines starting with '#' will be ignored, and an empty message aborts # the commit.
This commit is contained in:
commit
ac13bbf1af
18
README.md
18
README.md
|
@ -2,13 +2,13 @@
|
|||
## nginx-rtmp-module
|
||||
|
||||
|
||||
### Project page:
|
||||
### Project blog:
|
||||
|
||||
http://arut.github.com/nginx-rtmp-module
|
||||
http://rarut.wordpress.com
|
||||
|
||||
### Wiki manual:
|
||||
|
||||
https://github.com/arut/nginx-rtmp-module/wiki
|
||||
https://github.com/arut/nginx-rtmp-module/wiki/Directives
|
||||
|
||||
### Features:
|
||||
|
||||
|
@ -19,17 +19,19 @@
|
|||
* Stream relay support for distributed
|
||||
streaming: push & pull models
|
||||
|
||||
* Recording published streams in FLV file
|
||||
* Recording streams in multiple FLVs
|
||||
|
||||
* H264/AAC support
|
||||
|
||||
* Online transcoding with FFmpeg
|
||||
|
||||
* HLS (HTTP Live Streaming) support;
|
||||
experimental; requires recent libavformat
|
||||
requires recent libavformat
|
||||
(>= 53.31.100) from ffmpeg (ffmpeg.org)
|
||||
|
||||
* HTTP callbacks on publish/play/record
|
||||
* HTTP callbacks (publish/play/record etc)
|
||||
|
||||
* Running external programs on certain events (exec)
|
||||
|
||||
* Advanced buffering techniques
|
||||
to keep memory allocations at a minimum
|
||||
|
@ -44,6 +46,8 @@
|
|||
* Statistics in XML/XSL in machine- & human-
|
||||
readable form
|
||||
|
||||
* Linux/FreeBSD/MacOS
|
||||
|
||||
|
||||
### Build:
|
||||
|
||||
|
@ -197,7 +201,7 @@ rtmp_auto_push directive.
|
|||
}
|
||||
|
||||
|
||||
# HLS (experimental)
|
||||
# HLS
|
||||
|
||||
# HLS requires libavformat & should be configured as a separate
|
||||
# NGINX module in addition to nginx-rtmp-module:
|
||||
|
|
12
config
12
config
|
@ -5,16 +5,18 @@ 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_notify_module \
|
||||
ngx_rtmp_relay_module \
|
||||
ngx_rtmp_exec_module \
|
||||
ngx_rtmp_codec_module \
|
||||
ngx_rtmp_auto_push_module \
|
||||
ngx_rtmp_enotify_module \
|
||||
ngx_rtmp_notify_module \
|
||||
"
|
||||
|
||||
|
||||
|
@ -31,23 +33,25 @@ 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_notify_module.c \
|
||||
$ngx_addon_dir/ngx_rtmp_stat_module.c \
|
||||
$ngx_addon_dir/ngx_rtmp_relay_module.c \
|
||||
$ngx_addon_dir/ngx_rtmp_bandwidth.c \
|
||||
$ngx_addon_dir/ngx_rtmp_exec_module.c \
|
||||
$ngx_addon_dir/ngx_rtmp_codec_module.c \
|
||||
$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 \
|
||||
"
|
||||
CFLAGS="$CFLAGS -I$ngx_addon_dir"
|
||||
|
||||
|
|
|
@ -317,6 +317,7 @@ ngx_rtmp_merge_applications(ngx_conf_t *cf, ngx_array_t *applications,
|
|||
ngx_rtmp_conf_ctx_t *ctx, saved;
|
||||
ngx_rtmp_core_app_conf_t **cacfp;
|
||||
ngx_uint_t n;
|
||||
ngx_rtmp_core_app_conf_t *cacf;
|
||||
|
||||
if (applications == NULL) {
|
||||
return NGX_CONF_OK;
|
||||
|
@ -335,6 +336,14 @@ ngx_rtmp_merge_applications(ngx_conf_t *cf, ngx_array_t *applications,
|
|||
if (rv != NGX_CONF_OK) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
cacf = (*cacfp)->app_conf[ngx_rtmp_core_module.ctx_index];
|
||||
rv = ngx_rtmp_merge_applications(cf, &cacf->applications,
|
||||
(*cacfp)->app_conf,
|
||||
module, ctx_index);
|
||||
if (rv != NGX_CONF_OK) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
*ctx = saved;
|
||||
|
|
|
@ -209,6 +209,7 @@ typedef struct {
|
|||
|
||||
/* auto-pushed? */
|
||||
unsigned auto_pushed:1;
|
||||
unsigned relay:1;
|
||||
|
||||
/* input stream 0 (reserved by RTMP spec)
|
||||
* is used as free chain link */
|
||||
|
@ -294,6 +295,7 @@ typedef struct ngx_rtmp_core_srv_conf_s {
|
|||
|
||||
|
||||
typedef struct {
|
||||
ngx_array_t applications; /* ngx_rtmp_core_app_conf_t */
|
||||
ngx_str_t name;
|
||||
void **app_conf;
|
||||
} ngx_rtmp_core_app_conf_t;
|
||||
|
@ -326,6 +328,7 @@ typedef struct {
|
|||
#define NGX_RTMP_MAIN_CONF 0x02000000
|
||||
#define NGX_RTMP_SRV_CONF 0x04000000
|
||||
#define NGX_RTMP_APP_CONF 0x08000000
|
||||
#define NGX_RTMP_REC_CONF 0x10000000
|
||||
|
||||
|
||||
#define NGX_RTMP_MAIN_CONF_OFFSET offsetof(ngx_rtmp_conf_ctx_t, main_conf)
|
||||
|
|
|
@ -400,7 +400,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) {
|
||||
if (s->auto_pushed || s->relay) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
|
|
|
@ -200,7 +200,7 @@ ngx_rtmp_cmd_connect(ngx_rtmp_session_t *s, ngx_rtmp_connect_t *v)
|
|||
|
||||
cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module);
|
||||
|
||||
ngx_log_debug8(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"connect: app='%s' flashver='%s' swf_url='%s' "
|
||||
"tc_url='%s' page_url='%s' acodecs=%uD vcodecs=%uD "
|
||||
"object_encoding=%ui",
|
||||
|
@ -327,7 +327,7 @@ ngx_rtmp_cmd_create_stream(ngx_rtmp_session_t *s, ngx_rtmp_create_stream_t *v)
|
|||
h.csid = NGX_RTMP_CMD_CSID_AMF_INI;
|
||||
h.type = NGX_RTMP_MSG_AMF_CMD;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"createStream");
|
||||
|
||||
/* send result with standard stream */
|
||||
|
@ -415,6 +415,9 @@ ngx_rtmp_cmd_delete_stream(ngx_rtmp_session_t *s, ngx_rtmp_delete_stream_t *v)
|
|||
{
|
||||
ngx_rtmp_close_stream_t cv;
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"deleteStream");
|
||||
|
||||
/* chain close_stream */
|
||||
cv.stream = 0;
|
||||
return ngx_rtmp_close_stream
|
||||
|
@ -523,7 +526,7 @@ ngx_rtmp_cmd_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
|
|||
out_inf, sizeof(out_inf) },
|
||||
};
|
||||
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"publish: name='%s' args='%s' type=%s silent=%d",
|
||||
v->name, v->args, v->type, v->silent);
|
||||
|
||||
|
@ -621,7 +624,7 @@ ngx_rtmp_cmd_fcpublish(ngx_rtmp_session_t *s, ngx_rtmp_fcpublish_t *v)
|
|||
out_inf, sizeof(out_inf) },
|
||||
};
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"fcpublish: name='%s'", v->name);
|
||||
|
||||
/* send onFCPublish reply */
|
||||
|
@ -801,8 +804,8 @@ ngx_rtmp_cmd_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v)
|
|||
out4_inf, sizeof(out4_inf) },
|
||||
};
|
||||
|
||||
ngx_log_debug6(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"cmd: play name='%s' args='%s' start=%i duration=%i "
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"play name='%s' args='%s' start=%i duration=%i "
|
||||
"reset=%i silent=%i",
|
||||
v->name, v->args, (ngx_int_t) v->start,
|
||||
(ngx_int_t) v->duration, (ngx_int_t) v->reset,
|
||||
|
@ -934,7 +937,7 @@ ngx_rtmp_cmd_fcsubscribe(ngx_rtmp_session_t *s, ngx_rtmp_fcsubscribe_t *v)
|
|||
sizeof(out_inf) },
|
||||
};
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"fcsubscribe: name='%s'", v->name);
|
||||
|
||||
/* send onFCSubscribe reply */
|
||||
|
@ -1038,6 +1041,10 @@ ngx_rtmp_cmd_pause(ngx_rtmp_session_t *s, ngx_rtmp_pause_t *v)
|
|||
out_inf, sizeof(out_inf) },
|
||||
};
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"pause: state='%i' position=%i",
|
||||
v->pause, (ngx_int_t) v->position);
|
||||
|
||||
/* send onStatus reply */
|
||||
ngx_memzero(&h, sizeof(h));
|
||||
h.type = NGX_RTMP_MSG_AMF_CMD;
|
||||
|
@ -1068,6 +1075,9 @@ static ngx_int_t
|
|||
ngx_rtmp_cmd_disconnect(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
||||
ngx_chain_t *in)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"disconnect");
|
||||
|
||||
return ngx_rtmp_delete_stream
|
||||
? ngx_rtmp_delete_stream(s, NULL)
|
||||
: NGX_OK;
|
||||
|
@ -1152,6 +1162,9 @@ ngx_rtmp_cmd_seek(ngx_rtmp_session_t *s, ngx_rtmp_seek_t *v)
|
|||
out_inf, sizeof(out_inf) },
|
||||
};
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"seek: offset=%i", (ngx_int_t) v->offset);
|
||||
|
||||
/* send onStatus reply */
|
||||
ngx_memzero(&h, sizeof(h));
|
||||
h.type = NGX_RTMP_MSG_AMF_CMD;
|
||||
|
|
|
@ -282,6 +282,13 @@ ngx_rtmp_core_create_app_conf(ngx_conf_t *cf)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (ngx_array_init(&conf->applications, cf->pool, 1,
|
||||
sizeof(ngx_rtmp_core_app_conf_t *))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
|
|
564
ngx_rtmp_enotify_module.c
Normal file
564
ngx_rtmp_enotify_module.c
Normal file
|
@ -0,0 +1,564 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Roman Arutyunyan
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#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 NGX_LINUX
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
||||
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,
|
||||
void *conf);
|
||||
static ngx_int_t ngx_rtmp_enotify_postconfiguration(ngx_conf_t *cf);
|
||||
static void * ngx_rtmp_enotify_create_app_conf(ngx_conf_t *cf);
|
||||
static char * ngx_rtmp_enotify_merge_app_conf(ngx_conf_t *cf,
|
||||
void *parent, void *child);
|
||||
|
||||
|
||||
#define NGX_RTMP_ENOTIFY_PUBLISHING 0x01
|
||||
#define NGX_RTMP_ENOTIFY_PLAYING 0x02
|
||||
|
||||
|
||||
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 {
|
||||
ngx_str_t cmd;
|
||||
ngx_array_t args; /* ngx_str_t */
|
||||
} ngx_rtmp_enotify_conf_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_rtmp_enotify_conf_t *event[NGX_RTMP_ENOTIFY_MAX];
|
||||
ngx_flag_t active;
|
||||
} ngx_rtmp_enotify_app_conf_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_uint_t flags;
|
||||
u_char name[NGX_RTMP_MAX_NAME];
|
||||
u_char args[NGX_RTMP_MAX_ARGS];
|
||||
ngx_str_t path;
|
||||
ngx_str_t recorder;
|
||||
} ngx_rtmp_enotify_ctx_t;
|
||||
|
||||
|
||||
static ngx_command_t ngx_rtmp_enotify_commands[] = {
|
||||
|
||||
{ ngx_string("exec_publish"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_1MORE,
|
||||
ngx_rtmp_enotify_on_event,
|
||||
NGX_RTMP_APP_CONF_OFFSET,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
{ ngx_string("exec_play"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_1MORE,
|
||||
ngx_rtmp_enotify_on_event,
|
||||
NGX_RTMP_APP_CONF_OFFSET,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
{ ngx_string("exec_publish_done"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_1MORE,
|
||||
ngx_rtmp_enotify_on_event,
|
||||
NGX_RTMP_APP_CONF_OFFSET,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
{ ngx_string("exec_play_done"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_1MORE,
|
||||
ngx_rtmp_enotify_on_event,
|
||||
NGX_RTMP_APP_CONF_OFFSET,
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
static ngx_rtmp_module_t ngx_rtmp_enotify_module_ctx = {
|
||||
NULL, /* preconfiguration */
|
||||
ngx_rtmp_enotify_postconfiguration, /* postconfiguration */
|
||||
NULL, /* create main configuration */
|
||||
NULL, /* init main configuration */
|
||||
NULL, /* create server configuration */
|
||||
NULL, /* merge server configuration */
|
||||
ngx_rtmp_enotify_create_app_conf, /* create app configuration */
|
||||
ngx_rtmp_enotify_merge_app_conf /* merge app configuration */
|
||||
};
|
||||
|
||||
|
||||
ngx_module_t ngx_rtmp_enotify_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_rtmp_enotify_module_ctx, /* module context */
|
||||
ngx_rtmp_enotify_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 void
|
||||
ngx_rtmp_enotify_eval_astr(ngx_rtmp_session_t *s, ngx_rtmp_eval_t *e,
|
||||
ngx_str_t *ret)
|
||||
{
|
||||
ngx_rtmp_enotify_ctx_t *ctx;
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_enotify_module);
|
||||
if (ctx == NULL) {
|
||||
ret->len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
ret->data = (u_char *) ctx + e->offset;
|
||||
ret->len = ngx_strlen(ret->data);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_rtmp_enotify_eval_str(ngx_rtmp_session_t *s, ngx_rtmp_eval_t *e,
|
||||
ngx_str_t *ret)
|
||||
{
|
||||
ngx_rtmp_enotify_ctx_t *ctx;
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_enotify_module);
|
||||
if (ctx == NULL) {
|
||||
ret->len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
*ret = *(ngx_str_t *) ((u_char *) ctx + e->offset);
|
||||
}
|
||||
|
||||
|
||||
static ngx_rtmp_eval_t ngx_rtmp_enotify_eval[] = {
|
||||
|
||||
{ ngx_string("name"),
|
||||
ngx_rtmp_enotify_eval_astr,
|
||||
offsetof(ngx_rtmp_enotify_ctx_t, name) },
|
||||
|
||||
{ ngx_string("args"),
|
||||
ngx_rtmp_enotify_eval_astr,
|
||||
offsetof(ngx_rtmp_enotify_ctx_t, args) },
|
||||
|
||||
{ ngx_string("path"),
|
||||
ngx_rtmp_enotify_eval_str,
|
||||
offsetof(ngx_rtmp_enotify_ctx_t, path) },
|
||||
|
||||
{ ngx_string("recorder"),
|
||||
ngx_rtmp_enotify_eval_str,
|
||||
offsetof(ngx_rtmp_enotify_ctx_t, recorder) },
|
||||
|
||||
ngx_rtmp_null_eval
|
||||
};
|
||||
|
||||
|
||||
static ngx_rtmp_eval_t * ngx_rtmp_enotify_eval_p[] = {
|
||||
ngx_rtmp_eval_session,
|
||||
ngx_rtmp_enotify_eval,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
static void *
|
||||
ngx_rtmp_enotify_create_app_conf(ngx_conf_t *cf)
|
||||
{
|
||||
ngx_rtmp_enotify_app_conf_t *enacf;
|
||||
ngx_uint_t n;
|
||||
|
||||
enacf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_enotify_app_conf_t));
|
||||
if (enacf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (n = 0; n < NGX_RTMP_ENOTIFY_MAX; ++n) {
|
||||
enacf->event[n] = NGX_CONF_UNSET_PTR;
|
||||
}
|
||||
|
||||
return enacf;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_rtmp_enotify_merge_app_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
{
|
||||
ngx_rtmp_enotify_app_conf_t *prev = parent;
|
||||
ngx_rtmp_enotify_app_conf_t *conf = child;
|
||||
ngx_uint_t n;
|
||||
|
||||
for (n = 0; n < NGX_RTMP_ENOTIFY_MAX; ++n) {
|
||||
ngx_conf_merge_ptr_value(conf->event[n], prev->event[n], NULL);
|
||||
if (conf->event[n]) {
|
||||
conf->active = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (conf->active) {
|
||||
prev->active = 1;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_enotify_exec(ngx_rtmp_session_t *s, ngx_rtmp_enotify_conf_t *ec)
|
||||
{
|
||||
#ifndef NGX_WIN32
|
||||
int pid;
|
||||
ngx_str_t a, *arg;
|
||||
char **args;
|
||||
ngx_uint_t n;
|
||||
|
||||
pid = fork();
|
||||
|
||||
switch (pid) {
|
||||
case -1:
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, ngx_errno,
|
||||
"enotify: fork failed");
|
||||
return NGX_ERROR;
|
||||
|
||||
case 0:
|
||||
/* child */
|
||||
args = ngx_palloc(s->connection->pool,
|
||||
(ec->args.nelts + 2) * sizeof(char *));
|
||||
if (args == NULL) {
|
||||
exit(1);
|
||||
}
|
||||
arg = ec->args.elts;
|
||||
args[0] = (char *)ec->cmd.data;
|
||||
for (n = 0; n < ec->args.nelts; ++n, ++arg) {
|
||||
ngx_rtmp_eval(s, arg, ngx_rtmp_enotify_eval_p, &a);
|
||||
args[n + 1] = (char *) a.data;
|
||||
}
|
||||
args[n + 1] = NULL;
|
||||
if (execvp((char *)ec->cmd.data, args) == -1) {
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* parent */
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"enotify: child '%V' started pid=%ui",
|
||||
&ec->cmd, (ngx_uint_t)pid);
|
||||
break;
|
||||
}
|
||||
#endif /* NGX_WIN32 */
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_rtmp_enotify_init(ngx_rtmp_session_t *s,
|
||||
u_char name[NGX_RTMP_MAX_NAME], u_char args[NGX_RTMP_MAX_ARGS],
|
||||
ngx_uint_t flags)
|
||||
{
|
||||
ngx_rtmp_enotify_ctx_t *ctx;
|
||||
ngx_rtmp_enotify_app_conf_t *enacf;
|
||||
|
||||
enacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_enotify_module);
|
||||
|
||||
if (!enacf->active) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_enotify_module);
|
||||
|
||||
if (ctx == NULL) {
|
||||
ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_rtmp_enotify_ctx_t));
|
||||
if (ctx == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_enotify_module);
|
||||
}
|
||||
|
||||
ngx_memcpy(ctx->name, name, NGX_RTMP_MAX_NAME);
|
||||
ngx_memcpy(ctx->args, args, NGX_RTMP_MAX_ARGS);
|
||||
|
||||
ctx->flags |= flags;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_enotify_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_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) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
ngx_rtmp_enotify_init(s, v->name, v->args, NGX_RTMP_ENOTIFY_PUBLISHING);
|
||||
|
||||
ec = enacf->event[NGX_RTMP_ENOTIFY_PUBLISH];
|
||||
|
||||
if (ec == NULL) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"enotify: publish '%V'", &ec->cmd);
|
||||
|
||||
ngx_rtmp_enotify_exec(s, ec);
|
||||
|
||||
next:
|
||||
return next_publish(s, v);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_enotify_play(ngx_rtmp_session_t *s, ngx_rtmp_play_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) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
ngx_rtmp_enotify_init(s, v->name, v->args, NGX_RTMP_ENOTIFY_PLAYING);
|
||||
|
||||
ec = enacf->event[NGX_RTMP_ENOTIFY_PLAY];
|
||||
|
||||
if (ec == NULL) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"enotify: play '%V'", &ec->cmd);
|
||||
|
||||
ngx_rtmp_enotify_exec(s, ec);
|
||||
|
||||
next:
|
||||
return next_play(s, v);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_enotify_delete_stream(ngx_rtmp_session_t *s, ngx_rtmp_delete_stream_t
|
||||
*v)
|
||||
{
|
||||
ngx_rtmp_enotify_ctx_t *ctx;
|
||||
ngx_rtmp_enotify_app_conf_t *enacf;
|
||||
ngx_rtmp_enotify_conf_t *ec;
|
||||
|
||||
if (s->auto_pushed) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_enotify_module);
|
||||
|
||||
if (ctx == NULL) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
enacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_enotify_module);
|
||||
|
||||
if (enacf == NULL) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (enacf->event[NGX_RTMP_ENOTIFY_PUBLISH_DONE] &&
|
||||
(ctx->flags & NGX_RTMP_ENOTIFY_PUBLISHING))
|
||||
{
|
||||
ec = enacf->event[NGX_RTMP_ENOTIFY_PUBLISH_DONE];
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"enotify: publish_done '%V'", &ec->cmd);
|
||||
|
||||
ngx_rtmp_enotify_exec(s, ec);
|
||||
}
|
||||
|
||||
if (enacf->event[NGX_RTMP_ENOTIFY_PLAY_DONE] &&
|
||||
(ctx->flags & NGX_RTMP_ENOTIFY_PLAYING))
|
||||
{
|
||||
ec = enacf->event[NGX_RTMP_ENOTIFY_PLAY_DONE];
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"enotify: play_done '%V'", &ec->cmd);
|
||||
|
||||
ngx_rtmp_enotify_exec(s, ec);
|
||||
}
|
||||
|
||||
ctx->flags = 0;
|
||||
|
||||
next:
|
||||
return next_delete_stream(s, v);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
ngx_rtmp_enotify_ctx_t *ctx;
|
||||
|
||||
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_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"enotify: record_done %V recorder=%V path='%V'",
|
||||
&ec->cmd, &v->recorder, &v->path);
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_enotify_module);
|
||||
if (ctx == NULL) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
ctx->recorder = v->recorder;
|
||||
ctx->path = 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 nargs;
|
||||
ngx_uint_t n;
|
||||
|
||||
value = cf->args->elts;
|
||||
name = &value[0];
|
||||
|
||||
ec = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_enotify_conf_t));
|
||||
|
||||
if (ec == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
ec->cmd = value[1];
|
||||
|
||||
nargs = cf->args->nelts - 2;
|
||||
|
||||
if (nargs) {
|
||||
if (ngx_array_init(&ec->args, cf->pool, nargs, sizeof(ngx_str_t))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
s = ngx_array_push_n(&ec->args, nargs);
|
||||
for (n = 2; n < cf->args->nelts; ++n, ++s) {
|
||||
*s = value[n];
|
||||
}
|
||||
}
|
||||
|
||||
enacf = ngx_rtmp_conf_get_module_app_conf(cf, ngx_rtmp_enotify_module);
|
||||
|
||||
n = 0;
|
||||
|
||||
switch (name->len) {
|
||||
case sizeof("exec_play") - 1:
|
||||
n = NGX_RTMP_ENOTIFY_PLAY;
|
||||
break;
|
||||
|
||||
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->event[n] = ec;
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_enotify_postconfiguration(ngx_conf_t *cf)
|
||||
{
|
||||
next_publish = ngx_rtmp_publish;
|
||||
ngx_rtmp_publish = ngx_rtmp_enotify_publish;
|
||||
|
||||
next_play = ngx_rtmp_play;
|
||||
ngx_rtmp_play = ngx_rtmp_enotify_play;
|
||||
|
||||
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;
|
||||
}
|
188
ngx_rtmp_eval.c
Normal file
188
ngx_rtmp_eval.c
Normal file
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Roman Arutyunyan
|
||||
*/
|
||||
|
||||
|
||||
#include "ngx_rtmp_eval.h"
|
||||
|
||||
|
||||
#define NGX_RTMP_EVAL_BUFLEN 16
|
||||
|
||||
|
||||
static void
|
||||
ngx_rtmp_eval_session_str(ngx_rtmp_session_t *s, ngx_rtmp_eval_t *e,
|
||||
ngx_str_t *ret)
|
||||
{
|
||||
*ret = *(ngx_str_t *) ((u_char *) s + e->offset);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_rtmp_eval_connection_str(ngx_rtmp_session_t *s, ngx_rtmp_eval_t *e,
|
||||
ngx_str_t *ret)
|
||||
{
|
||||
*ret = *(ngx_str_t *) ((u_char *) s->connection + e->offset);
|
||||
}
|
||||
|
||||
|
||||
ngx_rtmp_eval_t ngx_rtmp_eval_session[] = {
|
||||
|
||||
{ ngx_string("app"),
|
||||
ngx_rtmp_eval_session_str,
|
||||
offsetof(ngx_rtmp_session_t, app) },
|
||||
|
||||
{ ngx_string("flashver"),
|
||||
ngx_rtmp_eval_session_str,
|
||||
offsetof(ngx_rtmp_session_t, flashver) },
|
||||
|
||||
{ ngx_string("swfurl"),
|
||||
ngx_rtmp_eval_session_str,
|
||||
offsetof(ngx_rtmp_session_t, swf_url) },
|
||||
|
||||
{ ngx_string("tcurl"),
|
||||
ngx_rtmp_eval_session_str,
|
||||
offsetof(ngx_rtmp_session_t, tc_url) },
|
||||
|
||||
{ ngx_string("pageurl"),
|
||||
ngx_rtmp_eval_session_str,
|
||||
offsetof(ngx_rtmp_session_t, page_url) },
|
||||
|
||||
{ ngx_string("addr"),
|
||||
ngx_rtmp_eval_connection_str,
|
||||
offsetof(ngx_connection_t, addr_text) },
|
||||
|
||||
ngx_rtmp_null_eval
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
ngx_rtmp_eval_append(ngx_rtmp_session_t *s, ngx_buf_t *b,
|
||||
void *data, size_t len)
|
||||
{
|
||||
size_t buf_len;
|
||||
|
||||
if (b->last + len > b->end) {
|
||||
buf_len = 2 * (b->last - b->pos) + len;
|
||||
|
||||
b->start = ngx_palloc(s->connection->pool, buf_len);
|
||||
if (b->start == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
b->last = ngx_cpymem(b->start, b->pos, b->last - b->pos);
|
||||
b->pos = b->start;
|
||||
b->end = b->start + buf_len;
|
||||
}
|
||||
|
||||
b->last = ngx_cpymem(b->last, data, len);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_rtmp_eval_append_var(ngx_rtmp_session_t *s, ngx_buf_t *b,
|
||||
ngx_rtmp_eval_t **e, ngx_str_t *name)
|
||||
{
|
||||
ngx_uint_t k;
|
||||
ngx_str_t v;
|
||||
ngx_rtmp_eval_t *ee;
|
||||
|
||||
for (; *e; ++e) {
|
||||
for (k = 0, ee = *e; ee->handler; ++k, ++ee) {
|
||||
if (ee->name.len == name->len &&
|
||||
ngx_memcmp(ee->name.data, name->data, name->len) == 0)
|
||||
{
|
||||
ee->handler(s, ee, &v);
|
||||
ngx_rtmp_eval_append(s, b, v.data, v.len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_rtmp_eval(ngx_rtmp_session_t *s, ngx_str_t *in, ngx_rtmp_eval_t **e,
|
||||
ngx_str_t *out)
|
||||
{
|
||||
u_char c, *p;;
|
||||
ngx_str_t name;
|
||||
ngx_buf_t b;
|
||||
ngx_uint_t n;
|
||||
|
||||
enum {
|
||||
NORMAL,
|
||||
ESCAPE,
|
||||
NAME,
|
||||
SNAME
|
||||
} state = NORMAL;
|
||||
|
||||
b.pos = b.last = b.start = ngx_palloc(s->connection->pool,
|
||||
NGX_RTMP_EVAL_BUFLEN);
|
||||
if (b.pos == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
b.end = b.pos + NGX_RTMP_EVAL_BUFLEN;
|
||||
|
||||
for (n = 0; n < in->len; ++n) {
|
||||
p = &in->data[n];
|
||||
c = *p;
|
||||
|
||||
switch (state) {
|
||||
case SNAME:
|
||||
if (c != '}') {
|
||||
continue;
|
||||
}
|
||||
|
||||
name.len = p - name.data;
|
||||
ngx_rtmp_eval_append_var(s, &b, e, &name);
|
||||
|
||||
state = NORMAL;
|
||||
|
||||
continue;
|
||||
|
||||
case NAME:
|
||||
if (c == '{' && name.data == p) {
|
||||
++name.data;
|
||||
state = SNAME;
|
||||
continue;
|
||||
}
|
||||
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
name.len = p - name.data;
|
||||
ngx_rtmp_eval_append_var(s, &b, e, &name);
|
||||
|
||||
case NORMAL:
|
||||
switch (c) {
|
||||
case '$':
|
||||
name.data = p + 1;
|
||||
state = NAME;
|
||||
continue;
|
||||
case '\\':
|
||||
state = ESCAPE;
|
||||
continue;
|
||||
}
|
||||
|
||||
case ESCAPE:
|
||||
ngx_rtmp_eval_append(s, &b, &c, 1);
|
||||
state = NORMAL;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (state == NAME) {
|
||||
p = &in->data[n];
|
||||
name.len = p - name.data;
|
||||
ngx_rtmp_eval_append_var(s, &b, e, &name);
|
||||
}
|
||||
|
||||
c = 0;
|
||||
ngx_rtmp_eval_append(s, &b, &c, 1);
|
||||
|
||||
out->data = b.pos;
|
||||
out->len = b.last - b.pos - 1;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
37
ngx_rtmp_eval.h
Normal file
37
ngx_rtmp_eval.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Roman Arutyunyan
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_RTMP_EVAL_H_INCLUDED_
|
||||
#define _NGX_RTMP_EVAL_H_INCLUDED_
|
||||
|
||||
#include "ngx_rtmp.h"
|
||||
|
||||
|
||||
typedef struct ngx_rtmp_eval_s ngx_rtmp_eval_t;
|
||||
|
||||
|
||||
typedef void (* ngx_rtmp_eval_pt)(ngx_rtmp_session_t *s, ngx_rtmp_eval_t *e,
|
||||
ngx_str_t *ret);
|
||||
|
||||
|
||||
struct ngx_rtmp_eval_s {
|
||||
ngx_str_t name;
|
||||
ngx_rtmp_eval_pt handler;
|
||||
ngx_uint_t offset;
|
||||
};
|
||||
|
||||
|
||||
#define ngx_rtmp_null_eval { ngx_null_string, NULL, 0 }
|
||||
|
||||
|
||||
/* standard session eval variables */
|
||||
extern ngx_rtmp_eval_t ngx_rtmp_eval_session[];
|
||||
|
||||
|
||||
ngx_int_t ngx_rtmp_eval(ngx_rtmp_session_t *s, ngx_str_t *in,
|
||||
ngx_rtmp_eval_t **e, ngx_str_t *out);
|
||||
|
||||
|
||||
#endif /* _NGX_RTMP_EVAL_H_INCLUDED_ */
|
|
@ -4,10 +4,8 @@
|
|||
|
||||
|
||||
#include "ngx_rtmp_cmd_module.h"
|
||||
#include "ngx_rtmp_eval.h"
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_MALLOC_H
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#ifdef NGX_LINUX
|
||||
#include <unistd.h>
|
||||
|
@ -121,6 +119,40 @@ ngx_module_t ngx_rtmp_exec_module = {
|
|||
};
|
||||
|
||||
|
||||
static void
|
||||
ngx_rtmp_exec_eval_astr(ngx_rtmp_session_t *s, ngx_rtmp_eval_t *e,
|
||||
ngx_str_t *ret)
|
||||
{
|
||||
ngx_rtmp_exec_ctx_t *ctx;
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_exec_module);
|
||||
if (ctx == NULL) {
|
||||
ret->len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
ret->data = (u_char *) ctx + e->offset;
|
||||
ret->len = ngx_strlen(ret->data);
|
||||
}
|
||||
|
||||
|
||||
static ngx_rtmp_eval_t ngx_rtmp_exec_eval[] = {
|
||||
|
||||
{ ngx_string("name"),
|
||||
ngx_rtmp_exec_eval_astr,
|
||||
offsetof(ngx_rtmp_exec_ctx_t, name) },
|
||||
|
||||
ngx_rtmp_null_eval
|
||||
};
|
||||
|
||||
|
||||
static ngx_rtmp_eval_t * ngx_rtmp_exec_eval_p[] = {
|
||||
ngx_rtmp_eval_session,
|
||||
ngx_rtmp_exec_eval,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
static void *
|
||||
ngx_rtmp_exec_create_app_conf(ngx_conf_t *cf)
|
||||
{
|
||||
|
@ -250,73 +282,6 @@ ngx_rtmp_exec_kill(ngx_rtmp_session_t *s, ngx_rtmp_exec_t *e, ngx_int_t term)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_rtmp_exec_append(ngx_str_t *result, u_char *data, size_t len)
|
||||
{
|
||||
if (len == 0) {
|
||||
len = ngx_strlen(data);
|
||||
}
|
||||
|
||||
/* use malloc in child */
|
||||
if (result->len == 0) {
|
||||
result->data = malloc(len + 1);
|
||||
result->len = len;
|
||||
ngx_memcpy(result->data, data, len);
|
||||
result->data[len] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
result->data = realloc(result->data, result->len + len + 1);
|
||||
ngx_memcpy(result->data + result->len, data, len);
|
||||
result->len += len;
|
||||
result->data[result->len] = 0;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_rtmp_exec_prepare_arg(ngx_rtmp_session_t *s, ngx_str_t *arg)
|
||||
{
|
||||
ngx_rtmp_core_app_conf_t *cacf;
|
||||
ngx_rtmp_exec_ctx_t *ctx;
|
||||
u_char *p, *pp;
|
||||
ngx_str_t result;
|
||||
|
||||
cacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_core_module);
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_exec_module);
|
||||
|
||||
/* substitute $app/${app} & $name/${name} */
|
||||
ngx_str_set(&result, "");
|
||||
pp = arg->data;
|
||||
for ( ;; ) {
|
||||
p = (u_char *)ngx_strchr(pp, '$');
|
||||
ngx_rtmp_exec_append(&result, pp, p ? p - pp : 0);
|
||||
if (p == NULL) {
|
||||
return (char *)result.data;
|
||||
}
|
||||
pp = p + 1;
|
||||
if (p != arg->data && p[-1] == '\\') {
|
||||
goto dollar;
|
||||
}
|
||||
if (!ngx_strncmp(p + 1, "app", sizeof("app") - 1)
|
||||
|| !ngx_strncmp(p + 1, "{app}", sizeof("{app}") - 1))
|
||||
{
|
||||
ngx_rtmp_exec_append(&result, cacf->name.data, cacf->name.len);
|
||||
pp += (p[1] == '{' ? sizeof("{app}") - 1 : sizeof("app") - 1);
|
||||
continue;
|
||||
}
|
||||
if (!ngx_strncmp(p + 1, "name", sizeof("name") - 1)
|
||||
|| !ngx_strncmp(p + 1, "{name}", sizeof("{name}") - 1))
|
||||
{
|
||||
ngx_rtmp_exec_append(&result, ctx->name, 0);
|
||||
pp += (p[1] == '{' ? sizeof("{name}") - 1 : sizeof("name") - 1);
|
||||
continue;
|
||||
}
|
||||
dollar:
|
||||
ngx_rtmp_exec_append(&result, (u_char *)"$", 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_rtmp_exec_run(ngx_rtmp_session_t *s, size_t n)
|
||||
{
|
||||
|
@ -328,7 +293,7 @@ ngx_rtmp_exec_run(ngx_rtmp_session_t *s, size_t n)
|
|||
int ret;
|
||||
ngx_rtmp_exec_conf_t *ec;
|
||||
ngx_rtmp_exec_t *e;
|
||||
ngx_str_t *arg;
|
||||
ngx_str_t *arg, a;
|
||||
char **args;
|
||||
|
||||
eacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_exec_module);
|
||||
|
@ -372,17 +337,19 @@ ngx_rtmp_exec_run(ngx_rtmp_session_t *s, size_t n)
|
|||
|
||||
case 0:
|
||||
/* child */
|
||||
args = malloc((ec->args.nelts + 2) * sizeof(char *));
|
||||
args = ngx_palloc(s->connection->pool,
|
||||
(ec->args.nelts + 2) * sizeof(char *));
|
||||
if (args == NULL) {
|
||||
exit(1);
|
||||
}
|
||||
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_exec_eval_p, &a);
|
||||
args[n + 1] = (char *) a.data;
|
||||
}
|
||||
args[n + 1] = NULL;
|
||||
if (execv((char *)ec->cmd.data, args) == -1) {
|
||||
if (execvp((char *)ec->cmd.data, args) == -1) {
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -9,34 +9,59 @@
|
|||
|
||||
#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,
|
||||
void *conf);
|
||||
void *conf);
|
||||
static ngx_int_t ngx_rtmp_notify_postconfiguration(ngx_conf_t *cf);
|
||||
static void * ngx_rtmp_notify_create_app_conf(ngx_conf_t *cf);
|
||||
static char * ngx_rtmp_notify_merge_app_conf(ngx_conf_t *cf,
|
||||
void *parent, void *child);
|
||||
void *parent, void *child);
|
||||
static ngx_int_t ngx_rtmp_notify_done(ngx_rtmp_session_t *s, char *cbname,
|
||||
ngx_url_t *url);
|
||||
|
||||
|
||||
#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 *done_url;
|
||||
ngx_url_t *url[NGX_RTMP_NOTIFY_MAX];
|
||||
ngx_flag_t active;
|
||||
} ngx_rtmp_notify_app_conf_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_uint_t flags;
|
||||
u_char name[NGX_RTMP_MAX_NAME];
|
||||
u_char args[NGX_RTMP_MAX_ARGS];
|
||||
} ngx_rtmp_notify_ctx_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
u_char *cbname;
|
||||
ngx_url_t *url;
|
||||
} ngx_rtmp_notify_done_t;
|
||||
|
||||
|
||||
static ngx_command_t ngx_rtmp_notify_commands[] = {
|
||||
|
||||
{ ngx_string("on_publish"),
|
||||
|
@ -53,6 +78,20 @@ static ngx_command_t ngx_rtmp_notify_commands[] = {
|
|||
0,
|
||||
NULL },
|
||||
|
||||
{ ngx_string("on_publish_done"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
|
||||
ngx_rtmp_notify_on_event,
|
||||
NGX_RTMP_APP_CONF_OFFSET,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
{ ngx_string("on_play_done"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
|
||||
ngx_rtmp_notify_on_event,
|
||||
NGX_RTMP_APP_CONF_OFFSET,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
{ ngx_string("on_done"),
|
||||
NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
|
||||
ngx_rtmp_notify_on_event,
|
||||
|
@ -60,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
|
||||
};
|
||||
|
||||
|
@ -95,13 +142,18 @@ ngx_module_t ngx_rtmp_notify_module = {
|
|||
static void *
|
||||
ngx_rtmp_notify_create_app_conf(ngx_conf_t *cf)
|
||||
{
|
||||
ngx_rtmp_notify_app_conf_t *nacf;
|
||||
ngx_rtmp_notify_app_conf_t *nacf;
|
||||
ngx_uint_t n;
|
||||
|
||||
nacf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_notify_app_conf_t));
|
||||
if (nacf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (n = 0; n < NGX_RTMP_NOTIFY_MAX; ++n) {
|
||||
nacf->url[n] = NGX_CONF_UNSET_PTR;
|
||||
}
|
||||
|
||||
return nacf;
|
||||
}
|
||||
|
||||
|
@ -111,9 +163,18 @@ 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], NULL);
|
||||
if (conf->url[n]) {
|
||||
conf->active = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (conf->active) {
|
||||
prev->active = 1;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
@ -183,8 +244,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) {
|
||||
|
@ -263,8 +324,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) {
|
||||
|
@ -283,14 +344,14 @@ static ngx_chain_t *
|
|||
ngx_rtmp_notify_done_create(ngx_rtmp_session_t *s, void *arg,
|
||||
ngx_pool_t *pool)
|
||||
{
|
||||
ngx_rtmp_notify_app_conf_t *nacf;
|
||||
ngx_rtmp_notify_done_t *ds = arg;
|
||||
|
||||
ngx_chain_t *hl, *cl, *pl;
|
||||
ngx_buf_t *b;
|
||||
size_t name_len, args_len;
|
||||
size_t cbname_len, name_len, args_len;
|
||||
ngx_str_t *addr_text;
|
||||
ngx_rtmp_notify_ctx_t *ctx;
|
||||
|
||||
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 */
|
||||
|
@ -306,12 +367,13 @@ ngx_rtmp_notify_done_create(ngx_rtmp_session_t *s, void *arg,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
cbname_len = ngx_strlen(ds->cbname);
|
||||
name_len = ctx ? ngx_strlen(ctx->name) : 0;
|
||||
args_len = ctx ? ngx_strlen(ctx->args) : 0;
|
||||
addr_text = &s->connection->addr_text;
|
||||
|
||||
b = ngx_create_temp_buf(pool,
|
||||
sizeof("&call=done") +
|
||||
sizeof("&call=") + cbname_len +
|
||||
sizeof("&addr=") + addr_text->len +
|
||||
sizeof("&name=") + name_len * 3
|
||||
+ 1 + args_len);
|
||||
|
@ -321,8 +383,8 @@ ngx_rtmp_notify_done_create(ngx_rtmp_session_t *s, void *arg,
|
|||
|
||||
pl->buf = b;
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*)"&call=done",
|
||||
sizeof("&call=done") - 1);
|
||||
b->last = ngx_cpymem(b->last, (u_char*)"&call=", sizeof("&call=") - 1);
|
||||
b->last = ngx_cpymem(b->last, ds->cbname, cbname_len);
|
||||
|
||||
b->last = ngx_cpymem(b->last, (u_char*)"&addr=", sizeof("&addr=") -1);
|
||||
b->last = (u_char*)ngx_escape_uri(b->last, addr_text->data,
|
||||
|
@ -339,7 +401,7 @@ ngx_rtmp_notify_done_create(ngx_rtmp_session_t *s, void *arg,
|
|||
}
|
||||
|
||||
/* HTTP header */
|
||||
hl = ngx_rtmp_netcall_http_format_header(nacf->done_url, pool,
|
||||
hl = ngx_rtmp_netcall_http_format_header(ds->url, pool,
|
||||
cl->buf->last - cl->buf->pos + (pl->buf->last - pl->buf->pos),
|
||||
&ngx_rtmp_netcall_content_type_urlencoded);
|
||||
|
||||
|
@ -355,6 +417,95 @@ 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)
|
||||
|
@ -417,22 +568,34 @@ ngx_rtmp_notify_play_handle(ngx_rtmp_session_t *s,
|
|||
|
||||
|
||||
static void
|
||||
ngx_rtmp_notify_save_name_args(ngx_rtmp_session_t *s,
|
||||
u_char name[NGX_RTMP_MAX_NAME], u_char args[NGX_RTMP_MAX_ARGS])
|
||||
ngx_rtmp_notify_init(ngx_rtmp_session_t *s,
|
||||
u_char name[NGX_RTMP_MAX_NAME], u_char args[NGX_RTMP_MAX_ARGS],
|
||||
ngx_uint_t flags)
|
||||
{
|
||||
ngx_rtmp_notify_ctx_t *ctx;
|
||||
ngx_rtmp_notify_app_conf_t *nacf;
|
||||
|
||||
nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module);
|
||||
|
||||
if (!nacf->active) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_notify_module);
|
||||
|
||||
if (ctx == NULL) {
|
||||
ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_rtmp_notify_ctx_t));
|
||||
if (ctx == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_notify_module);
|
||||
}
|
||||
|
||||
ngx_memcpy(ctx->name, name, NGX_RTMP_MAX_NAME);
|
||||
ngx_memcpy(ctx->args, args, NGX_RTMP_MAX_ARGS);
|
||||
|
||||
ctx->flags |= flags;
|
||||
}
|
||||
|
||||
|
||||
|
@ -447,20 +610,24 @@ ngx_rtmp_notify_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
|
|||
}
|
||||
|
||||
nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module);
|
||||
|
||||
if (nacf == NULL) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (nacf->done_url) {
|
||||
ngx_rtmp_notify_save_name_args(s, v->name, v->args);
|
||||
}
|
||||
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_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"notify: publish '%V'",
|
||||
&nacf->url[NGX_RTMP_NOTIFY_PUBLISH]->url);
|
||||
|
||||
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;
|
||||
|
@ -479,21 +646,29 @@ ngx_rtmp_notify_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v)
|
|||
ngx_rtmp_notify_app_conf_t *nacf;
|
||||
ngx_rtmp_netcall_init_t ci;
|
||||
|
||||
if (s->auto_pushed) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module);
|
||||
|
||||
if (nacf == NULL) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (nacf->done_url) {
|
||||
ngx_rtmp_notify_save_name_args(s, v->name, v->args);
|
||||
}
|
||||
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_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"notify: play '%V'",
|
||||
&nacf->url[NGX_RTMP_NOTIFY_PLAY]->url);
|
||||
|
||||
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;
|
||||
|
@ -507,25 +682,105 @@ 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;
|
||||
ngx_rtmp_netcall_init_t ci;
|
||||
|
||||
nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module);
|
||||
if (nacf == NULL || nacf->done_url == NULL) {
|
||||
if (s->auto_pushed) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_notify_module);
|
||||
|
||||
if (ctx == NULL) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module);
|
||||
|
||||
if (nacf == NULL) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
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->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->url[NGX_RTMP_NOTIFY_DONE] && ctx->flags) {
|
||||
ngx_rtmp_notify_done(s, "done", nacf->url[NGX_RTMP_NOTIFY_DONE]);
|
||||
}
|
||||
|
||||
ctx->flags = 0;
|
||||
|
||||
next:
|
||||
return next_delete_stream(s, v);
|
||||
}
|
||||
|
||||
|
||||
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_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"notify: record_done 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->done_url;
|
||||
ci.create = ngx_rtmp_notify_done_create;
|
||||
|
||||
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_delete_stream(s, v);
|
||||
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)
|
||||
{
|
||||
ngx_rtmp_netcall_init_t ci;
|
||||
ngx_rtmp_notify_done_t ds;
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"notify: %s '%V'", cbname, &url->url);
|
||||
|
||||
ds.cbname = (u_char *) cbname;
|
||||
ds.url = url;
|
||||
|
||||
ngx_memzero(&ci, sizeof(ci));
|
||||
|
||||
ci.url = url;
|
||||
ci.arg = &ds;
|
||||
ci.create = ngx_rtmp_notify_done_create;
|
||||
|
||||
return ngx_rtmp_netcall_create(s, &ci);
|
||||
}
|
||||
|
||||
|
||||
|
@ -537,6 +792,7 @@ ngx_rtmp_notify_on_event(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
ngx_url_t *u;
|
||||
size_t add;
|
||||
ngx_str_t *value;
|
||||
ngx_uint_t n;
|
||||
|
||||
value = cf->args->elts;
|
||||
name = &value[0];
|
||||
|
@ -568,17 +824,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);
|
||||
|
||||
switch (name->data[4]) {
|
||||
case 'l': /* on_pLay */
|
||||
nacf->play_url = u;
|
||||
n = 0;
|
||||
|
||||
switch (name->len) {
|
||||
case sizeof("on_done") - 1: /* and on_play */
|
||||
if (name->data[3] == 'd') {
|
||||
n = NGX_RTMP_NOTIFY_DONE;
|
||||
} else {
|
||||
n = NGX_RTMP_NOTIFY_PLAY;
|
||||
}
|
||||
break;
|
||||
case 'u': /* on_pUblish */
|
||||
nacf->publish_url = u;
|
||||
|
||||
case sizeof("on_publish") - 1:
|
||||
n = NGX_RTMP_NOTIFY_PUBLISH;
|
||||
break;
|
||||
|
||||
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;
|
||||
case 'o': /* on_dOne */
|
||||
nacf->done_url = u;
|
||||
}
|
||||
|
||||
nacf->url[n] = u;
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
@ -595,6 +870,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -440,8 +440,8 @@ ngx_rtmp_play_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v)
|
|||
goto next;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
"play: fmt found: '%V'", &ctx->fmt->name);
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"play: %V", &ctx->fmt->name);
|
||||
|
||||
sfx = &ctx->fmt->sfx;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -10,7 +10,15 @@
|
|||
#include "ngx_rtmp.h"
|
||||
|
||||
|
||||
#define NGX_RTMP_RECORD_OFF 0x01
|
||||
#define NGX_RTMP_RECORD_AUDIO 0x02
|
||||
#define NGX_RTMP_RECORD_VIDEO 0x04
|
||||
#define NGX_RTMP_RECORD_KEYFRAMES 0x08
|
||||
#define NGX_RTMP_RECORD_MANUAL 0x10
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t id;
|
||||
ngx_uint_t flags;
|
||||
ngx_str_t path;
|
||||
size_t max_size;
|
||||
|
@ -19,25 +27,50 @@ typedef struct {
|
|||
ngx_str_t suffix;
|
||||
ngx_flag_t unique;
|
||||
ngx_url_t *url;
|
||||
|
||||
void **rec_conf;
|
||||
ngx_array_t rec; /* ngx_rtmp_record_app_conf_t * */
|
||||
} ngx_rtmp_record_app_conf_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
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_rec_ctx_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
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;
|
||||
|
||||
|
||||
u_char * ngx_rtmp_record_make_path(ngx_rtmp_session_t *s);
|
||||
|
||||
ngx_int_t ngx_rtmp_record_open(ngx_rtmp_session_t *s);
|
||||
/* Manual recording control,
|
||||
* 'n' is record node index in config array.
|
||||
* Note: these functions allocate path in static buffer */
|
||||
|
||||
ngx_int_t ngx_rtmp_record_close(ngx_rtmp_session_t *s);
|
||||
ngx_int_t ngx_rtmp_record_open(ngx_rtmp_session_t *s, ngx_uint_t n,
|
||||
ngx_str_t *path);
|
||||
ngx_int_t ngx_rtmp_record_close(ngx_rtmp_session_t *s, ngx_uint_t n,
|
||||
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;
|
||||
|
|
|
@ -396,6 +396,7 @@ ngx_rtmp_relay_create_remote_ctx(ngx_rtmp_session_t *s, ngx_str_t* name,
|
|||
return NULL;
|
||||
}
|
||||
rs->app_conf = s->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");
|
||||
|
@ -503,7 +504,7 @@ ngx_int_t
|
|||
ngx_rtmp_relay_pull(ngx_rtmp_session_t *s, ngx_str_t *name,
|
||||
ngx_rtmp_relay_target_t *target)
|
||||
{
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"relay: create pull name='%V' app='%V' playpath='%V' url='%V'",
|
||||
name, &target->app, &target->play_path, &target->url.url);
|
||||
|
||||
|
@ -517,7 +518,7 @@ ngx_int_t
|
|||
ngx_rtmp_relay_push(ngx_rtmp_session_t *s, ngx_str_t *name,
|
||||
ngx_rtmp_relay_target_t *target)
|
||||
{
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
|
||||
"relay: create push name='%V' app='%V' playpath='%V' url='%V'",
|
||||
name, &target->app, &target->play_path, &target->url.url);
|
||||
|
||||
|
@ -536,6 +537,10 @@ ngx_rtmp_relay_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
|
|||
size_t n;
|
||||
ngx_rtmp_relay_ctx_t *ctx;
|
||||
|
||||
if (s->auto_pushed) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module);
|
||||
if (ctx && ctx->relay) {
|
||||
goto next;
|
||||
|
|
Loading…
Reference in a new issue