Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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.
  • Loading branch information...
commit ac13bbf1af345532a009a88d93ac4b7869ffe456 2 parents 9652689 + 17886de
Roman Arutyunyan arut authored
18 README.md
Source Rendered
@@ -2,13 +2,13 @@
2 2 ## nginx-rtmp-module
3 3
4 4
5   -### Project page:
  5 +### Project blog:
6 6
7   - http://arut.github.com/nginx-rtmp-module
  7 + http://rarut.wordpress.com
8 8
9 9 ### Wiki manual:
10 10
11   - https://github.com/arut/nginx-rtmp-module/wiki
  11 + https://github.com/arut/nginx-rtmp-module/wiki/Directives
12 12
13 13 ### Features:
14 14
@@ -19,17 +19,19 @@
19 19 * Stream relay support for distributed
20 20 streaming: push & pull models
21 21
22   -* Recording published streams in FLV file
  22 +* Recording streams in multiple FLVs
23 23
24 24 * H264/AAC support
25 25
26 26 * Online transcoding with FFmpeg
27 27
28 28 * HLS (HTTP Live Streaming) support;
29   - experimental; requires recent libavformat
  29 + requires recent libavformat
30 30 (>= 53.31.100) from ffmpeg (ffmpeg.org)
31 31
32   -* HTTP callbacks on publish/play/record
  32 +* HTTP callbacks (publish/play/record etc)
  33 +
  34 +* Running external programs on certain events (exec)
33 35
34 36 * Advanced buffering techniques
35 37 to keep memory allocations at a minimum
@@ -44,6 +46,8 @@
44 46 * Statistics in XML/XSL in machine- & human-
45 47 readable form
46 48
  49 +* Linux/FreeBSD/MacOS
  50 +
47 51
48 52 ### Build:
49 53
@@ -197,7 +201,7 @@ rtmp_auto_push directive.
197 201 }
198 202
199 203
200   - # HLS (experimental)
  204 + # HLS
201 205
202 206 # HLS requires libavformat & should be configured as a separate
203 207 # NGINX module in addition to nginx-rtmp-module:
12 config
@@ -5,16 +5,18 @@ CORE_MODULES="$CORE_MODULES
5 5 ngx_rtmp_core_module \
6 6 ngx_rtmp_cmd_module \
7 7 ngx_rtmp_access_module \
  8 + ngx_rtmp_record_module \
8 9 ngx_rtmp_live_module \
9 10 ngx_rtmp_play_module \
10 11 ngx_rtmp_flv_module \
11 12 ngx_rtmp_mp4_module \
12   - ngx_rtmp_record_module \
13 13 ngx_rtmp_netcall_module \
14   - ngx_rtmp_notify_module \
15 14 ngx_rtmp_relay_module \
16 15 ngx_rtmp_exec_module \
17 16 ngx_rtmp_codec_module \
  17 + ngx_rtmp_auto_push_module \
  18 + ngx_rtmp_enotify_module \
  19 + ngx_rtmp_notify_module \
18 20 "
19 21
20 22
@@ -31,23 +33,25 @@ NGX_ADDON_SRCS="$NGX_ADDON_SRCS \
31 33 $ngx_addon_dir/ngx_rtmp_amf.c \
32 34 $ngx_addon_dir/ngx_rtmp_send.c \
33 35 $ngx_addon_dir/ngx_rtmp_shared.c \
  36 + $ngx_addon_dir/ngx_rtmp_eval.c \
34 37 $ngx_addon_dir/ngx_rtmp_receive.c \
35 38 $ngx_addon_dir/ngx_rtmp_core_module.c \
36 39 $ngx_addon_dir/ngx_rtmp_cmd_module.c \
37 40 $ngx_addon_dir/ngx_rtmp_access_module.c \
  41 + $ngx_addon_dir/ngx_rtmp_record_module.c \
38 42 $ngx_addon_dir/ngx_rtmp_live_module.c \
39 43 $ngx_addon_dir/ngx_rtmp_play_module.c \
40 44 $ngx_addon_dir/ngx_rtmp_flv_module.c \
41 45 $ngx_addon_dir/ngx_rtmp_mp4_module.c \
42   - $ngx_addon_dir/ngx_rtmp_record_module.c \
43 46 $ngx_addon_dir/ngx_rtmp_netcall_module.c \
44   - $ngx_addon_dir/ngx_rtmp_notify_module.c \
45 47 $ngx_addon_dir/ngx_rtmp_stat_module.c \
46 48 $ngx_addon_dir/ngx_rtmp_relay_module.c \
47 49 $ngx_addon_dir/ngx_rtmp_bandwidth.c \
48 50 $ngx_addon_dir/ngx_rtmp_exec_module.c \
49 51 $ngx_addon_dir/ngx_rtmp_codec_module.c \
50 52 $ngx_addon_dir/ngx_rtmp_auto_push_module.c \
  53 + $ngx_addon_dir/ngx_rtmp_enotify_module.c \
  54 + $ngx_addon_dir/ngx_rtmp_notify_module.c \
51 55 "
52 56 CFLAGS="$CFLAGS -I$ngx_addon_dir"
53 57
9 ngx_rtmp.c
@@ -317,6 +317,7 @@ ngx_rtmp_merge_applications(ngx_conf_t *cf, ngx_array_t *applications,
317 317 ngx_rtmp_conf_ctx_t *ctx, saved;
318 318 ngx_rtmp_core_app_conf_t **cacfp;
319 319 ngx_uint_t n;
  320 + ngx_rtmp_core_app_conf_t *cacf;
320 321
321 322 if (applications == NULL) {
322 323 return NGX_CONF_OK;
@@ -335,6 +336,14 @@ ngx_rtmp_merge_applications(ngx_conf_t *cf, ngx_array_t *applications,
335 336 if (rv != NGX_CONF_OK) {
336 337 return rv;
337 338 }
  339 +
  340 + cacf = (*cacfp)->app_conf[ngx_rtmp_core_module.ctx_index];
  341 + rv = ngx_rtmp_merge_applications(cf, &cacf->applications,
  342 + (*cacfp)->app_conf,
  343 + module, ctx_index);
  344 + if (rv != NGX_CONF_OK) {
  345 + return rv;
  346 + }
338 347 }
339 348
340 349 *ctx = saved;
3  ngx_rtmp.h
@@ -209,6 +209,7 @@ typedef struct {
209 209
210 210 /* auto-pushed? */
211 211 unsigned auto_pushed:1;
  212 + unsigned relay:1;
212 213
213 214 /* input stream 0 (reserved by RTMP spec)
214 215 * is used as free chain link */
@@ -294,6 +295,7 @@ typedef struct ngx_rtmp_core_srv_conf_s {
294 295
295 296
296 297 typedef struct {
  298 + ngx_array_t applications; /* ngx_rtmp_core_app_conf_t */
297 299 ngx_str_t name;
298 300 void **app_conf;
299 301 } ngx_rtmp_core_app_conf_t;
@@ -326,6 +328,7 @@ typedef struct {
326 328 #define NGX_RTMP_MAIN_CONF 0x02000000
327 329 #define NGX_RTMP_SRV_CONF 0x04000000
328 330 #define NGX_RTMP_APP_CONF 0x08000000
  331 +#define NGX_RTMP_REC_CONF 0x10000000
329 332
330 333
331 334 #define NGX_RTMP_MAIN_CONF_OFFSET offsetof(ngx_rtmp_conf_ctx_t, main_conf)
2  ngx_rtmp_auto_push_module.c
@@ -400,7 +400,7 @@ ngx_rtmp_auto_push_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
400 400 ngx_rtmp_auto_push_conf_t *apcf;
401 401 ngx_rtmp_auto_push_ctx_t *ctx;
402 402
403   - if (s->auto_pushed) {
  403 + if (s->auto_pushed || s->relay) {
404 404 goto next;
405 405 }
406 406
27 ngx_rtmp_cmd_module.c
@@ -200,7 +200,7 @@ ngx_rtmp_cmd_connect(ngx_rtmp_session_t *s, ngx_rtmp_connect_t *v)
200 200
201 201 cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module);
202 202
203   - ngx_log_debug8(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
  203 + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
204 204 "connect: app='%s' flashver='%s' swf_url='%s' "
205 205 "tc_url='%s' page_url='%s' acodecs=%uD vcodecs=%uD "
206 206 "object_encoding=%ui",
@@ -327,7 +327,7 @@ ngx_rtmp_cmd_create_stream(ngx_rtmp_session_t *s, ngx_rtmp_create_stream_t *v)
327 327 h.csid = NGX_RTMP_CMD_CSID_AMF_INI;
328 328 h.type = NGX_RTMP_MSG_AMF_CMD;
329 329
330   - ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
  330 + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
331 331 "createStream");
332 332
333 333 /* 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)
415 415 {
416 416 ngx_rtmp_close_stream_t cv;
417 417
  418 + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
  419 + "deleteStream");
  420 +
418 421 /* chain close_stream */
419 422 cv.stream = 0;
420 423 return ngx_rtmp_close_stream
@@ -523,7 +526,7 @@ ngx_rtmp_cmd_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
523 526 out_inf, sizeof(out_inf) },
524 527 };
525 528
526   - ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
  529 + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
527 530 "publish: name='%s' args='%s' type=%s silent=%d",
528 531 v->name, v->args, v->type, v->silent);
529 532
@@ -621,7 +624,7 @@ ngx_rtmp_cmd_fcpublish(ngx_rtmp_session_t *s, ngx_rtmp_fcpublish_t *v)
621 624 out_inf, sizeof(out_inf) },
622 625 };
623 626
624   - ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
  627 + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
625 628 "fcpublish: name='%s'", v->name);
626 629
627 630 /* send onFCPublish reply */
@@ -801,8 +804,8 @@ ngx_rtmp_cmd_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v)
801 804 out4_inf, sizeof(out4_inf) },
802 805 };
803 806
804   - ngx_log_debug6(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
805   - "cmd: play name='%s' args='%s' start=%i duration=%i "
  807 + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
  808 + "play name='%s' args='%s' start=%i duration=%i "
806 809 "reset=%i silent=%i",
807 810 v->name, v->args, (ngx_int_t) v->start,
808 811 (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)
934 937 sizeof(out_inf) },
935 938 };
936 939
937   - ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
  940 + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
938 941 "fcsubscribe: name='%s'", v->name);
939 942
940 943 /* send onFCSubscribe reply */
@@ -1038,6 +1041,10 @@ ngx_rtmp_cmd_pause(ngx_rtmp_session_t *s, ngx_rtmp_pause_t *v)
1038 1041 out_inf, sizeof(out_inf) },
1039 1042 };
1040 1043
  1044 + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
  1045 + "pause: state='%i' position=%i",
  1046 + v->pause, (ngx_int_t) v->position);
  1047 +
1041 1048 /* send onStatus reply */
1042 1049 ngx_memzero(&h, sizeof(h));
1043 1050 h.type = NGX_RTMP_MSG_AMF_CMD;
@@ -1068,6 +1075,9 @@ static ngx_int_t
1068 1075 ngx_rtmp_cmd_disconnect(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
1069 1076 ngx_chain_t *in)
1070 1077 {
  1078 + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
  1079 + "disconnect");
  1080 +
1071 1081 return ngx_rtmp_delete_stream
1072 1082 ? ngx_rtmp_delete_stream(s, NULL)
1073 1083 : NGX_OK;
@@ -1152,6 +1162,9 @@ ngx_rtmp_cmd_seek(ngx_rtmp_session_t *s, ngx_rtmp_seek_t *v)
1152 1162 out_inf, sizeof(out_inf) },
1153 1163 };
1154 1164
  1165 + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
  1166 + "seek: offset=%i", (ngx_int_t) v->offset);
  1167 +
1155 1168 /* send onStatus reply */
1156 1169 ngx_memzero(&h, sizeof(h));
1157 1170 h.type = NGX_RTMP_MSG_AMF_CMD;
7 ngx_rtmp_core_module.c
@@ -282,6 +282,13 @@ ngx_rtmp_core_create_app_conf(ngx_conf_t *cf)
282 282 return NULL;
283 283 }
284 284
  285 + if (ngx_array_init(&conf->applications, cf->pool, 1,
  286 + sizeof(ngx_rtmp_core_app_conf_t *))
  287 + != NGX_OK)
  288 + {
  289 + return NULL;
  290 + }
  291 +
285 292 return conf;
286 293 }
287 294
564 ngx_rtmp_enotify_module.c
... ... @@ -0,0 +1,564 @@
  1 +/*
  2 + * Copyright (c) 2012 Roman Arutyunyan
  3 + */
  4 +
  5 +
  6 +#include <ngx_config.h>
  7 +#include <ngx_core.h>
  8 +#include "ngx_rtmp.h"
  9 +
  10 +#include "ngx_rtmp_eval.h"
  11 +#include "ngx_rtmp_cmd_module.h"
  12 +#include "ngx_rtmp_record_module.h"
  13 +
  14 +#include <stdlib.h>
  15 +#ifdef NGX_LINUX
  16 +#include <unistd.h>
  17 +#endif
  18 +
  19 +
  20 +static ngx_rtmp_publish_pt next_publish;
  21 +static ngx_rtmp_play_pt next_play;
  22 +static ngx_rtmp_delete_stream_pt next_delete_stream;
  23 +static ngx_rtmp_record_done_pt next_record_done;
  24 +
  25 +
  26 +static char *ngx_rtmp_enotify_on_event(ngx_conf_t *cf, ngx_command_t *cmd,
  27 + void *conf);
  28 +static ngx_int_t ngx_rtmp_enotify_postconfiguration(ngx_conf_t *cf);
  29 +static void * ngx_rtmp_enotify_create_app_conf(ngx_conf_t *cf);
  30 +static char * ngx_rtmp_enotify_merge_app_conf(ngx_conf_t *cf,
  31 + void *parent, void *child);
  32 +
  33 +
  34 +#define NGX_RTMP_ENOTIFY_PUBLISHING 0x01
  35 +#define NGX_RTMP_ENOTIFY_PLAYING 0x02
  36 +
  37 +
  38 +enum {
  39 + NGX_RTMP_ENOTIFY_PUBLISH,
  40 + NGX_RTMP_ENOTIFY_PLAY,
  41 + NGX_RTMP_ENOTIFY_PUBLISH_DONE,
  42 + NGX_RTMP_ENOTIFY_PLAY_DONE,
  43 + NGX_RTMP_ENOTIFY_RECORD_DONE,
  44 + NGX_RTMP_ENOTIFY_MAX
  45 +};
  46 +
  47 +
  48 +typedef struct {
  49 + ngx_str_t cmd;
  50 + ngx_array_t args; /* ngx_str_t */
  51 +} ngx_rtmp_enotify_conf_t;
  52 +
  53 +
  54 +typedef struct {
  55 + ngx_rtmp_enotify_conf_t *event[NGX_RTMP_ENOTIFY_MAX];
  56 + ngx_flag_t active;
  57 +} ngx_rtmp_enotify_app_conf_t;
  58 +
  59 +
  60 +typedef struct {
  61 + ngx_uint_t flags;
  62 + u_char name[NGX_RTMP_MAX_NAME];
  63 + u_char args[NGX_RTMP_MAX_ARGS];
  64 + ngx_str_t path;
  65 + ngx_str_t recorder;
  66 +} ngx_rtmp_enotify_ctx_t;
  67 +
  68 +
  69 +static ngx_command_t ngx_rtmp_enotify_commands[] = {
  70 +
  71 + { ngx_string("exec_publish"),
  72 + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_1MORE,
  73 + ngx_rtmp_enotify_on_event,
  74 + NGX_RTMP_APP_CONF_OFFSET,
  75 + 0,
  76 + NULL },
  77 +
  78 + { ngx_string("exec_play"),
  79 + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_1MORE,
  80 + ngx_rtmp_enotify_on_event,
  81 + NGX_RTMP_APP_CONF_OFFSET,
  82 + 0,
  83 + NULL },
  84 +
  85 + { ngx_string("exec_publish_done"),
  86 + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_1MORE,
  87 + ngx_rtmp_enotify_on_event,
  88 + NGX_RTMP_APP_CONF_OFFSET,
  89 + 0,
  90 + NULL },
  91 +
  92 + { ngx_string("exec_play_done"),
  93 + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_1MORE,
  94 + ngx_rtmp_enotify_on_event,
  95 + NGX_RTMP_APP_CONF_OFFSET,
  96 + 0,
  97 + NULL },
  98 +
  99 + { ngx_string("exec_record_done"),
  100 + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_RTMP_REC_CONF|
  101 + NGX_CONF_1MORE,
  102 + ngx_rtmp_enotify_on_event,
  103 + NGX_RTMP_APP_CONF_OFFSET,
  104 + 0,
  105 + NULL },
  106 +
  107 + ngx_null_command
  108 +};
  109 +
  110 +
  111 +static ngx_rtmp_module_t ngx_rtmp_enotify_module_ctx = {
  112 + NULL, /* preconfiguration */
  113 + ngx_rtmp_enotify_postconfiguration, /* postconfiguration */
  114 + NULL, /* create main configuration */
  115 + NULL, /* init main configuration */
  116 + NULL, /* create server configuration */
  117 + NULL, /* merge server configuration */
  118 + ngx_rtmp_enotify_create_app_conf, /* create app configuration */
  119 + ngx_rtmp_enotify_merge_app_conf /* merge app configuration */
  120 +};
  121 +
  122 +
  123 +ngx_module_t ngx_rtmp_enotify_module = {
  124 + NGX_MODULE_V1,
  125 + &ngx_rtmp_enotify_module_ctx, /* module context */
  126 + ngx_rtmp_enotify_commands, /* module directives */
  127 + NGX_RTMP_MODULE, /* module type */
  128 + NULL, /* init master */
  129 + NULL, /* init module */
  130 + NULL, /* init process */
  131 + NULL, /* init thread */
  132 + NULL, /* exit thread */
  133 + NULL, /* exit process */
  134 + NULL, /* exit master */
  135 + NGX_MODULE_V1_PADDING
  136 +};
  137 +
  138 +
  139 +static void
  140 +ngx_rtmp_enotify_eval_astr(ngx_rtmp_session_t *s, ngx_rtmp_eval_t *e,
  141 + ngx_str_t *ret)
  142 +{
  143 + ngx_rtmp_enotify_ctx_t *ctx;
  144 +
  145 + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_enotify_module);
  146 + if (ctx == NULL) {
  147 + ret->len = 0;
  148 + return;
  149 + }
  150 +
  151 + ret->data = (u_char *) ctx + e->offset;
  152 + ret->len = ngx_strlen(ret->data);
  153 +}
  154 +
  155 +
  156 +static void
  157 +ngx_rtmp_enotify_eval_str(ngx_rtmp_session_t *s, ngx_rtmp_eval_t *e,
  158 + ngx_str_t *ret)
  159 +{
  160 + ngx_rtmp_enotify_ctx_t *ctx;
  161 +
  162 + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_enotify_module);
  163 + if (ctx == NULL) {
  164 + ret->len = 0;
  165 + return;
  166 + }
  167 +
  168 + *ret = *(ngx_str_t *) ((u_char *) ctx + e->offset);
  169 +}
  170 +
  171 +
  172 +static ngx_rtmp_eval_t ngx_rtmp_enotify_eval[] = {
  173 +
  174 + { ngx_string("name"),
  175 + ngx_rtmp_enotify_eval_astr,
  176 + offsetof(ngx_rtmp_enotify_ctx_t, name) },
  177 +
  178 + { ngx_string("args"),
  179 + ngx_rtmp_enotify_eval_astr,
  180 + offsetof(ngx_rtmp_enotify_ctx_t, args) },
  181 +
  182 + { ngx_string("path"),
  183 + ngx_rtmp_enotify_eval_str,
  184 + offsetof(ngx_rtmp_enotify_ctx_t, path) },
  185 +
  186 + { ngx_string("recorder"),
  187 + ngx_rtmp_enotify_eval_str,
  188 + offsetof(ngx_rtmp_enotify_ctx_t, recorder) },
  189 +
  190 + ngx_rtmp_null_eval
  191 +};
  192 +
  193 +
  194 +static ngx_rtmp_eval_t * ngx_rtmp_enotify_eval_p[] = {
  195 + ngx_rtmp_eval_session,
  196 + ngx_rtmp_enotify_eval,
  197 + NULL
  198 +};
  199 +
  200 +
  201 +static void *
  202 +ngx_rtmp_enotify_create_app_conf(ngx_conf_t *cf)
  203 +{
  204 + ngx_rtmp_enotify_app_conf_t *enacf;
  205 + ngx_uint_t n;
  206 +
  207 + enacf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_enotify_app_conf_t));
  208 + if (enacf == NULL) {
  209 + return NULL;
  210 + }
  211 +
  212 + for (n = 0; n < NGX_RTMP_ENOTIFY_MAX; ++n) {
  213 + enacf->event[n] = NGX_CONF_UNSET_PTR;
  214 + }
  215 +
  216 + return enacf;
  217 +}
  218 +
  219 +
  220 +static char *
  221 +ngx_rtmp_enotify_merge_app_conf(ngx_conf_t *cf, void *parent, void *child)
  222 +{
  223 + ngx_rtmp_enotify_app_conf_t *prev = parent;
  224 + ngx_rtmp_enotify_app_conf_t *conf = child;
  225 + ngx_uint_t n;
  226 +
  227 + for (n = 0; n < NGX_RTMP_ENOTIFY_MAX; ++n) {
  228 + ngx_conf_merge_ptr_value(conf->event[n], prev->event[n], NULL);
  229 + if (conf->event[n]) {
  230 + conf->active = 1;
  231 + }
  232 + }
  233 +
  234 + if (conf->active) {
  235 + prev->active = 1;
  236 + }
  237 +
  238 + return NGX_CONF_OK;
  239 +}
  240 +
  241 +
  242 +static ngx_int_t
  243 +ngx_rtmp_enotify_exec(ngx_rtmp_session_t *s, ngx_rtmp_enotify_conf_t *ec)
  244 +{
  245 +#ifndef NGX_WIN32
  246 + int pid;
  247 + ngx_str_t a, *arg;
  248 + char **args;
  249 + ngx_uint_t n;
  250 +
  251 + pid = fork();
  252 +
  253 + switch (pid) {
  254 + case -1:
  255 + ngx_log_error(NGX_LOG_INFO, s->connection->log, ngx_errno,
  256 + "enotify: fork failed");
  257 + return NGX_ERROR;
  258 +
  259 + case 0:
  260 + /* child */
  261 + args = ngx_palloc(s->connection->pool,
  262 + (ec->args.nelts + 2) * sizeof(char *));
  263 + if (args == NULL) {
  264 + exit(1);
  265 + }
  266 + arg = ec->args.elts;
  267 + args[0] = (char *)ec->cmd.data;
  268 + for (n = 0; n < ec->args.nelts; ++n, ++arg) {
  269 + ngx_rtmp_eval(s, arg, ngx_rtmp_enotify_eval_p, &a);
  270 + args[n + 1] = (char *) a.data;
  271 + }
  272 + args[n + 1] = NULL;
  273 + if (execvp((char *)ec->cmd.data, args) == -1) {
  274 + exit(1);
  275 + }
  276 + break;
  277 +
  278 + default:
  279 + /* parent */
  280 + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
  281 + "enotify: child '%V' started pid=%ui",
  282 + &ec->cmd, (ngx_uint_t)pid);
  283 + break;
  284 + }
  285 +#endif /* NGX_WIN32 */
  286 +
  287 + return NGX_OK;
  288 +}
  289 +
  290 +
  291 +static void
  292 +ngx_rtmp_enotify_init(ngx_rtmp_session_t *s,
  293 + u_char name[NGX_RTMP_MAX_NAME], u_char args[NGX_RTMP_MAX_ARGS],
  294 + ngx_uint_t flags)
  295 +{
  296 + ngx_rtmp_enotify_ctx_t *ctx;
  297 + ngx_rtmp_enotify_app_conf_t *enacf;
  298 +
  299 + enacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_enotify_module);
  300 +
  301 + if (!enacf->active) {
  302 + return;
  303 + }
  304 +
  305 + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_enotify_module);
  306 +
  307 + if (ctx == NULL) {
  308 + ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_rtmp_enotify_ctx_t));
  309 + if (ctx == NULL) {
  310 + return;
  311 + }
  312 +
  313 + ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_enotify_module);
  314 + }
  315 +
  316 + ngx_memcpy(ctx->name, name, NGX_RTMP_MAX_NAME);
  317 + ngx_memcpy(ctx->args, args, NGX_RTMP_MAX_ARGS);
  318 +
  319 + ctx->flags |= flags;
  320 +}
  321 +
  322 +
  323 +static ngx_int_t
  324 +ngx_rtmp_enotify_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v)
  325 +{
  326 + ngx_rtmp_enotify_app_conf_t *enacf;
  327 + ngx_rtmp_enotify_conf_t *ec;
  328 +
  329 + if (s->auto_pushed) {
  330 + goto next;
  331 + }
  332 +
  333 + enacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_enotify_module);
  334 +
  335 + if (enacf == NULL) {
  336 + goto next;
  337 + }
  338 +
  339 + ngx_rtmp_enotify_init(s, v->name, v->args, NGX_RTMP_ENOTIFY_PUBLISHING);
  340 +
  341 + ec = enacf->event[NGX_RTMP_ENOTIFY_PUBLISH];
  342 +
  343 + if (ec == NULL) {
  344 + goto next;
  345 + }
  346 +
  347 + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
  348 + "enotify: publish '%V'", &ec->cmd);
  349 +
  350 + ngx_rtmp_enotify_exec(s, ec);
  351 +
  352 +next:
  353 + return next_publish(s, v);
  354 +}
  355 +
  356 +
  357 +static ngx_int_t
  358 +ngx_rtmp_enotify_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v)
  359 +{
  360 + ngx_rtmp_enotify_app_conf_t *enacf;
  361 + ngx_rtmp_enotify_conf_t *ec;
  362 +
  363 + if (s->auto_pushed) {
  364 + goto next;
  365 + }
  366 +
  367 + enacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_enotify_module);
  368 +
  369 + if (enacf == NULL) {
  370 + goto next;
  371 + }
  372 +
  373 + ngx_rtmp_enotify_init(s, v->name, v->args, NGX_RTMP_ENOTIFY_PLAYING);
  374 +
  375 + ec = enacf->event[NGX_RTMP_ENOTIFY_PLAY];
  376 +
  377 + if (ec == NULL) {
  378 + goto next;
  379 + }
  380 +
  381 + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
  382 + "enotify: play '%V'", &ec->cmd);
  383 +
  384 + ngx_rtmp_enotify_exec(s, ec);
  385 +
  386 +next:
  387 + return next_play(s, v);
  388 +}
  389 +
  390 +
  391 +static ngx_int_t
  392 +ngx_rtmp_enotify_delete_stream(ngx_rtmp_session_t *s, ngx_rtmp_delete_stream_t
  393 + *v)
  394 +{
  395 + ngx_rtmp_enotify_ctx_t *ctx;
  396 + ngx_rtmp_enotify_app_conf_t *enacf;
  397 + ngx_rtmp_enotify_conf_t *ec;
  398 +
  399 + if (s->auto_pushed) {
  400 + goto next;
  401 + }
  402 +
  403 + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_enotify_module);
  404 +
  405 + if (ctx == NULL) {
  406 + goto next;
  407 + }
  408 +
  409 + enacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_enotify_module);
  410 +
  411 + if (enacf == NULL) {
  412 + goto next;
  413 + }
  414 +
  415 + if (enacf->event[NGX_RTMP_ENOTIFY_PUBLISH_DONE] &&
  416 + (ctx->flags & NGX_RTMP_ENOTIFY_PUBLISHING))
  417 + {
  418 + ec = enacf->event[NGX_RTMP_ENOTIFY_PUBLISH_DONE];
  419 +
  420 + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
  421 + "enotify: publish_done '%V'", &ec->cmd);
  422 +
  423 + ngx_rtmp_enotify_exec(s, ec);
  424 + }
  425 +
  426 + if (enacf->event[NGX_RTMP_ENOTIFY_PLAY_DONE] &&
  427 + (ctx->flags & NGX_RTMP_ENOTIFY_PLAYING))
  428 + {
  429 + ec = enacf->event[NGX_RTMP_ENOTIFY_PLAY_DONE];
  430 +
  431 + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
  432 + "enotify: play_done '%V'", &ec->cmd);
  433 +
  434 + ngx_rtmp_enotify_exec(s, ec);
  435 + }
  436 +
  437 + ctx->flags = 0;
  438 +
  439 +next:
  440 + return next_delete_stream(s, v);
  441 +}
  442 +
  443 +
  444 +static ngx_int_t
  445 +ngx_rtmp_enotify_record_done(ngx_rtmp_session_t *s, ngx_rtmp_record_done_t *v)
  446 +{
  447 + ngx_rtmp_enotify_app_conf_t *enacf;
  448 + ngx_rtmp_enotify_conf_t *ec;
  449 + ngx_rtmp_enotify_ctx_t *ctx;
  450 +
  451 + if (s->auto_pushed) {
  452 + goto next;
  453 + }
  454 +
  455 + enacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_enotify_module);
  456 + if (enacf == NULL || enacf->event[NGX_RTMP_ENOTIFY_RECORD_DONE] == NULL) {
  457 + goto next;
  458 + }
  459 +
  460 + ec = enacf->event[NGX_RTMP_ENOTIFY_RECORD_DONE];
  461 +
  462 + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
  463 + "enotify: record_done %V recorder=%V path='%V'",
  464 + &ec->cmd, &v->recorder, &v->path);
  465 +
  466 + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_enotify_module);
  467 + if (ctx == NULL) {
  468 + goto next;
  469 + }
  470 +
  471 + ctx->recorder = v->recorder;
  472 + ctx->path = v->path;
  473 +
  474 + ngx_rtmp_enotify_exec(s, ec);
  475 +
  476 +next:
  477 + return next_record_done(s, v);
  478 +}
  479 +
  480 +
  481 +static char *
  482 +ngx_rtmp_enotify_on_event(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  483 +{
  484 + ngx_rtmp_enotify_app_conf_t *enacf;
  485 + ngx_rtmp_enotify_conf_t *ec;
  486 + ngx_str_t *name, *value, *s;
  487 + size_t nargs;
  488 + ngx_uint_t n;
  489 +
  490 + value = cf->args->elts;
  491 + name = &value[0];
  492 +
  493 + ec = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_enotify_conf_t));
  494 +
  495 + if (ec == NULL) {
  496 + return NGX_CONF_ERROR;
  497 + }
  498 +
  499 + ec->cmd = value[1];
  500 +
  501 + nargs = cf->args->nelts - 2;
  502 +
  503 + if (nargs) {
  504 + if (ngx_array_init(&ec->args, cf->pool, nargs, sizeof(ngx_str_t))
  505 + != NGX_OK)
  506 + {
  507 + return NGX_CONF_ERROR;
  508 + }
  509 +
  510 + s = ngx_array_push_n(&ec->args, nargs);
  511 + for (n = 2; n < cf->args->nelts; ++n, ++s) {
  512 + *s = value[n];
  513 + }
  514 + }
  515 +
  516 + enacf = ngx_rtmp_conf_get_module_app_conf(cf, ngx_rtmp_enotify_module);
  517 +
  518 + n = 0;
  519 +
  520 + switch (name->len) {
  521 + case sizeof("exec_play") - 1:
  522 + n = NGX_RTMP_ENOTIFY_PLAY;
  523 + break;
  524 +
  525 + case sizeof("exec_publish") - 1:
  526 + n = NGX_RTMP_ENOTIFY_PUBLISH;
  527 + break;
  528 +
  529 + case sizeof("exec_play_done") - 1:
  530 + n = NGX_RTMP_ENOTIFY_PLAY_DONE;
  531 + break;
  532 +
  533 + case sizeof("exec_record_done") - 1:
  534 + n = NGX_RTMP_ENOTIFY_RECORD_DONE;
  535 + break;
  536 +
  537 + case sizeof("exec_publish_done") - 1:
  538 + n = NGX_RTMP_ENOTIFY_PUBLISH_DONE;
  539 + break;
  540 + }
  541 +
  542 + enacf->event[n] = ec;
  543 +
  544 + return NGX_CONF_OK;
  545 +}
  546 +
  547 +
  548 +static ngx_int_t
  549 +ngx_rtmp_enotify_postconfiguration(ngx_conf_t *cf)
  550 +{
  551 + next_publish = ngx_rtmp_publish;
  552 + ngx_rtmp_publish = ngx_rtmp_enotify_publish;
  553 +
  554 + next_play = ngx_rtmp_play;
  555 + ngx_rtmp_play = ngx_rtmp_enotify_play;
  556 +
  557 + next_delete_stream = ngx_rtmp_delete_stream;
  558 + ngx_rtmp_delete_stream = ngx_rtmp_enotify_delete_stream;
  559 +
  560 + next_record_done = ngx_rtmp_record_done;
  561 + ngx_rtmp_record_done = ngx_rtmp_enotify_record_done;
  562 +
  563 + return NGX_OK;
  564 +}
188 ngx_rtmp_eval.c
... ... @@ -0,0 +1,188 @@
  1 +/*
  2 + * Copyright (c) 2012 Roman Arutyunyan
  3 + */
  4 +
  5 +
  6 +#include "ngx_rtmp_eval.h"
  7 +
  8 +
  9 +#define NGX_RTMP_EVAL_BUFLEN 16
  10 +
  11 +
  12 +static void
  13 +ngx_rtmp_eval_session_str(ngx_rtmp_session_t *s, ngx_rtmp_eval_t *e,
  14 + ngx_str_t *ret)
  15 +{
  16 + *ret = *(ngx_str_t *) ((u_char *) s + e->offset);
  17 +}
  18 +
  19 +
  20 +static void
  21 +ngx_rtmp_eval_connection_str(ngx_rtmp_session_t *s, ngx_rtmp_eval_t *e,
  22 + ngx_str_t *ret)
  23 +{
  24 + *ret = *(ngx_str_t *) ((u_char *) s->connection + e->offset);
  25 +}
  26 +
  27 +
  28 +ngx_rtmp_eval_t ngx_rtmp_eval_session[] = {
  29 +
  30 + { ngx_string("app"),
  31 + ngx_rtmp_eval_session_str,
  32 + offsetof(ngx_rtmp_session_t, app) },
  33 +
  34 + { ngx_string("flashver"),
  35 + ngx_rtmp_eval_session_str,
  36 + offsetof(ngx_rtmp_session_t, flashver) },
  37 +
  38 + { ngx_string("swfurl"),
  39 + ngx_rtmp_eval_session_str,
  40 + offsetof(ngx_rtmp_session_t, swf_url) },
  41 +
  42 + { ngx_string("tcurl"),
  43 + ngx_rtmp_eval_session_str,
  44 + offsetof(ngx_rtmp_session_t, tc_url) },
  45 +
  46 + { ngx_string("pageurl"),
  47 + ngx_rtmp_eval_session_str,
  48 + offsetof(ngx_rtmp_session_t, page_url) },
  49 +
  50 + { ngx_string("addr"),
  51 + ngx_rtmp_eval_connection_str,
  52 + offsetof(ngx_connection_t, addr_text) },
  53 +
  54 + ngx_rtmp_null_eval
  55 +};
  56 +
  57 +
  58 +static void
  59 +ngx_rtmp_eval_append(ngx_rtmp_session_t *s, ngx_buf_t *b,
  60 + void *data, size_t len)
  61 +{
  62 + size_t buf_len;
  63 +
  64 + if (b->last + len > b->end) {
  65 + buf_len = 2 * (b->last - b->pos) + len;
  66 +
  67 + b->start = ngx_palloc(s->connection->pool, buf_len);
  68 + if (b->start == NULL) {
  69 + return;
  70 + }
  71 +
  72 + b->last = ngx_cpymem(b->start, b->pos, b->last - b->pos);
  73 + b->pos = b->start;
  74 + b->end = b->start + buf_len;
  75 + }
  76 +
  77 + b->last = ngx_cpymem(b->last, data, len);
  78 +}
  79 +
  80 +
  81 +static void
  82 +ngx_rtmp_eval_append_var(ngx_rtmp_session_t *s, ngx_buf_t *b,
  83 + ngx_rtmp_eval_t **e, ngx_str_t *name)
  84 +{
  85 + ngx_uint_t k;
  86 + ngx_str_t v;
  87 + ngx_rtmp_eval_t *ee;
  88 +
  89 + for (; *e; ++e) {
  90 + for (k = 0, ee = *e; ee->handler; ++k, ++ee) {
  91 + if (ee->name.len == name->len &&
  92 + ngx_memcmp(ee->name.data, name->data, name->len) == 0)
  93 + {
  94 + ee->handler(s, ee, &v);
  95 + ngx_rtmp_eval_append(s, b, v.data, v.len);
  96 + }
  97 + }
  98 + }
  99 +}
  100 +
  101 +
  102 +ngx_int_t
  103 +ngx_rtmp_eval(ngx_rtmp_session_t *s, ngx_str_t *in, ngx_rtmp_eval_t **e,
  104 + ngx_str_t *out)
  105 +{
  106 + u_char c, *p;;
  107 + ngx_str_t name;
  108 + ngx_buf_t b;
  109 + ngx_uint_t n;
  110 +
  111 + enum {
  112 + NORMAL,
  113 + ESCAPE,
  114 + NAME,
  115 + SNAME
  116 + } state = NORMAL;
  117 +
  118 + b.pos = b.last = b.start = ngx_palloc(s->connection->pool,
  119 + NGX_RTMP_EVAL_BUFLEN);
  120 + if (b.pos == NULL) {
  121 + return NGX_ERROR;
  122 + }
  123 +
  124 + b.end = b.pos + NGX_RTMP_EVAL_BUFLEN;
  125 +
  126 + for (n = 0; n < in->len; ++n) {
  127 + p = &in->data[n];
  128 + c = *p;
  129 +
  130 + switch (state) {
  131 + case SNAME:
  132 + if (c != '}') {
  133 + continue;
  134 + }
  135 +
  136 + name.len = p - name.data;
  137 + ngx_rtmp_eval_append_var(s, &b, e, &name);
  138 +
  139 + state = NORMAL;
  140 +
  141 + continue;
  142 +
  143 + case NAME:
  144 + if (c == '{' && name.data == p) {
  145 + ++name.data;
  146 + state = SNAME;
  147 + continue;
  148 + }
  149 + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
  150 + continue;
  151 + }
  152 +
  153 + name.len = p - name.data;
  154 + ngx_rtmp_eval_append_var(s, &b, e, &name);
  155 +
  156 + case NORMAL:
  157 + switch (c) {
  158 + case '$':
  159 + name.data = p + 1;
  160 + state = NAME;
  161 + continue;
  162 + case '\\':
  163 + state = ESCAPE;
  164 + continue;
  165 + }
  166 +
  167 + case ESCAPE:
  168 + ngx_rtmp_eval_append(s, &b, &c, 1);
  169 + state = NORMAL;
  170 + break;
  171 +
  172 + }
  173 + }
  174 +
  175 + if (state == NAME) {
  176 + p = &in->data[n];
  177 + name.len = p - name.data;
  178 + ngx_rtmp_eval_append_var(s, &b, e, &name);
  179 + }
  180 +
  181 + c = 0;
  182 + ngx_rtmp_eval_append(s, &b, &c, 1);
  183 +
  184 + out->data = b.pos;
  185 + out->len = b.last - b.pos - 1;
  186 +
  187 + return NGX_OK;
  188 +}
37 ngx_rtmp_eval.h
... ... @@ -0,0 +1,37 @@
  1 +/*
  2 + * Copyright (c) 2012 Roman Arutyunyan
  3 + */
  4 +
  5 +
  6 +#ifndef _NGX_RTMP_EVAL_H_INCLUDED_
  7 +#define _NGX_RTMP_EVAL_H_INCLUDED_
  8 +
  9 +#include "ngx_rtmp.h"
  10 +
  11 +
  12 +typedef struct ngx_rtmp_eval_s ngx_rtmp_eval_t;
  13 +
  14 +
  15 +typedef void (* ngx_rtmp_eval_pt)(ngx_rtmp_session_t *s, ngx_rtmp_eval_t *e,
  16 + ngx_str_t *ret);
  17 +
  18 +
  19 +struct ngx_rtmp_eval_s {
  20 + ngx_str_t name;
  21 + ngx_rtmp_eval_pt handler;
  22 + ngx_uint_t offset;
  23 +};
  24 +
  25 +
  26 +#define ngx_rtmp_null_eval { ngx_null_string, NULL, 0 }
  27 +
  28 +
  29 +/* standard session eval variables */
  30 +extern ngx_rtmp_eval_t ngx_rtmp_eval_session[];
  31 +
  32 +
  33 +ngx_int_t ngx_rtmp_eval(ngx_rtmp_session_t *s, ngx_str_t *in,
  34 + ngx_rtmp_eval_t **e, ngx_str_t *out);
  35 +
  36 +
  37 +#endif /* _NGX_RTMP_EVAL_H_INCLUDED_ */
115 ngx_rtmp_exec_module.c
@@ -4,10 +4,8 @@
4 4
5 5
6 6 #include "ngx_rtmp_cmd_module.h"
  7 +#include "ngx_rtmp_eval.h"
7 8 #include <stdlib.h>
8   -#ifdef HAVE_MALLOC_H
9   -#include <malloc.h>
10   -#endif
11 9
12 10 #ifdef NGX_LINUX
13 11 #include <unistd.h>
@@ -121,6 +119,40 @@ ngx_module_t ngx_rtmp_exec_module = {
121 119 };
122 120
123 121
  122 +static void
  123 +ngx_rtmp_exec_eval_astr(ngx_rtmp_session_t *s, ngx_rtmp_eval_t *e,
  124 + ngx_str_t *ret)
  125 +{
  126 + ngx_rtmp_exec_ctx_t *ctx;
  127 +
  128 + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_exec_module);
  129 + if (ctx == NULL) {
  130 + ret->len = 0;
  131 + return;
  132 + }
  133 +
  134 + ret->data = (u_char *) ctx + e->offset;
  135 + ret->len = ngx_strlen(ret->data);
  136 +}
  137 +
  138 +
  139 +static ngx_rtmp_eval_t ngx_rtmp_exec_eval[] = {
  140 +
  141 + { ngx_string("name"),
  142 + ngx_rtmp_exec_eval_astr,
  143 + offsetof(ngx_rtmp_exec_ctx_t, name) },
  144 +
  145 + ngx_rtmp_null_eval
  146 +};
  147 +
  148 +
  149 +static ngx_rtmp_eval_t * ngx_rtmp_exec_eval_p[] = {
  150 + ngx_rtmp_eval_session,
  151 + ngx_rtmp_exec_eval,
  152 + NULL
  153 +};
  154 +
  155 +
124 156 static void *
125 157 ngx_rtmp_exec_create_app_conf(ngx_conf_t *cf)
126 158 {
@@ -250,73 +282,6 @@ ngx_rtmp_exec_kill(ngx_rtmp_session_t *s, ngx_rtmp_exec_t *e, ngx_int_t term)
250 282 }
251 283
252 284
253   -static void
254   -ngx_rtmp_exec_append(ngx_str_t *result, u_char *data, size_t len)
255   -{
256   - if (len == 0) {
257   - len = ngx_strlen(data);
258   - }
259   -
260   - /* use malloc in child */
261   - if (result->len == 0) {
262   - result->data = malloc(len + 1);
263   - result->len = len;
264   - ngx_memcpy(result->data, data, len);
265   - result->data[len] = 0;
266   - return;
267   - }
268   -
269   - result->data = realloc(result->data, result->len + len + 1);
270   - ngx_memcpy(result->data + result->len, data, len);
271   - result->len += len;
272   - result->data[result->len] = 0;
273   -}
274   -
275   -
276   -static char *
277   -ngx_rtmp_exec_prepare_arg(ngx_rtmp_session_t *s, ngx_str_t *arg)
278   -{
279   - ngx_rtmp_core_app_conf_t *cacf;
280   - ngx_rtmp_exec_ctx_t *ctx;
281   - u_char *p, *pp;
282   - ngx_str_t result;
283   -
284   - cacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_core_module);
285   - ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_exec_module);
286   -
287   - /* substitute $app/${app} & $name/${name} */
288   - ngx_str_set(&result, "");
289   - pp = arg->data;
290   - for ( ;; ) {
291   - p = (u_char *)ngx_strchr(pp, '$');
292   - ngx_rtmp_exec_append(&result, pp, p ? p - pp : 0);
293   - if (p == NULL) {
294   - return (char *)result.data;
295   - }
296   - pp = p + 1;
297   - if (p != arg->data && p[-1] == '\\') {
298   - goto dollar;
299   - }
300   - if (!ngx_strncmp(p + 1, "app", sizeof("app") - 1)
301   - || !ngx_strncmp(p + 1, "{app}", sizeof("{app}") - 1))
302   - {
303   - ngx_rtmp_exec_append(&result, cacf->name.data, cacf->name.len);
304   - pp += (p[1] == '{' ? sizeof("{app}") - 1 : sizeof("app") - 1);
305   - continue;
306   - }
307   - if (!ngx_strncmp(p + 1, "name", sizeof("name") - 1)
308   - || !ngx_strncmp(p + 1, "{name}", sizeof("{name}") - 1))
309   - {
310   - ngx_rtmp_exec_append(&result, ctx->name, 0);
311   - pp += (p[1] == '{' ? sizeof("{name}") - 1 : sizeof("name") - 1);
312   - continue;
313   - }
314   -dollar:
315   - ngx_rtmp_exec_append(&result, (u_char *)"$", 1);
316   - }