From 31d18ed4478684571476aed6125e942bfc738d77 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Fri, 23 Mar 2012 16:03:32 +0400 Subject: [PATCH] implemented applications --- TODO | 1 + config | 13 +- ngx_rtmp.c | 102 ++++++++- ngx_rtmp.h | 41 +++- ngx_rtmp_access_module.c | 60 ++--- ngx_rtmp_amf0.c | 21 +- ngx_rtmp_amf0.h | 2 + ngx_rtmp_app.c | 219 ++++++++++++++++++ ngx_rtmp_broadcast_module.c | 436 ++++++++++++++++-------------------- ngx_rtmp_core_module.c | 147 ++++++++++-- test/nginx.conf | 14 +- test/www/index.html | 6 +- 12 files changed, 748 insertions(+), 314 deletions(-) create mode 100644 ngx_rtmp_app.c diff --git a/TODO b/TODO index 19de8f7..50aa4dc 100644 --- a/TODO +++ b/TODO @@ -11,3 +11,4 @@ - fix broken data_frame(?) +- fix '..greeing line..' in log diff --git a/config b/config index f7ce9f5..b92697e 100644 --- a/config +++ b/config @@ -4,15 +4,18 @@ CORE_MODULES="$CORE_MODULES ngx_rtmp_module \ ngx_rtmp_core_module \ ngx_rtmp_access_module \ - ngx_rtmp_broadcast_module" + ngx_rtmp_broadcast_module \ + " NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ $ngx_addon_dir/ngx_rtmp.c \ - $ngx_addon_dir/ngx_rtmp_shared.c \ - $ngx_addon_dir/ngx_rtmp_handler.c \ - $ngx_addon_dir/ngx_rtmp_core_module.c \ + $ngx_addon_dir/ngx_rtmp_app.c \ $ngx_addon_dir/ngx_rtmp_amf0.c \ $ngx_addon_dir/ngx_rtmp_send.c \ + $ngx_addon_dir/ngx_rtmp_shared.c \ + $ngx_addon_dir/ngx_rtmp_handler.c \ $ngx_addon_dir/ngx_rtmp_receive.c \ + $ngx_addon_dir/ngx_rtmp_core_module.c \ $ngx_addon_dir/ngx_rtmp_access_module.c \ - $ngx_addon_dir/ngx_rtmp_broadcast_module.c" + $ngx_addon_dir/ngx_rtmp_broadcast_module.c \ + " diff --git a/ngx_rtmp.c b/ngx_rtmp.c index 4d0bb89..a842eb1 100644 --- a/ngx_rtmp.c +++ b/ngx_rtmp.c @@ -24,6 +24,9 @@ static ngx_int_t ngx_rtmp_init_events(ngx_conf_t *cf, ngx_rtmp_core_main_conf_t *cmcf); static ngx_int_t ngx_rtmp_init_event_handlers(ngx_conf_t *cf, ngx_rtmp_core_main_conf_t *cmcf); +static char * ngx_rtmp_merge_applications(ngx_conf_t *cf, + ngx_array_t *applications, void **app_conf, ngx_rtmp_module_t *module, + ngx_uint_t ctx_index); ngx_uint_t ngx_rtmp_max_module; @@ -75,7 +78,7 @@ ngx_rtmp_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_rtmp_listen_t *listen; ngx_rtmp_module_t *module; ngx_rtmp_conf_ctx_t *ctx; - ngx_rtmp_core_srv_conf_t **cscfp; + ngx_rtmp_core_srv_conf_t *cscf, **cscfp; ngx_rtmp_core_main_conf_t *cmcf; ctx = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_conf_ctx_t)); @@ -118,7 +121,18 @@ ngx_rtmp_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) /* - * create the main_conf's, the null srv_conf's, and the null loc_conf's + * the rtmp null app_conf context, it is used to merge + * the server{}s' app_conf's + */ + + ctx->app_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_rtmp_max_module); + if (ctx->app_conf == NULL) { + return NGX_CONF_ERROR; + } + + + /* + * create the main_conf's, the null srv_conf's, and the null app_conf's * of the all rtmp modules */ @@ -143,6 +157,13 @@ ngx_rtmp_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } } + + if (module->create_app_conf) { + ctx->app_conf[mi] = module->create_app_conf(cf); + if (ctx->app_conf[mi] == NULL) { + return NGX_CONF_ERROR; + } + } } pcf = *cf; @@ -214,9 +235,38 @@ ngx_rtmp_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return rv; } } + + if (module->merge_app_conf) { + + /* merge the server{}'s app_conf */ + + /*ctx->app_conf = cscfp[s]->ctx->loc_conf;*/ + + rv = module->merge_app_conf(cf, + ctx->app_conf[mi], + cscfp[s]->ctx->app_conf[mi]); + if (rv != NGX_CONF_OK) { + *cf = pcf; + return rv; + } + + /* merge the applications{}' app_conf's */ + + cscf = cscfp[s]->ctx->srv_conf[ngx_rtmp_core_module.ctx_index]; + + rv = ngx_rtmp_merge_applications(cf, &cscf->applications, + cscfp[s]->ctx->app_conf, + module, mi); + if (rv != NGX_CONF_OK) { + *cf = pcf; + return rv; + } + } + } } + if (ngx_rtmp_init_events(cf, cmcf) != NGX_OK) { return NGX_CONF_ERROR; } @@ -259,10 +309,45 @@ ngx_rtmp_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +static char * +ngx_rtmp_merge_applications(ngx_conf_t *cf, ngx_array_t *applications, + void **app_conf, ngx_rtmp_module_t *module, ngx_uint_t ctx_index) +{ + char *rv; + ngx_rtmp_conf_ctx_t *ctx, saved; + ngx_rtmp_core_app_conf_t **cacfp; + ngx_uint_t n; + + if (applications == NULL) { + return NGX_CONF_OK; + } + + ctx = (ngx_rtmp_conf_ctx_t *) cf->ctx; + saved = *ctx; + + cacfp = applications->elts; + for (n = 0; n < applications->nelts; ++n, ++cacfp) { + + ctx->app_conf = (*cacfp)->app_conf; + + rv = module->merge_app_conf(cf, app_conf[ctx_index], + (*cacfp)->app_conf[ctx_index]); + if (rv != NGX_CONF_OK) { + return rv; + } + } + + *ctx = saved; + + return NGX_CONF_OK; +} + + static ngx_int_t ngx_rtmp_init_events(ngx_conf_t *cf, ngx_rtmp_core_main_conf_t *cmcf) { - size_t n; + size_t n; + ngx_rtmp_amf0_handler_t *h; for(n = 0; n < NGX_RTMP_MAX_EVENT; ++n) { if (ngx_array_init(&cmcf->events[n], cf->pool, 1, @@ -278,6 +363,11 @@ ngx_rtmp_init_events(ngx_conf_t *cf, ngx_rtmp_core_main_conf_t *cmcf) return NGX_ERROR; } + /* this handler of connect should always be the first */ + h = ngx_array_push(&cmcf->amf0); + ngx_str_set(&h->name, "connect"); + h->handler = ngx_rtmp_connect; + return NGX_OK; } @@ -321,6 +411,11 @@ ngx_rtmp_init_event_handlers(ngx_conf_t *cf, ngx_rtmp_core_main_conf_t *cmcf) eh = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_USER]); *eh = ngx_rtmp_user_message_handler; + /* init several AMF0 callbacks */ + h = ngx_array_push(&cmcf->amf0); + ngx_str_set(&h->name, "createStream"); + h->handler = ngx_rtmp_create_stream; + /* init amf0 callbacks */ ngx_array_init(&cmcf->amf0_arrays, cf->pool, 1, sizeof(ngx_hash_key_t)); @@ -674,6 +769,7 @@ ngx_rtmp_cmp_conf_addrs(const void *one, const void *two) return 0; } + void * ngx_rtmp_rmemcpy(void *dst, void* src, size_t n) { diff --git a/ngx_rtmp.h b/ngx_rtmp.h index 1fec6f3..0bfdd1e 100644 --- a/ngx_rtmp.h +++ b/ngx_rtmp.h @@ -18,6 +18,7 @@ typedef struct { void **main_conf; void **srv_conf; + void **app_conf; } ngx_rtmp_conf_ctx_t; @@ -178,8 +179,19 @@ typedef struct { void **ctx; void **main_conf; void **srv_conf; + void **app_conf; ngx_str_t *addr_text; + int connected; + + /* connection parameters */ + ngx_str_t app; + ngx_str_t flashver; + ngx_str_t swf_url; + ngx_str_t tc_url; + uint32_t acodecs; + uint32_t vcodecs; + ngx_str_t page_url; /* TODO: allocate this bufs from shared pool */ ngx_buf_t hs_in_buf; @@ -232,6 +244,8 @@ typedef struct { typedef struct ngx_rtmp_core_srv_conf_s { + ngx_array_t applications; /* ngx_rtmp_core_app_conf_t */ + ngx_msec_t timeout; ngx_flag_t so_keepalive; ngx_int_t max_streams; @@ -244,7 +258,6 @@ typedef struct ngx_rtmp_core_srv_conf_s { ngx_chain_t *free_chains; size_t max_buf; size_t max_message; - ngx_flag_t wait_key_frame; ngx_flag_t play_time_fix; ngx_flag_t publish_time_fix; @@ -252,6 +265,12 @@ typedef struct ngx_rtmp_core_srv_conf_s { } ngx_rtmp_core_srv_conf_t; +typedef struct { + ngx_str_t name; + void **app_conf; +} ngx_rtmp_core_app_conf_t; + + typedef struct { ngx_str_t *client; ngx_rtmp_session_t *session; @@ -266,18 +285,24 @@ typedef struct { char *(*init_main_conf)(ngx_conf_t *cf, void *conf); void *(*create_srv_conf)(ngx_conf_t *cf); - char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, - void *conf); + char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, + void *conf); + + void *(*create_app_conf)(ngx_conf_t *cf); + char *(*merge_app_conf)(ngx_conf_t *cf, void *prev, + void *conf); } ngx_rtmp_module_t; #define NGX_RTMP_MODULE 0x504D5452 /* "RTMP" */ #define NGX_RTMP_MAIN_CONF 0x02000000 #define NGX_RTMP_SRV_CONF 0x04000000 +#define NGX_RTMP_APP_CONF 0x08000000 #define NGX_RTMP_MAIN_CONF_OFFSET offsetof(ngx_rtmp_conf_ctx_t, main_conf) #define NGX_RTMP_SRV_CONF_OFFSET offsetof(ngx_rtmp_conf_ctx_t, srv_conf) +#define NGX_RTMP_APP_CONF_OFFSET offsetof(ngx_rtmp_conf_ctx_t, app_conf) #define ngx_rtmp_get_module_ctx(s, module) (s)->ctx[module.ctx_index] @@ -288,6 +313,8 @@ typedef struct { #define ngx_rtmp_get_module_main_conf(s, module) \ (s)->main_conf[module.ctx_index] #define ngx_rtmp_get_module_srv_conf(s, module) (s)->srv_conf[module.ctx_index] +#define ngx_rtmp_get_module_app_conf(s, module) ((s)->app_conf ? \ + (s)->app_conf[module.ctx_index] : NULL) #define ngx_rtmp_conf_get_module_main_conf(cf, module) \ ((ngx_rtmp_conf_ctx_t *) cf->ctx)->main_conf[module.ctx_index] @@ -321,6 +348,14 @@ ngx_int_t ngx_rtmp_user_message_handler(ngx_rtmp_session_t *s, ngx_int_t ngx_rtmp_amf0_message_handler(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in); +/* Standard AMF0 handlers */ +ngx_int_t ngx_rtmp_connect(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in); +ngx_int_t ngx_rtmp_create_stream(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in); +ngx_int_t ngx_rtmp_amf0_default(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in); + /* Shared output buffers */ ngx_chain_t * ngx_rtmp_alloc_shared_buf(ngx_rtmp_core_srv_conf_t *cscf); diff --git a/ngx_rtmp_access_module.c b/ngx_rtmp_access_module.c index 03dc38a..8e89800 100644 --- a/ngx_rtmp_access_module.c +++ b/ngx_rtmp_access_module.c @@ -12,6 +12,8 @@ #define NGX_RTMP_ACCESS_PLAY 0x02 +static ngx_int_t ngx_rtmp_access_connect(ngx_rtmp_session_t *s, + ngx_rtmp_header_t *h, ngx_chain_t *in); static ngx_int_t ngx_rtmp_access_publish(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in); static ngx_int_t ngx_rtmp_access_play(ngx_rtmp_session_t *s, @@ -19,12 +21,13 @@ static ngx_int_t ngx_rtmp_access_play(ngx_rtmp_session_t *s, static char * ngx_rtmp_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static ngx_int_t ngx_rtmp_access_postconfiguration(ngx_conf_t *cf); -static void * ngx_rtmp_access_create_srv_conf(ngx_conf_t *cf); -static char * ngx_rtmp_access_merge_srv_conf(ngx_conf_t *cf, +static void * ngx_rtmp_access_create_app_conf(ngx_conf_t *cf); +static char * ngx_rtmp_access_merge_app_conf(ngx_conf_t *cf, void *parent, void *child); static ngx_rtmp_amf0_handler_t ngx_rtmp_access_map[] = { + { ngx_string("connect"), ngx_rtmp_access_connect }, { ngx_string("publish"), ngx_rtmp_access_publish }, { ngx_string("play"), ngx_rtmp_access_play }, }; @@ -55,22 +58,22 @@ typedef struct { #if (NGX_HAVE_INET6) ngx_array_t *rules6; /* array of ngx_rtmp_access_rule6_t */ #endif -} ngx_rtmp_access_srv_conf_t; +} ngx_rtmp_access_app_conf_t; static ngx_command_t ngx_rtmp_access_commands[] = { { ngx_string("allow"), - NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1|NGX_CONF_TAKE2, + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE12, ngx_rtmp_access_rule, - NGX_RTMP_SRV_CONF_OFFSET, + NGX_RTMP_APP_CONF_OFFSET, 0, NULL }, { ngx_string("deny"), - NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1|NGX_CONF_TAKE2, + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE12, ngx_rtmp_access_rule, - NGX_RTMP_SRV_CONF_OFFSET, + NGX_RTMP_APP_CONF_OFFSET, 0, NULL }, @@ -83,8 +86,10 @@ static ngx_rtmp_module_t ngx_rtmp_access_module_ctx = { ngx_rtmp_access_postconfiguration, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ - ngx_rtmp_access_create_srv_conf, /* create server configuration */ - ngx_rtmp_access_merge_srv_conf /* merge server configuration */ + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + ngx_rtmp_access_create_app_conf, /* create app configuration */ + ngx_rtmp_access_merge_app_conf, /* merge app configuration */ }; @@ -105,21 +110,21 @@ ngx_module_t ngx_rtmp_access_module = { static void * -ngx_rtmp_access_create_srv_conf(ngx_conf_t *cf) +ngx_rtmp_access_create_app_conf(ngx_conf_t *cf) { - ngx_rtmp_access_srv_conf_t *ascf; + ngx_rtmp_access_app_conf_t *aacf; - ascf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_access_srv_conf_t)); - if (ascf == NULL) { + aacf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_access_app_conf_t)); + if (aacf == NULL) { return NULL; } - return ascf; + return aacf; } static char * -ngx_rtmp_access_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) +ngx_rtmp_access_merge_app_conf(ngx_conf_t *cf, void *parent, void *child) { return NGX_CONF_OK; } @@ -140,7 +145,7 @@ ngx_rtmp_access_found(ngx_rtmp_session_t *s, ngx_uint_t deny) static ngx_int_t ngx_rtmp_access_inet(ngx_rtmp_session_t *s, - ngx_rtmp_access_srv_conf_t *ascf, + ngx_rtmp_access_app_conf_t *ascf, in_addr_t addr, ngx_uint_t flag) { ngx_uint_t i; @@ -168,7 +173,7 @@ ngx_rtmp_access_inet(ngx_rtmp_session_t *s, static ngx_int_t ngx_rtmp_access_inet6(ngx_rtmp_session_t *s, - ngx_rtmp_srv_conf_t *ascf, + ngx_rtmp_app_conf_t *ascf, u_char *p, ngx_uint_t flag) { ngx_uint_t n; @@ -218,14 +223,20 @@ static ngx_int_t ngx_rtmp_access(ngx_rtmp_session_t *s, ngx_uint_t flag) { struct sockaddr_in *sin; - ngx_rtmp_access_srv_conf_t *ascf; + ngx_rtmp_access_app_conf_t *ascf; #if (NGX_HAVE_INET6) u_char *p; in_addr_t addr; struct sockaddr_in6 *sin6; #endif - ascf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_access_module); + ascf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_access_module); + + if (ascf == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, s->connection->log, 0, + "access: NULL loc conf"); + return NGX_ERROR; + } switch (s->connection->sockaddr->sa_family) { @@ -266,7 +277,7 @@ ngx_rtmp_access(ngx_rtmp_session_t *s, ngx_uint_t flag) static char * ngx_rtmp_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_rtmp_access_srv_conf_t *ascf = conf; + ngx_rtmp_access_app_conf_t *ascf = conf; ngx_int_t rc; ngx_uint_t all; @@ -390,7 +401,7 @@ ngx_rtmp_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) static ngx_int_t -ngx_rtmp_access_init(ngx_rtmp_session_t *s, +ngx_rtmp_access_connect(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) { return ngx_rtmp_access(s, NGX_RTMP_ACCESS_PUBLISH) == NGX_OK @@ -420,21 +431,16 @@ static ngx_int_t ngx_rtmp_access_postconfiguration(ngx_conf_t *cf) { ngx_rtmp_core_main_conf_t *cmcf; - ngx_rtmp_handler_pt *h; ngx_rtmp_amf0_handler_t *ch, *bh; size_t n, ncalls; cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module); - /* register event handlers */ - h = ngx_array_push(&cmcf->events[NGX_RTMP_CONNECT]); - *h = ngx_rtmp_access_init; - /* register AMF0 callbacks */ ncalls = sizeof(ngx_rtmp_access_map) / sizeof(ngx_rtmp_access_map[0]); ch = ngx_array_push_n(&cmcf->amf0, ncalls); - if (h == NULL) { + if (ch == NULL) { return NGX_ERROR; } diff --git a/ngx_rtmp_amf0.c b/ngx_rtmp_amf0.c index 3cc862e..09a6830 100644 --- a/ngx_rtmp_amf0.c +++ b/ngx_rtmp_amf0.c @@ -103,7 +103,7 @@ ngx_rtmp_amf0_get(ngx_rtmp_amf0_ctx_t *ctx, void *p, size_t n) ngx_log_debug1(NGX_LOG_DEBUG_RTMP, ctx->log, 0, "AMF0 read eof (%d)", n); - return NGX_ERROR; + return NGX_DONE; } @@ -243,14 +243,21 @@ ngx_rtmp_amf0_read(ngx_rtmp_amf0_ctx_t *ctx, ngx_rtmp_amf0_elt_t *elts, for(n = 0; till_end || n < nelts; ++n) { - if (ngx_rtmp_amf0_get(ctx, &type, sizeof(type)) != NGX_OK) - return NGX_ERROR; + switch (ngx_rtmp_amf0_get(ctx, &type, sizeof(type))) { + case NGX_DONE: + if (elts->type & NGX_RTMP_AMF0_OPTIONAL) { + return NGX_OK; + } + case NGX_ERROR: + return NGX_ERROR; + } - data = (n >= nelts || elts == NULL || elts->type != type) - ? NULL - : elts->data; + data = (n >= nelts || elts == NULL + || (elts->type & ~NGX_RTMP_AMF0_OPTIONAL) != type) + ? NULL + : elts->data; - switch(type) { + switch (type) { case NGX_RTMP_AMF0_NUMBER: if (ngx_rtmp_amf0_get(ctx, buf, 8) != NGX_OK) { return NGX_ERROR; diff --git a/ngx_rtmp_amf0.h b/ngx_rtmp_amf0.h index d3bb3cb..ffd7b2b 100644 --- a/ngx_rtmp_amf0.h +++ b/ngx_rtmp_amf0.h @@ -15,6 +15,8 @@ #define NGX_RTMP_AMF0_ARRAY 0x08 #define NGX_RTMP_AMF0_END 0x09 +#define NGX_RTMP_AMF0_OPTIONAL 0x80 + #include #include diff --git a/ngx_rtmp_app.c b/ngx_rtmp_app.c new file mode 100644 index 0000000..99e8fed --- /dev/null +++ b/ngx_rtmp_app.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2012 Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp.h" + + +#define NGX_RTMP_FMS_VERSION "FMS/3,0,1,123" +#define NGX_RTMP_CAPABILITIES 31 + + +ngx_int_t +ngx_rtmp_connect(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_rtmp_core_srv_conf_t *cscf; + ngx_uint_t n; + ngx_rtmp_core_app_conf_t **cacfp; + size_t len; + + static double trans; + static double capabilities = NGX_RTMP_CAPABILITIES; + + static struct { + u_char app[1024]; + u_char flashver[1024]; + u_char swf_url[1024]; + u_char tc_url[1024]; + double acodecs; + double vcodecs; + u_char page_url[1024]; + } v; + + + static ngx_rtmp_amf0_elt_t in_cmd[] = { + { NGX_RTMP_AMF0_STRING, "app", v.app, sizeof(v.app) }, + { NGX_RTMP_AMF0_STRING, "flashver", v.flashver, sizeof(v.flashver) }, + { NGX_RTMP_AMF0_STRING, "swfUrl", v.swf_url, sizeof(v.swf_url) }, + { NGX_RTMP_AMF0_STRING, "tcUrl", v.tc_url, sizeof(v.tc_url) }, + { NGX_RTMP_AMF0_NUMBER, "audioCodecs", &v.acodecs, sizeof(v.acodecs) }, + { NGX_RTMP_AMF0_NUMBER, "videoCodecs", &v.vcodecs, sizeof(v.vcodecs) }, + { NGX_RTMP_AMF0_STRING, "pageUrl", v.page_url, sizeof(v.page_url) }, + }; + + static ngx_rtmp_amf0_elt_t in_elts[] = { + { NGX_RTMP_AMF0_NUMBER, 0, &trans, 0 }, + { NGX_RTMP_AMF0_OBJECT, NULL, in_cmd, sizeof(in_cmd) }, + }; + + static ngx_rtmp_amf0_elt_t out_obj[] = { + { NGX_RTMP_AMF0_STRING, "fmsVer", NGX_RTMP_FMS_VERSION, 0 }, + { NGX_RTMP_AMF0_NUMBER, "capabilities", &capabilities, 0 }, + }; + + static ngx_rtmp_amf0_elt_t out_inf[] = { + { NGX_RTMP_AMF0_STRING, "level", "status", 0 }, + { NGX_RTMP_AMF0_STRING, "code", "NetConnection.Connect.Success", 0 }, + { NGX_RTMP_AMF0_STRING, "description", "Connection succeeded.", 0 }, + }; + + static ngx_rtmp_amf0_elt_t out_elts[] = { + { NGX_RTMP_AMF0_STRING, NULL, "_result", 0 }, + { NGX_RTMP_AMF0_NUMBER, NULL, &trans, 0 }, + { NGX_RTMP_AMF0_OBJECT, NULL, out_obj, sizeof(out_obj) }, + { NGX_RTMP_AMF0_OBJECT, NULL, out_inf, sizeof(out_inf) }, + }; + + if (s->connected) { + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, "duplicate connection"); + return NGX_ERROR; + } + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + /* parse input */ + ngx_memzero(&v, sizeof(v)); + if (ngx_rtmp_receive_amf0(s, in, in_elts, + sizeof(in_elts) / sizeof(in_elts[0]))) + { + return NGX_ERROR; + } + + ngx_log_debug7(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "connect: app='%s' flashver='%s' swf_url='%s' " + "tc_url='%s' page_url='%s' acodecs=%uD vcodecs=%uD", + v.app, v.flashver, v.swf_url, v.tc_url, v.page_url, + (uint32_t)v.acodecs, (uint32_t)v.vcodecs); + + /* fill session parameters */ + s->connected = 1; + +#define NGX_RTMP_SET_STRPAR(name) \ + s->name.len = ngx_strlen(v.name); \ + s->name.data = ngx_palloc(s->connection->pool, s->name.len); \ + ngx_memcpy(s->name.data, v.name, s->name.len) + + NGX_RTMP_SET_STRPAR(app); + NGX_RTMP_SET_STRPAR(flashver); + NGX_RTMP_SET_STRPAR(swf_url); + NGX_RTMP_SET_STRPAR(tc_url); + NGX_RTMP_SET_STRPAR(page_url); + +#undef NGX_RTMP_SET_STRPAR + + s->acodecs = v.acodecs; + s->vcodecs = v.vcodecs; + + /* find application & set app_conf */ + len = ngx_strlen(v.app); + + cacfp = cscf->applications.elts; + for(n = 0; n < cscf->applications.nelts; ++n, ++cacfp) { + if ((*cacfp)->name.len == len + && !ngx_strncmp((*cacfp)->name.data, v.app, len)) + { + /* found app! */ + s->app_conf = (*cacfp)->app_conf; + break; + } + } + + if (s->app_conf == NULL) { + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "application not found: '%s'", v.app); + return NGX_ERROR; + } + + /* send all replies */ + return ngx_rtmp_send_ack_size(s, cscf->ack_window) + || ngx_rtmp_send_bandwidth(s, cscf->ack_window, NGX_RTMP_LIMIT_DYNAMIC) + || ngx_rtmp_send_user_stream_begin(s, 0) + || ngx_rtmp_send_chunk_size(s, cscf->chunk_size) + || ngx_rtmp_send_amf0(s, h, out_elts, + sizeof(out_elts) / sizeof(out_elts[0])) + ? NGX_ERROR + : NGX_OK; + + /* we need NGX_OK not NGX_DONE to make access module + * work after connect has successfully finished */ +} + + +ngx_int_t +ngx_rtmp_create_stream(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + /* support one message stream per connection */ + static double stream = 1; + static double trans; + + static ngx_rtmp_amf0_elt_t in_elts[] = { + { NGX_RTMP_AMF0_NUMBER, 0, &trans, sizeof(trans) }, + }; + + static ngx_rtmp_amf0_elt_t out_elts[] = { + { NGX_RTMP_AMF0_STRING, NULL, "_result", 0 }, + { NGX_RTMP_AMF0_NUMBER, NULL, &trans, 0 }, + { NGX_RTMP_AMF0_NULL , NULL, NULL, 0 }, + { NGX_RTMP_AMF0_NUMBER, NULL, &stream, sizeof(stream) }, + }; + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "createStream"); + + /* parse input */ + if (ngx_rtmp_receive_amf0(s, in, in_elts, + sizeof(in_elts) / sizeof(in_elts[0]))) + { + return NGX_ERROR; + } + + /* send result with standard stream */ + return ngx_rtmp_send_amf0(s, h, out_elts, + sizeof(out_elts) / sizeof(out_elts[0])) == NGX_OK + ? NGX_DONE + : NGX_ERROR; +} + + +ngx_int_t +ngx_rtmp_amf0_default(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_rtmp_header_t sh; + + static double trans; + + static ngx_rtmp_amf0_elt_t in_elts[] = { + { NGX_RTMP_AMF0_NUMBER, 0, &trans, sizeof(trans) }, + }; + + static ngx_rtmp_amf0_elt_t out_elts[] = { + { NGX_RTMP_AMF0_STRING, NULL, "_result", 0 }, + { NGX_RTMP_AMF0_NUMBER, NULL, &trans, 0 }, + { NGX_RTMP_AMF0_NULL , NULL, NULL, 0 }, + { NGX_RTMP_AMF0_NULL , NULL, NULL, 0 }, + }; + + /* parse input */ + if (ngx_rtmp_receive_amf0(s, in, in_elts, + sizeof(in_elts) / sizeof(in_elts[0]))) + { + return NGX_ERROR; + } + + memset(&sh, 0, sizeof(sh)); + sh.csid = h->csid; + sh.type = NGX_RTMP_MSG_AMF0_CMD; + sh.msid = 0; + + /* send simple _result */ + return ngx_rtmp_send_amf0(s, &sh, out_elts, + sizeof(out_elts) / sizeof(out_elts[0])) == NGX_OK + ? NGX_DONE + : NGX_ERROR; +} diff --git a/ngx_rtmp_broadcast_module.c b/ngx_rtmp_broadcast_module.c index 586f41c..8ecc0e3 100644 --- a/ngx_rtmp_broadcast_module.c +++ b/ngx_rtmp_broadcast_module.c @@ -9,64 +9,73 @@ /* Standard stream ids for broadcasting */ -#define NGX_RTMP_BROADCAST_MSID 1 #define NGX_RTMP_BROADCAST_CSID_AMF0 5 #define NGX_RTMP_BROADCAST_CSID_AUDIO 6 #define NGX_RTMP_BROADCAST_CSID_VIDEO 7 static ngx_int_t ngx_rtmp_broadcast_postconfiguration(ngx_conf_t *cf); -static void * ngx_rtmp_broadcast_create_srv_conf(ngx_conf_t *cf); -static char * ngx_rtmp_broadcast_merge_srv_conf(ngx_conf_t *cf, +static void * ngx_rtmp_broadcast_create_app_conf(ngx_conf_t *cf); +static char * ngx_rtmp_broadcast_merge_app_conf(ngx_conf_t *cf, void *parent, void *child); -static ngx_int_t ngx_rtmp_broadcast_connect(ngx_rtmp_session_t *s, - ngx_rtmp_header_t *h, ngx_chain_t *in); -static ngx_int_t ngx_rtmp_broadcast_create_stream(ngx_rtmp_session_t *s, - ngx_rtmp_header_t *h, ngx_chain_t *in); static ngx_int_t ngx_rtmp_broadcast_publish(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in); static ngx_int_t ngx_rtmp_broadcast_play(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in); static ngx_int_t ngx_rtmp_broadcast_set_data_frame(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in); -static ngx_int_t ngx_rtmp_broadcast_ok(ngx_rtmp_session_t *s, - ngx_rtmp_header_t *h, ngx_chain_t *in); static ngx_int_t ngx_rtmp_broadcast_stream_length(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in); static ngx_rtmp_amf0_handler_t ngx_rtmp_broadcast_map[] = { - { ngx_string("connect"), ngx_rtmp_broadcast_connect }, - { ngx_string("createStream"), ngx_rtmp_broadcast_create_stream }, { ngx_string("publish"), ngx_rtmp_broadcast_publish }, { ngx_string("play"), ngx_rtmp_broadcast_play }, { ngx_string("-@setDataFrame"), ngx_rtmp_broadcast_set_data_frame }, - { ngx_string("releaseStream"), ngx_rtmp_broadcast_ok }, { ngx_string("getStreamLength"), ngx_rtmp_broadcast_stream_length }, - { ngx_string("FCPublish"), ngx_rtmp_broadcast_ok }, - { ngx_string("FCSubscribe"), ngx_rtmp_broadcast_ok }, + { ngx_string("releaseStream"), ngx_rtmp_amf0_default }, + { ngx_string("FCPublish"), ngx_rtmp_amf0_default }, + { ngx_string("FCSubscribe"), ngx_rtmp_amf0_default }, }; +typedef struct ngx_rtmp_broadcast_ctx_s ngx_rtmp_broadcast_ctx_t; + + typedef struct { - /* use hash-map - * stream -> broadcast contexts */ - ngx_int_t buckets; - struct ngx_rtmp_broadcast_ctx_s **contexts; -} ngx_rtmp_broadcast_srv_conf_t; + ngx_int_t nbuckets; + ngx_rtmp_broadcast_ctx_t **contexts; + ngx_flag_t live; + ngx_flag_t wait_key_frame; +} ngx_rtmp_broadcast_app_conf_t; static ngx_command_t ngx_rtmp_broadcast_commands[] = { - { ngx_string("broadcast_buckets"), - NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, - NGX_RTMP_SRV_CONF_OFFSET, - offsetof(ngx_rtmp_broadcast_srv_conf_t, buckets), + { ngx_string("live"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_broadcast_app_conf_t, live), NULL }, + { ngx_string("stream_buckets"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_broadcast_app_conf_t, nbuckets), + NULL }, + + { ngx_string("wait_key_frame"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_broadcast_app_conf_t, wait_key_frame), + NULL }, + + ngx_null_command }; @@ -76,8 +85,10 @@ static ngx_rtmp_module_t ngx_rtmp_broadcast_module_ctx = { ngx_rtmp_broadcast_postconfiguration, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ - ngx_rtmp_broadcast_create_srv_conf, /* create server configuration */ - ngx_rtmp_broadcast_merge_srv_conf /* merge server configuration */ + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + ngx_rtmp_broadcast_create_app_conf, /* create app configuration */ + ngx_rtmp_broadcast_merge_app_conf /* merge app configuration */ }; @@ -98,48 +109,52 @@ ngx_module_t ngx_rtmp_broadcast_module = { /* session flags */ -#define NGX_RTMP_BROADCAST_PUBLISHER 0x01 -#define NGX_RTMP_BROADCAST_SUBSCRIBER 0x02 +#define NGX_RTMP_BROADCAST_PUBLISHING 0x01 +#define NGX_RTMP_BROADCAST_PLAYING 0x02 #define NGX_RTMP_BROADCAST_KEYFRAME 0x04 #define NGX_RTMP_BROADCAST_DATA_FRAME 0x08 -typedef struct ngx_rtmp_broadcast_ctx_s { +struct ngx_rtmp_broadcast_ctx_s { ngx_str_t stream; ngx_rtmp_session_t *session; - struct ngx_rtmp_broadcast_ctx_s *next; + ngx_rtmp_broadcast_ctx_t *next; ngx_uint_t flags; uint32_t csid; ngx_chain_t *data_frame; -} ngx_rtmp_broadcast_ctx_t; +}; static void * -ngx_rtmp_broadcast_create_srv_conf(ngx_conf_t *cf) +ngx_rtmp_broadcast_create_app_conf(ngx_conf_t *cf) { - ngx_rtmp_broadcast_srv_conf_t *cscf; + ngx_rtmp_broadcast_app_conf_t *bacf; - cscf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_broadcast_srv_conf_t)); - if (cscf == NULL) { + bacf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_broadcast_app_conf_t)); + if (bacf == NULL) { return NULL; } - cscf->buckets = NGX_CONF_UNSET; + bacf->live = NGX_CONF_UNSET; + bacf->nbuckets = NGX_CONF_UNSET; + bacf->wait_key_frame = NGX_CONF_UNSET; - return cscf; + return bacf; } static char * -ngx_rtmp_broadcast_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) +ngx_rtmp_broadcast_merge_app_conf(ngx_conf_t *cf, void *parent, void *child) { - ngx_rtmp_broadcast_srv_conf_t *prev = parent; - ngx_rtmp_broadcast_srv_conf_t *conf = child; + ngx_rtmp_broadcast_app_conf_t *prev = parent; + ngx_rtmp_broadcast_app_conf_t *conf = child; - ngx_conf_merge_value(conf->buckets, prev->buckets, 1024); + ngx_conf_merge_value(conf->live, prev->live, 0); + ngx_conf_merge_value(conf->nbuckets, prev->nbuckets, 1024); + ngx_conf_merge_value(conf->wait_key_frame, prev->wait_key_frame, 1); conf->contexts = ngx_pcalloc(cf->pool, - sizeof(ngx_rtmp_broadcast_ctx_t *) * conf->buckets); + sizeof(ngx_rtmp_broadcast_ctx_t *) * conf->nbuckets); return NGX_CONF_OK; } @@ -148,29 +163,20 @@ ngx_rtmp_broadcast_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) static ngx_rtmp_broadcast_ctx_t ** ngx_rtmp_broadcast_get_head(ngx_rtmp_session_t *s) { - ngx_rtmp_broadcast_srv_conf_t *bscf; + ngx_rtmp_broadcast_app_conf_t *bacf; ngx_rtmp_broadcast_ctx_t *ctx; - bscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_broadcast_module); - ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_broadcast_module); + bacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_broadcast_module); - return &bscf->contexts[ - ngx_hash_key(ctx->stream.data, ctx->stream.len) - % bscf->buckets]; -} - - -static void -ngx_rtmp_broadcast_set_flags(ngx_rtmp_session_t *s, ngx_uint_t flags) -{ - ngx_rtmp_broadcast_ctx_t *ctx; - - ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_broadcast_module); - if (ctx == NULL) { - return; + if (bacf == NULL) { + return NULL; } - ctx->flags |= flags; + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_broadcast_module); + + return &bacf->contexts[ + ngx_hash_key(ctx->stream.data, ctx->stream.len) + % bacf->nbuckets]; } @@ -191,15 +197,18 @@ ngx_rtmp_broadcast_join(ngx_rtmp_session_t *s, ngx_str_t *stream, } if (ctx->stream.len) { - ngx_log_debug0(NGX_LOG_DEBUG_RTMP, c->log, 0, "already joined"); + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, c->log, 0, "live: already joined"); return; } ngx_log_debug1(NGX_LOG_DEBUG_RTMP, c->log, 0, - "join broadcast stream '%V'", stream); + "live: join '%V'", stream); ctx->stream = *stream; hctx = ngx_rtmp_broadcast_get_head(s); + if (hctx == NULL) { + return; + } ctx->next = *hctx; ctx->flags = flags; *hctx = ctx; @@ -207,7 +216,8 @@ ngx_rtmp_broadcast_join(ngx_rtmp_session_t *s, ngx_str_t *stream, static ngx_int_t -ngx_rtmp_broadcast_leave(ngx_rtmp_session_t *s) +ngx_rtmp_broadcast_leave(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) { ngx_connection_t *c; ngx_rtmp_broadcast_ctx_t *ctx, **hctx; @@ -220,9 +230,12 @@ ngx_rtmp_broadcast_leave(ngx_rtmp_session_t *s) } ngx_log_debug1(NGX_LOG_DEBUG_RTMP, c->log, 0, - "leave broadcast stream '%V'", &ctx->stream); + "live: leave '%V'", &ctx->stream); hctx = ngx_rtmp_broadcast_get_head(s); + if (hctx == NULL) { + return NGX_ERROR; + } ngx_str_null(&ctx->stream); for(; *hctx; hctx = &(*hctx)->next) { @@ -257,6 +270,7 @@ ngx_rtmp_broadcast_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_rtmp_broadcast_ctx_t *ctx, *cctx, *cnext; ngx_chain_t *out; ngx_rtmp_core_srv_conf_t *cscf; + ngx_rtmp_broadcast_app_conf_t *bacf; ngx_rtmp_session_t *ss; ngx_rtmp_header_t sh; ngx_uint_t priority; @@ -264,16 +278,28 @@ ngx_rtmp_broadcast_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, int keyframe; c = s->connection; - cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + bacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_broadcast_module); + + if (bacf == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, c->log, 0, + "live: NULL application"); + return NGX_ERROR; + } + + if (!bacf->live) { + return NGX_OK; + } + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_broadcast_module); + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); memset(&sh, 0, sizeof(sh)); sh.timestamp = (h->timestamp + s->epoch);/* & 0x00ffffff*/; /*FIXME*/ - sh.msid = NGX_RTMP_BROADCAST_MSID; + sh.msid = 1; sh.type = h->type; ngx_log_debug4(NGX_LOG_DEBUG_RTMP, c->log, 0, - "av packet; peer_epoch=%uD; my_epoch=%uD timestamp=%uD; r=%uD", + "live: av: peer_epoch=%uD; my_epoch=%uD timestamp=%uD; r=%uD", s->peer_epoch, s->epoch, h->timestamp, sh.timestamp); keyframe = 0; @@ -293,10 +319,10 @@ ngx_rtmp_broadcast_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, } if (ctx == NULL - || !(ctx->flags & NGX_RTMP_BROADCAST_PUBLISHER)) + || !(ctx->flags & NGX_RTMP_BROADCAST_PUBLISHING)) { ngx_log_debug0(NGX_LOG_DEBUG_RTMP, c->log, 0, - "received audio/video from non-publisher"); + "live: received audio/video from non-publisher"); return NGX_ERROR; } @@ -315,7 +341,7 @@ ngx_rtmp_broadcast_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, cnext = cctx->next; if (cctx == ctx - || !(cctx->flags & NGX_RTMP_BROADCAST_SUBSCRIBER) + || !(cctx->flags & NGX_RTMP_BROADCAST_PLAYING) || cctx->stream.len != ctx->stream.len || ngx_strncmp(cctx->stream.data, ctx->stream.data, ctx->stream.len)) @@ -331,7 +357,7 @@ ngx_rtmp_broadcast_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, && !(cctx->flags & NGX_RTMP_BROADCAST_DATA_FRAME)) { ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "sending data_frame"); + "live: sending data_frame"); rc = ngx_rtmp_send_message(ss, ctx->data_frame, 0); if (rc == NGX_ERROR) { @@ -344,7 +370,7 @@ ngx_rtmp_broadcast_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, } /* waiting for a keyframe? */ - if (cscf->wait_key_frame + if (bacf->wait_key_frame && sh.type == NGX_RTMP_MSG_VIDEO && !(cctx->flags & NGX_RTMP_BROADCAST_KEYFRAME) && !keyframe) @@ -357,7 +383,7 @@ ngx_rtmp_broadcast_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, && !(cctx->flags & NGX_RTMP_BROADCAST_KEYFRAME)) { ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "keyframe sent"); + "live: keyframe sent"); cctx->flags |= NGX_RTMP_BROADCAST_KEYFRAME; } } @@ -368,130 +394,26 @@ ngx_rtmp_broadcast_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, } -static ngx_int_t -ngx_rtmp_broadcast_done(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, - ngx_chain_t *in) -{ - return ngx_rtmp_broadcast_leave(s); -} - - -static ngx_int_t -ngx_rtmp_broadcast_connect(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, - ngx_chain_t *in) -{ - ngx_connection_t *c; - ngx_rtmp_core_srv_conf_t *cscf; - - static double trans; - static u_char app[1024]; - static ngx_str_t stream; - static double capabilities = 31; - - static ngx_rtmp_amf0_elt_t in_cmd[] = { - { NGX_RTMP_AMF0_STRING, "app", app, sizeof(app) }, - }; - - static ngx_rtmp_amf0_elt_t in_elts[] = { - { NGX_RTMP_AMF0_NUMBER, 0, &trans, 0 }, - { NGX_RTMP_AMF0_OBJECT, NULL, in_cmd, sizeof(in_cmd) }, - }; - - static ngx_rtmp_amf0_elt_t out_obj[] = { - { NGX_RTMP_AMF0_STRING, "fmsVer", "FMS/3,0,1,123", 0 }, - { NGX_RTMP_AMF0_NUMBER, "capabilities", &capabilities, 0 }, - }; - - static ngx_rtmp_amf0_elt_t out_inf[] = { - { NGX_RTMP_AMF0_STRING, "level", "status", 0 }, - { NGX_RTMP_AMF0_STRING, "code", "NetConnection.Connect.Success", 0 }, - { NGX_RTMP_AMF0_STRING, "description", "Connection succeeded.", 0 }, - }; - - static ngx_rtmp_amf0_elt_t out_elts[] = { - { NGX_RTMP_AMF0_STRING, NULL, "_result", 0 }, - { NGX_RTMP_AMF0_NUMBER, NULL, &trans, 0 }, - { NGX_RTMP_AMF0_OBJECT, NULL, out_obj, sizeof(out_obj) }, - { NGX_RTMP_AMF0_OBJECT, NULL, out_inf, sizeof(out_inf) }, - }; - - c = s->connection; - cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); - - /* parse input */ - app[0] = 0; - if (ngx_rtmp_receive_amf0(s, in, in_elts, - sizeof(in_elts) / sizeof(in_elts[0]))) - { - return NGX_ERROR; - } - - ngx_log_debug1(NGX_LOG_DEBUG_RTMP, c->log, 0, - "connect() called; app='%s'", app); - - /* join stream */ - stream.len = ngx_strlen(app); - stream.data = ngx_palloc(c->pool, stream.len); - ngx_memcpy(stream.data, app, stream.len); - ngx_rtmp_broadcast_join(s, &stream, 0); - - /* send all replies */ - return ngx_rtmp_send_ack_size(s, cscf->ack_window) - || ngx_rtmp_send_bandwidth(s, cscf->ack_window, NGX_RTMP_LIMIT_DYNAMIC) - || ngx_rtmp_send_user_stream_begin(s, 0) - || ngx_rtmp_send_chunk_size(s, cscf->chunk_size) - || ngx_rtmp_send_amf0(s, h, out_elts, - sizeof(out_elts) / sizeof(out_elts[0])) - ? NGX_ERROR - : NGX_OK; -} - - -static ngx_int_t -ngx_rtmp_broadcast_create_stream(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, - ngx_chain_t *in) -{ - static double trans; - static double stream; - - static ngx_rtmp_amf0_elt_t in_elts[] = { - { NGX_RTMP_AMF0_NUMBER, 0, &trans, sizeof(trans) }, - }; - - static ngx_rtmp_amf0_elt_t out_elts[] = { - { NGX_RTMP_AMF0_STRING, NULL, "_result", 0 }, - { NGX_RTMP_AMF0_NUMBER, NULL, &trans, 0 }, - { NGX_RTMP_AMF0_NULL , NULL, NULL, 0 }, - { NGX_RTMP_AMF0_NUMBER, NULL, &stream, sizeof(stream) }, - }; - - ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "createStream() called"); - - /* parse input */ - if (ngx_rtmp_receive_amf0(s, in, in_elts, - sizeof(in_elts) / sizeof(in_elts[0]))) - { - return NGX_ERROR; - } - - /* send result with standard stream */ - stream = NGX_RTMP_BROADCAST_MSID; - return ngx_rtmp_send_amf0(s, h, out_elts, - sizeof(out_elts) / sizeof(out_elts[0])); -} - - static ngx_int_t ngx_rtmp_broadcast_publish(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) { + ngx_rtmp_broadcast_app_conf_t *bacf; ngx_rtmp_header_t sh; + ngx_str_t stream; static double trans; + static struct { + u_char name[1024]; + u_char type[1024]; + } v; + static ngx_rtmp_amf0_elt_t in_elts[] = { - { NGX_RTMP_AMF0_NUMBER, 0, &trans, 0 }, + { NGX_RTMP_AMF0_NUMBER, 0, &trans, 0 }, + { NGX_RTMP_AMF0_NULL, 0, NULL, 0 }, + { NGX_RTMP_AMF0_STRING, 0, &v.name, sizeof(v.name) }, + { NGX_RTMP_AMF0_STRING, 0, &v.type, sizeof(v.type) }, }; static ngx_rtmp_amf0_elt_t out_inf[] = { @@ -507,6 +429,14 @@ ngx_rtmp_broadcast_publish(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, { NGX_RTMP_AMF0_OBJECT, NULL, out_inf, sizeof(out_inf) }, }; + bacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_broadcast_module); + + if (bacf == NULL || !bacf->live) { + return NGX_OK; + } + + ngx_memzero(&v, sizeof(v)); + /* parse input */ if (ngx_rtmp_receive_amf0(s, in, in_elts, sizeof(in_elts) / sizeof(in_elts[0]))) @@ -514,16 +444,20 @@ ngx_rtmp_broadcast_publish(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, return NGX_ERROR; } - ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "publish() called"); + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "live: publish: name='%s' type=%s", + v.name, v.type); - /* mark current session as publisher */ - ngx_rtmp_broadcast_set_flags(s, NGX_RTMP_BROADCAST_PUBLISHER); + /* join stream as publisher */ + stream.len = ngx_strlen(v.name); + stream.data = ngx_palloc(s->connection->pool, stream.len); + ngx_memcpy(stream.data, v.name, stream.len); + ngx_rtmp_broadcast_join(s, &stream, NGX_RTMP_BROADCAST_PUBLISHING); + + /* TODO: we can probably make any use of v.type: live/record/append */ /* start stream */ - if (ngx_rtmp_send_user_stream_begin(s, - NGX_RTMP_BROADCAST_MSID) != NGX_OK) - { + if (ngx_rtmp_send_user_stream_begin(s, 1) != NGX_OK) { return NGX_ERROR; } @@ -539,7 +473,7 @@ ngx_rtmp_broadcast_publish(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, return NGX_ERROR; } - return NGX_OK; + return NGX_DONE; } @@ -547,13 +481,30 @@ static ngx_int_t ngx_rtmp_broadcast_play(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) { + ngx_rtmp_broadcast_app_conf_t *bacf; ngx_rtmp_header_t sh; + ngx_str_t stream; static double trans; - static uint8_t bfalse; + static int bfalse; + + static struct { + u_char name[1024]; + double start; + double duration; + int flush; + } v; static ngx_rtmp_amf0_elt_t in_elts[] = { - { NGX_RTMP_AMF0_NUMBER, 0, &trans, 0 }, + { NGX_RTMP_AMF0_NUMBER, 0, &trans, 0 }, + { NGX_RTMP_AMF0_NULL, 0, NULL, 0 }, + { NGX_RTMP_AMF0_STRING, 0, &v.name, sizeof(v.name) }, + { NGX_RTMP_AMF0_OPTIONAL + | NGX_RTMP_AMF0_NUMBER, 0, &v.start, 0 }, + { NGX_RTMP_AMF0_OPTIONAL + | NGX_RTMP_AMF0_NUMBER, 0, &v.duration, 0 }, + { NGX_RTMP_AMF0_OPTIONAL + | NGX_RTMP_AMF0_BOOLEAN,0, &v.flush, 0 } }; static ngx_rtmp_amf0_elt_t out_inf[] = { @@ -597,6 +548,14 @@ ngx_rtmp_broadcast_play(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, { NGX_RTMP_AMF0_OBJECT, NULL, out4_inf, sizeof(out4_inf) }, }; + bacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_broadcast_module); + + if (bacf == NULL || !bacf->live) { + return NGX_OK; + } + + ngx_memzero(&v, sizeof(v)); + /* parse input */ if (ngx_rtmp_receive_amf0(s, in, in_elts, sizeof(in_elts) / sizeof(in_elts[0]))) @@ -604,16 +563,18 @@ ngx_rtmp_broadcast_play(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, return NGX_ERROR; } - ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "play() called"); + ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "live: play: name='%s' start=%uD duration=%uD flush=%d", + v.name, (uint32_t)v.start, (uint32_t)v.duration, v.flush); - /* mark session as subscriber */ - ngx_rtmp_broadcast_set_flags(s, NGX_RTMP_BROADCAST_SUBSCRIBER); + /* join stream as player */ + stream.len = ngx_strlen(v.name); + stream.data = ngx_palloc(s->connection->pool, stream.len); + ngx_memcpy(stream.data, v.name, stream.len); + ngx_rtmp_broadcast_join(s, &stream, NGX_RTMP_BROADCAST_PLAYING); /* start stream */ - if (ngx_rtmp_send_user_stream_begin(s, - NGX_RTMP_BROADCAST_MSID) != NGX_OK) - { + if (ngx_rtmp_send_user_stream_begin(s, 1) != NGX_OK) { return NGX_ERROR; } @@ -650,7 +611,7 @@ ngx_rtmp_broadcast_play(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, return NGX_ERROR; } - return NGX_OK; + return NGX_DONE; } @@ -658,6 +619,7 @@ static ngx_int_t ngx_rtmp_broadcast_set_data_frame(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) { + ngx_rtmp_broadcast_app_conf_t *bacf; ngx_connection_t *c; ngx_rtmp_broadcast_ctx_t *ctx; ngx_rtmp_amf0_ctx_t act; @@ -668,11 +630,17 @@ ngx_rtmp_broadcast_set_data_frame(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, { NGX_RTMP_AMF0_STRING, NULL, "@setDataFrame", 0 }, }; + bacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_broadcast_module); + + if (bacf == NULL || !bacf->live) { + return NGX_OK; + } + c = s->connection; cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_broadcast_module); - ngx_log_debug0(NGX_LOG_DEBUG_RTMP, c->log, 0, "data_frame arrived"); + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, c->log, 0, "live: data_frame"); /* TODO: allow sending more meta packages to change broadcast content */ @@ -712,49 +680,12 @@ ngx_rtmp_broadcast_set_data_frame(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, memset(&sh, 0, sizeof(sh)); sh.csid = NGX_RTMP_BROADCAST_CSID_AMF0; - sh.msid = NGX_RTMP_BROADCAST_MSID; + sh.msid = 1; sh.type = NGX_RTMP_MSG_AMF0_META; ngx_rtmp_prepare_message(s, &sh, NULL, ctx->data_frame); - return NGX_OK; -} - - -static ngx_int_t -ngx_rtmp_broadcast_ok(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, - ngx_chain_t *in) -{ - ngx_rtmp_header_t sh; - - static double trans; - - static ngx_rtmp_amf0_elt_t in_elts[] = { - { NGX_RTMP_AMF0_NUMBER, 0, &trans, sizeof(trans) }, - }; - - static ngx_rtmp_amf0_elt_t out_elts[] = { - { NGX_RTMP_AMF0_STRING, NULL, "_result", 0 }, - { NGX_RTMP_AMF0_NUMBER, NULL, &trans, 0 }, - { NGX_RTMP_AMF0_NULL , NULL, NULL, 0 }, - { NGX_RTMP_AMF0_NULL , NULL, NULL, 0 }, - }; - - /* parse input */ - if (ngx_rtmp_receive_amf0(s, in, in_elts, - sizeof(in_elts) / sizeof(in_elts[0]))) - { - return NGX_ERROR; - } - - memset(&sh, 0, sizeof(sh)); - sh.csid = h->csid; - sh.type = NGX_RTMP_MSG_AMF0_CMD; - sh.msid = 0; - - /* send simple _result */ - return ngx_rtmp_send_amf0(s, &sh, out_elts, - sizeof(out_elts) / sizeof(out_elts[0])); + return NGX_DONE; } @@ -762,6 +693,7 @@ static ngx_int_t ngx_rtmp_broadcast_stream_length(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) { + ngx_rtmp_broadcast_app_conf_t *bacf; ngx_rtmp_header_t sh; static double trans; @@ -777,6 +709,12 @@ ngx_rtmp_broadcast_stream_length(ngx_rtmp_session_t *s, { NGX_RTMP_AMF0_NUMBER, NULL, &length, 0 }, }; + bacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_broadcast_module); + + if (bacf == NULL || !bacf->live) { + return NGX_OK; + } + /* parse input */ if (ngx_rtmp_receive_amf0(s, in, in_elts, sizeof(in_elts) / sizeof(in_elts[0]))) @@ -791,7 +729,9 @@ ngx_rtmp_broadcast_stream_length(ngx_rtmp_session_t *s, /* send simple _result */ return ngx_rtmp_send_amf0(s, &sh, out_elts, - sizeof(out_elts) / sizeof(out_elts[0])); + sizeof(out_elts) / sizeof(out_elts[0])) == NGX_OK + ? NGX_DONE + : NGX_ERROR; } @@ -813,7 +753,7 @@ ngx_rtmp_broadcast_postconfiguration(ngx_conf_t *cf) *h = ngx_rtmp_broadcast_av; h = ngx_array_push(&cmcf->events[NGX_RTMP_DISCONNECT]); - *h = ngx_rtmp_broadcast_done; + *h = ngx_rtmp_broadcast_leave; /* register AMF0 callbacks */ ncalls = sizeof(ngx_rtmp_broadcast_map) diff --git a/ngx_rtmp_core_module.c b/ngx_rtmp_core_module.c index b014383..6c102d4 100644 --- a/ngx_rtmp_core_module.c +++ b/ngx_rtmp_core_module.c @@ -14,10 +14,15 @@ static void *ngx_rtmp_core_create_main_conf(ngx_conf_t *cf); static void *ngx_rtmp_core_create_srv_conf(ngx_conf_t *cf); static char *ngx_rtmp_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child); +static void *ngx_rtmp_core_create_app_conf(ngx_conf_t *cf); +static char *ngx_rtmp_core_merge_app_conf(ngx_conf_t *cf, void *parent, + void *child); static char *ngx_rtmp_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_rtmp_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_rtmp_core_application(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static ngx_conf_deprecated_t ngx_conf_deprecated_so_keepalive = { @@ -42,6 +47,13 @@ static ngx_command_t ngx_rtmp_core_commands[] = { 0, NULL }, + { ngx_string("application"), + NGX_RTMP_SRV_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1, + ngx_rtmp_core_application, + NGX_RTMP_SRV_CONF_OFFSET, + 0, + NULL }, + { ngx_string("so_keepalive"), NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -91,23 +103,16 @@ static ngx_command_t ngx_rtmp_core_commands[] = { offsetof(ngx_rtmp_core_srv_conf_t, max_message), NULL }, - { ngx_string("wait_key_frame"), - NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_flag_slot, - NGX_RTMP_SRV_CONF_OFFSET, - offsetof(ngx_rtmp_core_srv_conf_t, wait_key_frame), - NULL }, - /* time fixes are needed for flash clients */ { ngx_string("play_time_fix"), - NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, ngx_conf_set_flag_slot, NGX_RTMP_SRV_CONF_OFFSET, offsetof(ngx_rtmp_core_srv_conf_t, play_time_fix), NULL }, { ngx_string("publish_time_fix"), - NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, ngx_conf_set_flag_slot, NGX_RTMP_SRV_CONF_OFFSET, offsetof(ngx_rtmp_core_srv_conf_t, publish_time_fix), @@ -123,7 +128,9 @@ static ngx_rtmp_module_t ngx_rtmp_core_module_ctx = { ngx_rtmp_core_create_main_conf, /* create main configuration */ NULL, /* init main configuration */ ngx_rtmp_core_create_srv_conf, /* create server configuration */ - ngx_rtmp_core_merge_srv_conf /* merge server configuration */ + ngx_rtmp_core_merge_srv_conf, /* merge server configuration */ + ngx_rtmp_core_create_app_conf, /* create app configuration */ + ngx_rtmp_core_merge_app_conf /* merge app configuration */ }; @@ -180,6 +187,13 @@ ngx_rtmp_core_create_srv_conf(ngx_conf_t *cf) return NULL; } + if (ngx_array_init(&conf->applications, cf->pool, 4, + sizeof(ngx_rtmp_core_app_conf_t *)) + != NGX_OK) + { + return NULL; + } + conf->timeout = NGX_CONF_UNSET_MSEC; conf->so_keepalive = NGX_CONF_UNSET; conf->max_streams = NGX_CONF_UNSET; @@ -187,7 +201,6 @@ ngx_rtmp_core_create_srv_conf(ngx_conf_t *cf) conf->ack_window = NGX_CONF_UNSET; conf->max_buf = NGX_CONF_UNSET; conf->max_message = NGX_CONF_UNSET; - conf->wait_key_frame = NGX_CONF_UNSET; conf->play_time_fix = NGX_CONF_UNSET; conf->publish_time_fix = NGX_CONF_UNSET; @@ -209,7 +222,6 @@ ngx_rtmp_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_uint_value(conf->ack_window, prev->ack_window, 5000000); ngx_conf_merge_size_value(conf->max_buf, prev->max_buf, 128 * 1024); ngx_conf_merge_size_value(conf->max_message, prev->max_message, 1024 * 1024); - ngx_conf_merge_value(conf->wait_key_frame, prev->wait_key_frame, 1); ngx_conf_merge_value(conf->play_time_fix, prev->play_time_fix, 1); ngx_conf_merge_value(conf->publish_time_fix, prev->publish_time_fix, 1); @@ -226,6 +238,33 @@ ngx_rtmp_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) } +static void * +ngx_rtmp_core_create_app_conf(ngx_conf_t *cf) +{ + ngx_rtmp_core_app_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_core_app_conf_t)); + if (conf == NULL) { + return NULL; + } + + return conf; +} + + +static char * +ngx_rtmp_core_merge_app_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_rtmp_core_app_conf_t *prev = parent; + ngx_rtmp_core_app_conf_t *conf = child; + + (void)prev; + (void)conf; + + return NGX_CONF_OK; +} + + static char * ngx_rtmp_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { @@ -253,6 +292,11 @@ ngx_rtmp_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } + ctx->app_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_rtmp_max_module); + if (ctx->app_conf == NULL) { + return NGX_CONF_ERROR; + } + for (m = 0; ngx_modules[m]; m++) { if (ngx_modules[m]->type != NGX_RTMP_MODULE) { continue; @@ -268,6 +312,15 @@ ngx_rtmp_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf; } + + if (module->create_app_conf) { + mconf = module->create_app_conf(cf); + if (mconf == NULL) { + return NGX_CONF_ERROR; + } + + ctx->app_conf[ngx_modules[m]->ctx_index] = mconf; + } } /* the server configuration context */ @@ -299,6 +352,75 @@ ngx_rtmp_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +static char * +ngx_rtmp_core_application(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *rv; + ngx_int_t i; + ngx_str_t *value; + ngx_conf_t save; + ngx_rtmp_module_t *module; + ngx_rtmp_conf_ctx_t *ctx, *pctx; + ngx_rtmp_core_srv_conf_t *cscf; + ngx_rtmp_core_app_conf_t *cacf, **cacfp; + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_conf_ctx_t)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + pctx = cf->ctx; + ctx->main_conf = pctx->main_conf; + ctx->srv_conf = pctx->srv_conf; + + ctx->app_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_rtmp_max_module); + if (ctx->app_conf == NULL) { + return NGX_CONF_ERROR; + } + + for (i = 0; ngx_modules[i]; i++) { + if (ngx_modules[i]->type != NGX_RTMP_MODULE) { + continue; + } + + module = ngx_modules[i]->ctx; + + if (module->create_app_conf) { + ctx->app_conf[ngx_modules[i]->ctx_index] = + module->create_app_conf(cf); + if (ctx->app_conf[ngx_modules[i]->ctx_index] == NULL) { + return NGX_CONF_ERROR; + } + } + } + + cacf = ctx->app_conf[ngx_rtmp_core_module.ctx_index]; + cacf->app_conf = ctx->app_conf; + + value = cf->args->elts; + + cacf->name = value[1]; + cscf = pctx->srv_conf[ngx_rtmp_core_module.ctx_index]; + + cacfp = ngx_array_push(&cscf->applications); + if (cacf == NULL) { + return NGX_CONF_ERROR; + } + + *cacfp = cacf; + + save = *cf; + cf->ctx = ctx; + cf->cmd_type = NGX_RTMP_APP_CONF; + + rv = ngx_conf_parse(cf, NULL); + + *cf= save; + + return rv; +} + + static char * ngx_rtmp_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { @@ -543,4 +665,3 @@ ngx_rtmp_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_OK; } - diff --git a/test/nginx.conf b/test/nginx.conf index fc88159..d92265f 100644 --- a/test/nginx.conf +++ b/test/nginx.conf @@ -20,19 +20,23 @@ rtmp { listen 1935; - #wait_key_frame on; - chunk_size 128; max_buf 1000000; #timestamp_fix on; - #allow play all; + application helo { - allow publish 127.0.0.1; + live on; - deny publish all; + #wait_key_frame on; + + # publish only from localhost + allow publish 127.0.0.1; + + deny publish all; + } } } diff --git a/test/www/index.html b/test/www/index.html index c9f358d..cb234ad 100644 --- a/test/www/index.html +++ b/test/www/index.html @@ -9,9 +9,9 @@ { type: "flash", src: "/jwplayer/player.swf", config: { - bufferlength: 3, - file: "livepresentation", - streamer: "rtmp://192.168.0.100/helo", + bufferlength: 3, + file: "online", + streamer: "rtmp://10.31.1.78/helo", provider: "rtmp", } }