From 840b62bf7152f06494eb5d5a7a580cbf0587a7bb Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Thu, 27 Sep 2012 14:24:51 +0400 Subject: [PATCH 1/6] initial implementation of control http module --- config | 2 + ngx_rtmp_control_module.c | 310 ++++++++++++++++++++++++++++++++++++++ ngx_rtmp_record_module.c | 22 +++ ngx_rtmp_record_module.h | 4 + 4 files changed, 338 insertions(+) create mode 100644 ngx_rtmp_control_module.c diff --git a/config b/config index 0714a51..b2d2114 100644 --- a/config +++ b/config @@ -22,6 +22,7 @@ CORE_MODULES="$CORE_MODULES HTTP_MODULES="$HTTP_MODULES \ ngx_rtmp_stat_module \ + ngx_rtmp_control_module \ " @@ -45,6 +46,7 @@ NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ $ngx_addon_dir/ngx_rtmp_mp4_module.c \ $ngx_addon_dir/ngx_rtmp_netcall_module.c \ $ngx_addon_dir/ngx_rtmp_stat_module.c \ + $ngx_addon_dir/ngx_rtmp_control_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 \ diff --git a/ngx_rtmp_control_module.c b/ngx_rtmp_control_module.c new file mode 100644 index 0000000..5538942 --- /dev/null +++ b/ngx_rtmp_control_module.c @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2012 Roman Arutyunyan + */ + + +#include +#include + +#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); + + +#define NGX_RTMP_CONTROL_ALL 0xff +#define NGX_RTMP_CONTROL_RECORD 0x01 + +/* + * global: stat-{bufs-{total,free,used}, total bytes in/out, bw in/out} - cscf +*/ + + +typedef struct { + ngx_uint_t control; +} ngx_rtmp_control_loc_conf_t; + + +static ngx_conf_bitmask_t ngx_rtmp_control_masks[] = { + { ngx_string("all"), NGX_RTMP_CONTROL_ALL }, + { ngx_string("record"), NGX_RTMP_CONTROL_RECORD }, + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_rtmp_control_commands[] = { + + { ngx_string("rtmp_control"), + 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 }, + + 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 +}; + + +/* /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_rtmp_core_main_conf_t *cmcf; + ngx_rtmp_core_srv_conf_t **pcscf, *cscf; + ngx_rtmp_core_app_conf_t **pcacf, *cacf; + ngx_rtmp_live_app_conf_t *lacf; + ngx_rtmp_live_stream_t *ls; + ngx_rtmp_live_ctx_t *lctx; + ngx_rtmp_record_app_conf_t *racf; + ngx_rtmp_session_t *s; + ngx_uint_t sn, rn, n; + ngx_str_t srv, app, rec, name; + size_t len; + ngx_str_t msg; + ngx_chain_t cl; + ngx_buf_t *b; + + sn = 0; + if (ngx_http_arg(r, (u_char *) "srv", sizeof("srv") - 1, &srv) == NGX_OK) { + sn = ngx_atoi(srv.data, srv.len); + } + + 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"); + ngx_str_set(&msg, "Application not specified"); + goto error; + } + + ngx_memzero(&rec, sizeof(rec)); + ngx_http_arg(r, (u_char *) "rec", sizeof("rec") - 1, &rec); + + ngx_memzero(&name, sizeof(name)); + ngx_http_arg(r, (u_char *) "name", sizeof("name") - 1, &name); + + cmcf = ngx_rtmp_core_main_conf; + if (cmcf == NULL) { + ngx_str_set(&msg, "Missing main RTMP conf"); + goto error; + } + + /* find server */ + if (sn >= cmcf->servers.nelts) { + ngx_str_set(&msg, "Server index out of range"); + goto error; + } + + pcscf = cmcf->servers.elts; + pcscf += sn; + cscf = *pcscf; + + /* find application */ + pcacf = cscf->applications.elts; + cacf = NULL; + + for (n = 0; n < cscf->applications.nelts; ++n, ++pcacf) { + if ((*pcacf)->name.len == app.len && + ngx_strncmp((*pcacf)->name.data, app.data, app.len) == 0) + { + cacf = *pcacf; + break; + } + } + + if (cacf == NULL) { + ngx_str_set(&msg, "Application not found"); + goto error; + } + + lacf = cacf->app_conf[ngx_rtmp_live_module.ctx_index]; + racf = cacf->app_conf[ngx_rtmp_record_module.ctx_index]; + + /* find live stream by name */ + for (ls = lacf->streams[ngx_hash_key(name.data, name.len)]; ls; + ls = ls->next) + { + len = ngx_strlen(ls->name); + + if (name.len == len && ngx_strncmp(name.data, ls->name, name.len) + == 0) + { + break; + } + } + + if (ls == NULL) { + ngx_str_set(&msg, "Live stream not found"); + goto error; + } + + /* find publisher context */ + for (lctx = ls->ctx; lctx; lctx = lctx->next) { + if (lctx->flags & NGX_RTMP_LIVE_PUBLISHING) { + break; + } + } + + if (lctx == NULL) { + ngx_str_set(&msg, "No publisher"); + goto error; + } + + s = lctx->session; + + /* find recorder */ + rn = ngx_rtmp_record_find(racf, &rec); + if (rn == NGX_CONF_UNSET_UINT) { + ngx_str_set(&msg, "Recorder not found"); + goto error; + } + + if (r->uri.len == sizeof("/record/start") - 1 && + ngx_strncmp(r->uri.data, "/record/start", r->uri.len) == 0) + { + ngx_rtmp_record_open(s, rn, NULL); + + } else if (r->uri.len == sizeof("/record/stop") - 1 && + ngx_strncmp(r->uri.data, "/record/stop", r->uri.len) == 0) + { + ngx_rtmp_record_close(s, rn, NULL); + + } else { + ngx_str_set(&msg, "Undefined subrequest"); + goto error; + } + + r->header_only = 1; + r->headers_out.status = NGX_HTTP_OK; + + return ngx_http_send_header(r); + +error: + r->headers_out.status = NGX_HTTP_INTERNAL_SERVER_ERROR; + r->headers_out.content_length_n = msg.len; + + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + ngx_memzero(&cl, sizeof(cl)); + cl.buf = b; + + b->start = b->pos = msg.data; + b->end = b->last = msg.data + msg.len; + b->memory = 1; + b->last_buf = 1; + + ngx_http_send_header(r); + + return ngx_http_output_filter(r, &cl); +} + + +static ngx_int_t +ngx_rtmp_control_handler(ngx_http_request_t *r) +{ + ngx_rtmp_control_loc_conf_t *llcf; + + llcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_control_module); + if (llcf->control == 0) { + return NGX_DECLINED; + } + + if (llcf->control & NGX_RTMP_CONTROL_RECORD && + ngx_strncmp(r->uri.data, "/record/", sizeof("/record/") - 1) == 0) + { + return ngx_rtmp_control_record(r); + } + + 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; +} diff --git a/ngx_rtmp_record_module.c b/ngx_rtmp_record_module.c index 419a302..141a09a 100644 --- a/ngx_rtmp_record_module.c +++ b/ngx_rtmp_record_module.c @@ -307,6 +307,28 @@ ngx_rtmp_record_close(ngx_rtmp_session_t *s, ngx_uint_t n, ngx_str_t *path) } +ngx_uint_t +ngx_rtmp_record_find(ngx_rtmp_record_app_conf_t *racf, ngx_str_t *id) +{ + ngx_rtmp_record_app_conf_t **pracf, *rracf; + ngx_uint_t n; + + pracf = racf->rec.elts; + + for (n = 0; n < racf->rec.nelts; ++n, ++pracf) { + rracf = *pracf; + + if (rracf->id.len == id->len && + ngx_strncmp(rracf->id.data, id->data, id->len) == 0) + { + return n; + } + } + + return NGX_CONF_UNSET_UINT; +} + + /* This funcion returns pointer to a static buffer */ static void ngx_rtmp_record_make_path(ngx_rtmp_session_t *s, diff --git a/ngx_rtmp_record_module.h b/ngx_rtmp_record_module.h index 6b7d417..ea79b7e 100644 --- a/ngx_rtmp_record_module.h +++ b/ngx_rtmp_record_module.h @@ -50,6 +50,10 @@ typedef struct { } ngx_rtmp_record_ctx_t; +ngx_uint_t ngx_rtmp_record_find(ngx_rtmp_record_app_conf_t *racf, + ngx_str_t *id); + + /* Manual recording control, * 'n' is record node index in config array. * Note: these functions allocate path in static buffer */ From 3d6d65f7c7df3a491e86a04615b9dd67f67f1608 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Thu, 27 Sep 2012 14:39:46 +0400 Subject: [PATCH 2/6] minor fixes in control module --- ngx_rtmp_control_module.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/ngx_rtmp_control_module.c b/ngx_rtmp_control_module.c index 5538942..4fa4913 100644 --- a/ngx_rtmp_control_module.c +++ b/ngx_rtmp_control_module.c @@ -20,10 +20,6 @@ static char * ngx_rtmp_control_merge_loc_conf(ngx_conf_t *cf, #define NGX_RTMP_CONTROL_ALL 0xff #define NGX_RTMP_CONTROL_RECORD 0x01 -/* - * global: stat-{bufs-{total,free,used}, total bytes in/out, bw in/out} - cscf -*/ - typedef struct { ngx_uint_t control; @@ -40,11 +36,11 @@ static ngx_conf_bitmask_t ngx_rtmp_control_masks[] = { static ngx_command_t ngx_rtmp_control_commands[] = { { ngx_string("rtmp_control"), - 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 }, + 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 }, ngx_null_command }; @@ -222,7 +218,7 @@ ngx_rtmp_control_record(ngx_http_request_t *r) return ngx_http_send_header(r); error: - r->headers_out.status = NGX_HTTP_INTERNAL_SERVER_ERROR; + r->headers_out.status = NGX_HTTP_BAD_REQUEST; r->headers_out.content_length_n = msg.len; b = ngx_calloc_buf(r->pool); From b70d37edb1274dcc5d28d4f2aa064169fb6e30c5 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Thu, 27 Sep 2012 21:05:52 +0400 Subject: [PATCH 3/6] improved manual recorder: keyframes, repeated open/close --- ngx_rtmp_record_module.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/ngx_rtmp_record_module.c b/ngx_rtmp_record_module.c index 141a09a..56042ce 100644 --- a/ngx_rtmp_record_module.c +++ b/ngx_rtmp_record_module.c @@ -27,7 +27,7 @@ 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_rec_ctx_t *rctx, - ngx_rtmp_header_t *h, ngx_chain_t *in); + ngx_rtmp_header_t *h, ngx_chain_t *in, ngx_int_t inc_nframes); 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, @@ -168,8 +168,6 @@ ngx_rtmp_record_create_app_conf(ngx_conf_t *cf) racf->unique = NGX_CONF_UNSET; racf->url = NGX_CONF_UNSET_PTR; - ngx_str_set(&racf->id, "default"); - if (ngx_array_init(&racf->rec, cf->pool, 1, sizeof(void *)) != NGX_OK) { return NULL; } @@ -259,6 +257,7 @@ ngx_int_t ngx_rtmp_record_open(ngx_rtmp_session_t *s, ngx_uint_t n, ngx_str_t *path) { ngx_rtmp_record_rec_ctx_t *rctx; + ngx_int_t rc; ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: #%ui manual open", n); @@ -269,8 +268,9 @@ ngx_rtmp_record_open(ngx_rtmp_session_t *s, ngx_uint_t n, ngx_str_t *path) return NGX_ERROR; } - if (ngx_rtmp_record_node_open(s, rctx) != NGX_OK) { - return NGX_ERROR; + rc = ngx_rtmp_record_node_open(s, rctx); + if (rc != NGX_OK) { + return rc; } if (path) { @@ -285,6 +285,7 @@ ngx_int_t ngx_rtmp_record_close(ngx_rtmp_session_t *s, ngx_uint_t n, ngx_str_t *path) { ngx_rtmp_record_rec_ctx_t *rctx; + ngx_int_t rc; ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: #%ui manual close", n); @@ -295,8 +296,9 @@ ngx_rtmp_record_close(ngx_rtmp_session_t *s, ngx_uint_t n, ngx_str_t *path) return NGX_ERROR; } - if (ngx_rtmp_record_node_close(s, rctx) != NGX_OK) { - return NGX_ERROR; + rc = ngx_rtmp_record_node_close(s, rctx); + if (rc != NGX_OK) { + return rc; } if (path) { @@ -384,7 +386,7 @@ ngx_rtmp_record_node_open(ngx_rtmp_session_t *s, rracf = rctx->conf; if (rctx->file.fd != NGX_INVALID_FILE) { - return NGX_OK; + return NGX_AGAIN; } ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, @@ -548,7 +550,7 @@ ngx_rtmp_record_node_close(ngx_rtmp_session_t *s, rracf = rctx->conf; if (rctx->file.fd == NGX_INVALID_FILE) { - return NGX_OK; + return NGX_AGAIN; } if (ngx_close_file(rctx->file.fd) == NGX_FILE_ERROR) { @@ -611,7 +613,8 @@ next: static ngx_int_t ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx, - ngx_rtmp_header_t *h, ngx_chain_t *in) + ngx_rtmp_header_t *h, ngx_chain_t *in, + ngx_int_t inc_nframes) { u_char hdr[11], *p, *ph; uint32_t timestamp, tag_size; @@ -688,7 +691,7 @@ ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s, return NGX_ERROR; } - ++rctx->nframes; + rctx->nframes += inc_nframes; /* watch max size */ if ((rracf->max_size && rctx->file.offset >= (ngx_int_t) rracf->max_size) || @@ -785,6 +788,12 @@ ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx, } } + if ((rracf->flags & NGX_RTMP_RECORD_MANUAL) && + !brkframe && rctx->nframes == 0) + { + return NGX_OK; + } + if (rctx->file.fd == NGX_INVALID_FILE) { return NGX_OK; } @@ -837,7 +846,8 @@ ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx, ch.type = NGX_RTMP_MSG_AUDIO; ch.mlen = ngx_rtmp_record_get_chain_mlen(codec_ctx->aac_header); - if (ngx_rtmp_record_write_frame(s, rctx, &ch, codec_ctx->aac_header) + if (ngx_rtmp_record_write_frame(s, rctx, &ch, + codec_ctx->aac_header, 0) != NGX_OK) { return NGX_OK; @@ -855,7 +865,8 @@ ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx, ch.type = NGX_RTMP_MSG_VIDEO; ch.mlen = ngx_rtmp_record_get_chain_mlen(codec_ctx->avc_header); - if (ngx_rtmp_record_write_frame(s, rctx, &ch, codec_ctx->avc_header) + if (ngx_rtmp_record_write_frame(s, rctx, &ch, + codec_ctx->avc_header, 0) != NGX_OK) { return NGX_OK; @@ -864,7 +875,7 @@ ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx, } } - return ngx_rtmp_record_write_frame(s, rctx, h, in); + return ngx_rtmp_record_write_frame(s, rctx, h, in, 1); } From 0cd7883a438a19f76d3d29d1f465516d1ec97bb1 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Thu, 27 Sep 2012 21:06:46 +0400 Subject: [PATCH 4/6] implemented control section/method parsers; added returning file path --- ngx_rtmp_control_module.c | 111 ++++++++++++++++++++++++++++++-------- 1 file changed, 88 insertions(+), 23 deletions(-) diff --git a/ngx_rtmp_control_module.c b/ngx_rtmp_control_module.c index 4fa4913..1346d81 100644 --- a/ngx_rtmp_control_module.c +++ b/ngx_rtmp_control_module.c @@ -86,22 +86,23 @@ ngx_module_t ngx_rtmp_control_module = { static ngx_int_t -ngx_rtmp_control_record(ngx_http_request_t *r) +ngx_rtmp_control_record(ngx_http_request_t *r, ngx_str_t *method) { + ngx_rtmp_record_app_conf_t *racf; ngx_rtmp_core_main_conf_t *cmcf; ngx_rtmp_core_srv_conf_t **pcscf, *cscf; ngx_rtmp_core_app_conf_t **pcacf, *cacf; ngx_rtmp_live_app_conf_t *lacf; ngx_rtmp_live_stream_t *ls; ngx_rtmp_live_ctx_t *lctx; - ngx_rtmp_record_app_conf_t *racf; ngx_rtmp_session_t *s; - ngx_uint_t sn, rn, n; - ngx_str_t srv, app, rec, name; - size_t len; - ngx_str_t msg; ngx_chain_t cl; + ngx_uint_t sn, rn, n; + ngx_str_t srv, app, rec, name, path; + ngx_str_t msg; ngx_buf_t *b; + ngx_int_t rc; + size_t len; sn = 0; if (ngx_http_arg(r, (u_char *) "srv", sizeof("srv") - 1, &srv) == NGX_OK) { @@ -159,8 +160,8 @@ ngx_rtmp_control_record(ngx_http_request_t *r) racf = cacf->app_conf[ngx_rtmp_record_module.ctx_index]; /* find live stream by name */ - for (ls = lacf->streams[ngx_hash_key(name.data, name.len)]; ls; - ls = ls->next) + for (ls = lacf->streams[ngx_hash_key(name.data, name.len) % lacf->nbuckets]; + ls; ls = ls->next) { len = ngx_strlen(ls->name); @@ -197,25 +198,53 @@ ngx_rtmp_control_record(ngx_http_request_t *r) goto error; } - if (r->uri.len == sizeof("/record/start") - 1 && - ngx_strncmp(r->uri.data, "/record/start", r->uri.len) == 0) - { - ngx_rtmp_record_open(s, rn, NULL); + ngx_memzero(&path, sizeof(path)); - } else if (r->uri.len == sizeof("/record/stop") - 1 && - ngx_strncmp(r->uri.data, "/record/stop", r->uri.len) == 0) + if (method->len == sizeof("start") - 1 && + ngx_strncmp(method->data, "start", method->len) == 0) { - ngx_rtmp_record_close(s, rn, NULL); + rc = ngx_rtmp_record_open(s, rn, &path); + + } else if (method->len == sizeof("stop") - 1 && + ngx_strncmp(method->data, "stop", method->len) == 0) + { + rc = ngx_rtmp_record_close(s, rn, &path); } else { - ngx_str_set(&msg, "Undefined subrequest"); + ngx_str_set(&msg, "Undefined method"); goto error; } - r->header_only = 1; - r->headers_out.status = NGX_HTTP_OK; + if (rc == NGX_ERROR) { + ngx_str_set(&msg, "Recorder error"); + goto error; + } - return ngx_http_send_header(r); + if (rc == NGX_AGAIN) { + /* already opened/closed */ + ngx_str_null(&path); + r->header_only = 1; + } + + r->headers_out.status = NGX_HTTP_OK; + 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->memory = 1; + b->last_buf = 1; + + ngx_http_send_header(r); + + return ngx_http_output_filter(r, &cl); error: r->headers_out.status = NGX_HTTP_BAD_REQUEST; @@ -244,18 +273,54 @@ static ngx_int_t ngx_rtmp_control_handler(ngx_http_request_t *r) { ngx_rtmp_control_loc_conf_t *llcf; + ngx_str_t section, method; + u_char *p; + ngx_uint_t n; llcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_control_module); if (llcf->control == 0) { return NGX_DECLINED; } - if (llcf->control & NGX_RTMP_CONTROL_RECORD && - ngx_strncmp(r->uri.data, "/record/", sizeof("/record/") - 1) == 0) - { - return ngx_rtmp_control_record(r); + /* 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); \ + } + + NGX_RTMP_CONTROL_SECTION(RECORD, record); + +#undef NGX_RTMP_CONTROL_SECTION + + return NGX_DECLINED; } From e630c913918b9a663a3416deaedb5795cd9dd978 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Thu, 27 Sep 2012 21:18:49 +0400 Subject: [PATCH 5/6] fixed formatting --- ngx_rtmp_record_module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ngx_rtmp_record_module.c b/ngx_rtmp_record_module.c index 56042ce..bb3eff9 100644 --- a/ngx_rtmp_record_module.c +++ b/ngx_rtmp_record_module.c @@ -791,7 +791,7 @@ ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx, if ((rracf->flags & NGX_RTMP_RECORD_MANUAL) && !brkframe && rctx->nframes == 0) { - return NGX_OK; + return NGX_OK; } if (rctx->file.fd == NGX_INVALID_FILE) { From 0b757e8a49480a88f5e051f6590f25e6c4de3288 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Thu, 27 Sep 2012 21:25:35 +0400 Subject: [PATCH 6/6] fixed http output --- ngx_rtmp_control_module.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/ngx_rtmp_control_module.c b/ngx_rtmp_control_module.c index 1346d81..227b677 100644 --- a/ngx_rtmp_control_module.c +++ b/ngx_rtmp_control_module.c @@ -238,8 +238,6 @@ ngx_rtmp_control_record(ngx_http_request_t *r, ngx_str_t *method) cl.buf = b; b->last = ngx_cpymem(b->pos, path.data, path.len); - - b->memory = 1; b->last_buf = 1; ngx_http_send_header(r);