2012-09-27 12:24:51 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2012 Roman Arutyunyan
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <nginx.h>
|
|
|
|
#include <ngx_http.h>
|
|
|
|
|
|
|
|
#include "ngx_rtmp.h"
|
|
|
|
#include "ngx_rtmp_live_module.h"
|
|
|
|
#include "ngx_rtmp_record_module.h"
|
|
|
|
|
|
|
|
|
|
|
|
static ngx_int_t ngx_rtmp_control_postconfiguration(ngx_conf_t *cf);
|
|
|
|
static void * ngx_rtmp_control_create_loc_conf(ngx_conf_t *cf);
|
|
|
|
static char * ngx_rtmp_control_merge_loc_conf(ngx_conf_t *cf,
|
|
|
|
void *parent, void *child);
|
|
|
|
|
|
|
|
|
2012-10-23 08:46:44 +02:00
|
|
|
typedef struct {
|
|
|
|
ngx_rtmp_core_main_conf_t *cmcf;
|
|
|
|
ngx_rtmp_core_srv_conf_t *cscf;
|
|
|
|
ngx_rtmp_core_app_conf_t *cacf;
|
|
|
|
} ngx_rtmp_control_core_t;
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
ngx_rtmp_live_app_conf_t *lacf;
|
|
|
|
ngx_rtmp_live_stream_t *ls;
|
|
|
|
} ngx_rtmp_control_live_t;
|
|
|
|
|
|
|
|
|
2012-09-27 12:24:51 +02:00
|
|
|
#define NGX_RTMP_CONTROL_ALL 0xff
|
|
|
|
#define NGX_RTMP_CONTROL_RECORD 0x01
|
2012-10-23 08:46:44 +02:00
|
|
|
#define NGX_RTMP_CONTROL_DROP 0x02
|
2012-09-27 12:24:51 +02:00
|
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
ngx_uint_t control;
|
|
|
|
} ngx_rtmp_control_loc_conf_t;
|
|
|
|
|
|
|
|
|
|
|
|
static ngx_conf_bitmask_t ngx_rtmp_control_masks[] = {
|
2012-10-23 08:46:44 +02:00
|
|
|
{ ngx_string("all"), NGX_RTMP_CONTROL_ALL },
|
|
|
|
{ ngx_string("record"), NGX_RTMP_CONTROL_RECORD },
|
|
|
|
{ ngx_string("drop"), NGX_RTMP_CONTROL_DROP },
|
|
|
|
{ ngx_null_string, 0 }
|
2012-09-27 12:24:51 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static ngx_command_t ngx_rtmp_control_commands[] = {
|
|
|
|
|
|
|
|
{ ngx_string("rtmp_control"),
|
2012-09-27 12:39:46 +02:00
|
|
|
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
|
|
|
|
ngx_conf_set_bitmask_slot,
|
|
|
|
NGX_HTTP_LOC_CONF_OFFSET,
|
|
|
|
offsetof(ngx_rtmp_control_loc_conf_t, control),
|
|
|
|
ngx_rtmp_control_masks },
|
2012-09-27 12:24:51 +02:00
|
|
|
|
|
|
|
ngx_null_command
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static ngx_http_module_t ngx_rtmp_control_module_ctx = {
|
|
|
|
NULL, /* preconfiguration */
|
|
|
|
ngx_rtmp_control_postconfiguration, /* postconfiguration */
|
|
|
|
|
|
|
|
NULL, /* create main configuration */
|
|
|
|
NULL, /* init main configuration */
|
|
|
|
|
|
|
|
NULL, /* create server configuration */
|
|
|
|
NULL, /* merge server configuration */
|
|
|
|
|
|
|
|
ngx_rtmp_control_create_loc_conf, /* create location configuration */
|
|
|
|
ngx_rtmp_control_merge_loc_conf, /* merge location configuration */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
ngx_module_t ngx_rtmp_control_module = {
|
|
|
|
NGX_MODULE_V1,
|
|
|
|
&ngx_rtmp_control_module_ctx, /* module context */
|
|
|
|
ngx_rtmp_control_commands, /* module directives */
|
|
|
|
NGX_HTTP_MODULE, /* module type */
|
|
|
|
NULL, /* init master */
|
|
|
|
NULL, /* init module */
|
|
|
|
NULL, /* init process */
|
|
|
|
NULL, /* init thread */
|
|
|
|
NULL, /* exit thread */
|
|
|
|
NULL, /* exit process */
|
|
|
|
NULL, /* exit master */
|
|
|
|
NGX_MODULE_V1_PADDING
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static ngx_int_t
|
2012-10-23 08:46:44 +02:00
|
|
|
ngx_rtmp_control_output_error(ngx_http_request_t *r, const char *msg)
|
2012-09-27 12:24:51 +02:00
|
|
|
{
|
2012-10-23 08:46:44 +02:00
|
|
|
size_t len;
|
|
|
|
ngx_buf_t *b;
|
|
|
|
ngx_chain_t cl;
|
2012-09-27 12:24:51 +02:00
|
|
|
|
2012-10-23 08:46:44 +02:00
|
|
|
len = ngx_strlen(msg);
|
2012-09-27 12:24:51 +02:00
|
|
|
|
2012-10-23 08:46:44 +02:00
|
|
|
r->headers_out.status = NGX_HTTP_BAD_REQUEST;
|
|
|
|
r->headers_out.content_length_n = len;
|
|
|
|
|
|
|
|
b = ngx_calloc_buf(r->pool);
|
|
|
|
if (b == NULL) {
|
|
|
|
return NGX_ERROR;
|
2012-09-27 12:24:51 +02:00
|
|
|
}
|
|
|
|
|
2012-10-23 08:46:44 +02:00
|
|
|
ngx_memzero(&cl, sizeof(cl));
|
|
|
|
cl.buf = b;
|
2012-09-27 12:24:51 +02:00
|
|
|
|
2012-10-23 08:46:44 +02:00
|
|
|
b->start = b->pos = (u_char *) msg;
|
|
|
|
b->end = b->last = (u_char *) msg + len;
|
|
|
|
b->memory = 1;
|
|
|
|
b->last_buf = 1;
|
2012-09-27 12:24:51 +02:00
|
|
|
|
2012-10-23 08:46:44 +02:00
|
|
|
ngx_http_send_header(r);
|
|
|
|
|
|
|
|
return ngx_http_output_filter(r, &cl);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
ngx_rtmp_control_parse_core(ngx_http_request_t *r,
|
|
|
|
ngx_rtmp_control_core_t *core)
|
|
|
|
{
|
|
|
|
ngx_str_t srv, app;
|
|
|
|
ngx_uint_t sn, n;
|
|
|
|
ngx_rtmp_core_srv_conf_t **pcscf;
|
|
|
|
ngx_rtmp_core_app_conf_t **pcacf;
|
|
|
|
|
|
|
|
|
|
|
|
core->cmcf = ngx_rtmp_core_main_conf;
|
|
|
|
if (core->cmcf == NULL) {
|
|
|
|
return "Missing main RTMP conf";
|
2012-09-27 12:24:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* find server */
|
2012-10-23 08:46:44 +02:00
|
|
|
sn = 0;
|
|
|
|
|
|
|
|
if (ngx_http_arg(r, (u_char *) "srv", sizeof("srv") - 1, &srv) == NGX_OK) {
|
|
|
|
sn = ngx_atoi(srv.data, srv.len);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sn >= core->cmcf->servers.nelts) {
|
|
|
|
return "Server index out of range";
|
2012-09-27 12:24:51 +02:00
|
|
|
}
|
|
|
|
|
2012-10-23 08:46:44 +02:00
|
|
|
pcscf = core->cmcf->servers.elts;
|
2012-09-27 12:24:51 +02:00
|
|
|
pcscf += sn;
|
2012-10-23 08:46:44 +02:00
|
|
|
|
|
|
|
core->cscf = *pcscf;
|
2012-09-27 12:24:51 +02:00
|
|
|
|
|
|
|
/* find application */
|
2012-10-23 08:46:44 +02:00
|
|
|
if (ngx_http_arg(r, (u_char *) "app", sizeof("app") - 1, &app) != NGX_OK) {
|
|
|
|
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
|
|
|
|
"rtmp_control: app not specified");
|
|
|
|
return "Application not specified";
|
|
|
|
}
|
|
|
|
|
|
|
|
core->cacf = NULL;
|
|
|
|
|
|
|
|
pcacf = core->cscf->applications.elts;
|
2012-09-27 12:24:51 +02:00
|
|
|
|
2012-10-23 08:46:44 +02:00
|
|
|
for (n = 0; n < core->cscf->applications.nelts; ++n, ++pcacf) {
|
2012-09-27 12:24:51 +02:00
|
|
|
if ((*pcacf)->name.len == app.len &&
|
|
|
|
ngx_strncmp((*pcacf)->name.data, app.data, app.len) == 0)
|
|
|
|
{
|
2012-10-23 08:46:44 +02:00
|
|
|
core->cacf = *pcacf;
|
2012-09-27 12:24:51 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-23 08:46:44 +02:00
|
|
|
if (core->cacf == NULL) {
|
|
|
|
return "Application not found";
|
2012-09-27 12:24:51 +02:00
|
|
|
}
|
|
|
|
|
2012-10-23 08:46:44 +02:00
|
|
|
return NGX_CONF_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
ngx_rtmp_control_parse_live(ngx_http_request_t *r,
|
|
|
|
ngx_rtmp_control_core_t *core,
|
|
|
|
ngx_rtmp_control_live_t *live)
|
|
|
|
{
|
|
|
|
ngx_str_t name;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
ngx_memzero(&name, sizeof(name));
|
|
|
|
ngx_http_arg(r, (u_char *) "name", sizeof("name") - 1, &name);
|
|
|
|
|
|
|
|
live->lacf = core->cacf->app_conf[ngx_rtmp_live_module.ctx_index];
|
2012-09-27 12:24:51 +02:00
|
|
|
|
|
|
|
/* find live stream by name */
|
2012-10-23 08:46:44 +02:00
|
|
|
for (live->ls = live->lacf->streams[ngx_hash_key(name.data, name.len) %
|
|
|
|
live->lacf->nbuckets];
|
|
|
|
live->ls; live->ls = live->ls->next)
|
2012-09-27 12:24:51 +02:00
|
|
|
{
|
2012-10-23 08:46:44 +02:00
|
|
|
len = ngx_strlen(live->ls->name);
|
2012-09-27 12:24:51 +02:00
|
|
|
|
2012-10-23 08:46:44 +02:00
|
|
|
if (name.len == len && ngx_strncmp(name.data, live->ls->name, name.len)
|
2012-09-27 12:24:51 +02:00
|
|
|
== 0)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-23 08:46:44 +02:00
|
|
|
if (live->ls == NULL) {
|
|
|
|
return "Live stream not found";
|
|
|
|
}
|
|
|
|
|
|
|
|
return NGX_CONF_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* /record arguments:
|
|
|
|
* srv - server index (optional)
|
|
|
|
* app - application name
|
|
|
|
* name - stream name
|
|
|
|
* rec - recorder name
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
static ngx_int_t
|
|
|
|
ngx_rtmp_control_record(ngx_http_request_t *r, ngx_str_t *method)
|
|
|
|
{
|
|
|
|
ngx_rtmp_control_core_t core;
|
|
|
|
ngx_rtmp_control_live_t live;
|
|
|
|
ngx_rtmp_record_app_conf_t *racf;
|
|
|
|
ngx_rtmp_live_ctx_t *lctx;
|
|
|
|
ngx_rtmp_session_t *s;
|
|
|
|
ngx_chain_t cl;
|
|
|
|
ngx_uint_t rn;
|
|
|
|
ngx_str_t rec, path;
|
|
|
|
ngx_buf_t *b;
|
|
|
|
ngx_int_t rc;
|
|
|
|
const char *msg;
|
|
|
|
|
|
|
|
msg = ngx_rtmp_control_parse_core(r, &core);
|
|
|
|
if (msg != NGX_CONF_OK) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
msg = ngx_rtmp_control_parse_live(r, &core, &live);
|
|
|
|
if (msg != NGX_CONF_OK) {
|
2012-09-27 12:24:51 +02:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find publisher context */
|
2012-10-23 08:46:44 +02:00
|
|
|
for (lctx = live.ls->ctx; lctx; lctx = lctx->next) {
|
2012-11-12 21:22:57 +01:00
|
|
|
if (lctx->publishing) {
|
2012-09-27 12:24:51 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lctx == NULL) {
|
2012-10-23 08:46:44 +02:00
|
|
|
msg = "No publisher";
|
2012-09-27 12:24:51 +02:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
s = lctx->session;
|
|
|
|
|
|
|
|
/* find recorder */
|
2012-10-23 08:46:44 +02:00
|
|
|
ngx_memzero(&rec, sizeof(rec));
|
|
|
|
ngx_http_arg(r, (u_char *) "rec", sizeof("rec") - 1, &rec);
|
|
|
|
|
|
|
|
racf = core.cacf->app_conf[ngx_rtmp_record_module.ctx_index];
|
|
|
|
|
2012-09-27 12:24:51 +02:00
|
|
|
rn = ngx_rtmp_record_find(racf, &rec);
|
|
|
|
if (rn == NGX_CONF_UNSET_UINT) {
|
2012-10-23 08:46:44 +02:00
|
|
|
msg = "Recorder not found";
|
2012-09-27 12:24:51 +02:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2012-10-23 08:46:44 +02:00
|
|
|
/* call the method */
|
2012-09-27 19:06:46 +02:00
|
|
|
ngx_memzero(&path, sizeof(path));
|
|
|
|
|
|
|
|
if (method->len == sizeof("start") - 1 &&
|
|
|
|
ngx_strncmp(method->data, "start", method->len) == 0)
|
2012-09-27 12:24:51 +02:00
|
|
|
{
|
2012-09-27 19:06:46 +02:00
|
|
|
rc = ngx_rtmp_record_open(s, rn, &path);
|
2012-09-27 12:24:51 +02:00
|
|
|
|
2012-09-27 19:06:46 +02:00
|
|
|
} else if (method->len == sizeof("stop") - 1 &&
|
|
|
|
ngx_strncmp(method->data, "stop", method->len) == 0)
|
2012-09-27 12:24:51 +02:00
|
|
|
{
|
2012-09-27 19:06:46 +02:00
|
|
|
rc = ngx_rtmp_record_close(s, rn, &path);
|
2012-09-27 12:24:51 +02:00
|
|
|
|
|
|
|
} else {
|
2012-10-23 08:46:44 +02:00
|
|
|
msg = "Undefined method";
|
2012-09-27 19:06:46 +02:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc == NGX_ERROR) {
|
2012-10-23 08:46:44 +02:00
|
|
|
msg = "Recorder error";
|
2012-09-27 12:24:51 +02:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2012-09-27 19:06:46 +02:00
|
|
|
if (rc == NGX_AGAIN) {
|
|
|
|
/* already opened/closed */
|
|
|
|
ngx_str_null(&path);
|
|
|
|
r->header_only = 1;
|
|
|
|
}
|
|
|
|
|
2012-09-27 12:24:51 +02:00
|
|
|
r->headers_out.status = NGX_HTTP_OK;
|
2012-09-27 19:06:46 +02:00
|
|
|
r->headers_out.content_length_n = path.len;
|
|
|
|
|
|
|
|
b = ngx_create_temp_buf(r->pool, path.len);
|
|
|
|
if (b == NULL) {
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
ngx_memzero(&cl, sizeof(cl));
|
|
|
|
cl.buf = b;
|
|
|
|
|
|
|
|
b->last = ngx_cpymem(b->pos, path.data, path.len);
|
|
|
|
b->last_buf = 1;
|
|
|
|
|
|
|
|
ngx_http_send_header(r);
|
|
|
|
|
|
|
|
return ngx_http_output_filter(r, &cl);
|
2012-09-27 12:24:51 +02:00
|
|
|
|
|
|
|
error:
|
2012-10-23 08:46:44 +02:00
|
|
|
return ngx_rtmp_control_output_error(r, msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static ngx_int_t
|
|
|
|
ngx_rtmp_control_drop(ngx_http_request_t *r, ngx_str_t *method)
|
|
|
|
{
|
|
|
|
ngx_rtmp_control_core_t core;
|
|
|
|
ngx_rtmp_control_live_t live;
|
|
|
|
ngx_rtmp_live_ctx_t *lctx;
|
|
|
|
ngx_str_t addr, *paddr;
|
|
|
|
const char *msg;
|
|
|
|
ngx_uint_t ndropped;
|
|
|
|
size_t len;
|
|
|
|
u_char *p;
|
|
|
|
ngx_buf_t *b;
|
|
|
|
ngx_chain_t cl;
|
|
|
|
|
|
|
|
msg = ngx_rtmp_control_parse_core(r, &core);
|
|
|
|
if (msg != NGX_CONF_OK) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
msg = ngx_rtmp_control_parse_live(r, &core, &live);
|
|
|
|
if (msg != NGX_CONF_OK) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
ndropped = 0;
|
|
|
|
|
|
|
|
if (method->len == sizeof("publisher") - 1 &&
|
|
|
|
ngx_strncmp(method->data, "publisher", method->len) == 0)
|
|
|
|
{
|
|
|
|
for (lctx = live.ls->ctx; lctx; lctx = lctx->next) {
|
2012-11-12 21:22:57 +01:00
|
|
|
if (lctx->publishing) {
|
2012-10-23 08:46:44 +02:00
|
|
|
ngx_rtmp_finalize_session(lctx->session);
|
|
|
|
++ndropped;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (method->len == sizeof("client") - 1 &&
|
|
|
|
ngx_strncmp(method->data, "client", method->len) == 0)
|
|
|
|
{
|
|
|
|
ngx_memzero(&addr, sizeof(addr));
|
|
|
|
ngx_http_arg(r, (u_char *) "addr", sizeof("addr") - 1, &addr);
|
|
|
|
|
|
|
|
for (lctx = live.ls->ctx; lctx; lctx = lctx->next) {
|
|
|
|
if (addr.len && lctx->session && lctx->session->connection) {
|
|
|
|
paddr = &lctx->session->connection->addr_text;
|
|
|
|
if (paddr->len != addr.len ||
|
|
|
|
ngx_strncmp(paddr->data, addr.data, addr.len))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ngx_rtmp_finalize_session(lctx->session);
|
|
|
|
++ndropped;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
msg = "Undefined method";
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* output ndropped */
|
|
|
|
|
|
|
|
len = NGX_OFF_T_LEN;
|
|
|
|
|
|
|
|
p = ngx_palloc(r->connection->pool, len);
|
|
|
|
if (p == NULL) {
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = (size_t) (ngx_snprintf(p, len, "%ui", ndropped) - p);
|
|
|
|
|
|
|
|
r->headers_out.status = NGX_HTTP_OK;
|
|
|
|
r->headers_out.content_length_n = len;
|
2012-09-27 12:24:51 +02:00
|
|
|
|
|
|
|
b = ngx_calloc_buf(r->pool);
|
|
|
|
if (b == NULL) {
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
2012-10-23 08:46:44 +02:00
|
|
|
b->start = b->pos = p;
|
|
|
|
b->end = b->last = p + len;
|
|
|
|
b->temporary = 1;
|
|
|
|
b->last_buf = 1;
|
|
|
|
|
2012-09-27 12:24:51 +02:00
|
|
|
ngx_memzero(&cl, sizeof(cl));
|
|
|
|
cl.buf = b;
|
|
|
|
|
|
|
|
ngx_http_send_header(r);
|
|
|
|
|
|
|
|
return ngx_http_output_filter(r, &cl);
|
2012-10-23 08:46:44 +02:00
|
|
|
|
|
|
|
error:
|
|
|
|
return ngx_rtmp_control_output_error(r, msg);
|
2012-09-27 12:24:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static ngx_int_t
|
|
|
|
ngx_rtmp_control_handler(ngx_http_request_t *r)
|
|
|
|
{
|
|
|
|
ngx_rtmp_control_loc_conf_t *llcf;
|
2012-09-27 19:06:46 +02:00
|
|
|
ngx_str_t section, method;
|
|
|
|
u_char *p;
|
|
|
|
ngx_uint_t n;
|
2012-09-27 12:24:51 +02:00
|
|
|
|
|
|
|
llcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_control_module);
|
|
|
|
if (llcf->control == 0) {
|
|
|
|
return NGX_DECLINED;
|
|
|
|
}
|
|
|
|
|
2012-09-27 19:06:46 +02:00
|
|
|
/* uri format: .../section/method?args */
|
|
|
|
ngx_memzero(§ion, sizeof(section));
|
|
|
|
ngx_memzero(&method, sizeof(method));
|
|
|
|
|
|
|
|
for (n = r->uri.len; n; --n) {
|
|
|
|
p = &r->uri.data[n - 1];
|
|
|
|
|
|
|
|
if (*p != '/') {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (method.data) {
|
|
|
|
section.data = p + 1;
|
|
|
|
section.len = method.data - section.data - 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
method.data = p + 1;
|
|
|
|
method.len = r->uri.data + r->uri.len - method.data;
|
|
|
|
}
|
|
|
|
|
|
|
|
ngx_log_debug2(NGX_LOG_DEBUG_RTMP, r->connection->log, 0,
|
|
|
|
"rtmp_control: section='%V' method='%V'",
|
|
|
|
§ion, &method);
|
|
|
|
|
|
|
|
|
|
|
|
#define NGX_RTMP_CONTROL_SECTION(flag, secname) \
|
|
|
|
if (llcf->control & NGX_RTMP_CONTROL_##flag && \
|
|
|
|
section.len == sizeof(#secname) - 1 && \
|
|
|
|
ngx_strncmp(section.data, #secname, sizeof(#secname) - 1) == 0) \
|
|
|
|
{ \
|
|
|
|
return ngx_rtmp_control_##secname(r, &method); \
|
2012-09-27 12:24:51 +02:00
|
|
|
}
|
|
|
|
|
2012-09-27 19:06:46 +02:00
|
|
|
NGX_RTMP_CONTROL_SECTION(RECORD, record);
|
2012-10-23 08:46:44 +02:00
|
|
|
NGX_RTMP_CONTROL_SECTION(DROP, drop);
|
2012-09-27 19:06:46 +02:00
|
|
|
|
|
|
|
#undef NGX_RTMP_CONTROL_SECTION
|
|
|
|
|
|
|
|
|
2012-09-27 12:24:51 +02:00
|
|
|
return NGX_DECLINED;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void *
|
|
|
|
ngx_rtmp_control_create_loc_conf(ngx_conf_t *cf)
|
|
|
|
{
|
|
|
|
ngx_rtmp_control_loc_conf_t *conf;
|
|
|
|
|
|
|
|
conf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_control_loc_conf_t));
|
|
|
|
if (conf == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
conf->control = 0;
|
|
|
|
|
|
|
|
return conf;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
ngx_rtmp_control_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
|
|
|
|
{
|
|
|
|
ngx_rtmp_control_loc_conf_t *prev = parent;
|
|
|
|
ngx_rtmp_control_loc_conf_t *conf = child;
|
|
|
|
|
|
|
|
ngx_conf_merge_bitmask_value(conf->control, prev->control, 0);
|
|
|
|
|
|
|
|
return NGX_CONF_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static ngx_int_t
|
|
|
|
ngx_rtmp_control_postconfiguration(ngx_conf_t *cf)
|
|
|
|
{
|
|
|
|
ngx_http_handler_pt *h;
|
|
|
|
ngx_http_core_main_conf_t *cmcf;
|
|
|
|
|
|
|
|
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
|
|
|
|
|
|
|
|
h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
|
|
|
|
if (h == NULL) {
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
*h = ngx_rtmp_control_handler;
|
|
|
|
|
|
|
|
return NGX_OK;
|
|
|
|
}
|