diff --git a/.travis.yml b/.travis.yml index 8380572..2eacb18 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,5 +7,5 @@ install: - cd nginx-1.12.2 script: - - ./configure --add-module=../nginx-http-flv-module && make - - ./configure --add-dynamic-module=../nginx-http-flv-module && make + - ./configure --add-module=../nginx-http-flv-module && make -j 8 + - ./configure --add-dynamic-module=../nginx-http-flv-module && make -j 8 diff --git a/AUTHORS b/AUTHORS index 58a763c..2a42e38 100644 --- a/AUTHORS +++ b/AUTHORS @@ -19,3 +19,26 @@ Project author: Contacts: huzilong_007@163.com huzilong@kingsoft.com + + han4235 + Suzhou, China + + Contacts: + https://github.com/han4235 + + plainheart + Zhengzhou, China + + Contacts: + https://github.com/plainheart + + HeyJupiter: + Seattle, US + + Contacts: + https://github.com/HeyJupiter + + Vladimir Vainer + + Contacts: + https://github.com/ferreus diff --git a/README.CN.md b/README.CN.md index a3deb9e..f235b58 100644 --- a/README.CN.md +++ b/README.CN.md @@ -4,18 +4,35 @@ 基于[nginx-rtmp-module](https://github.com/arut/nginx-rtmp-module)的流媒体服务器。 +[English README](https://github.com/winshining/nginx-http-flv-module/blob/master/README.md)。 + +如果您喜欢这个模块,可以通过赞赏来支持我的工作,非常感谢! + +![reward_qrcode_winshining](https://raw.githubusercontent.com/wiki/winshining/nginx-http-flv-module/reward_qrcode_winshining.png) + +### 感谢 + +* Igor Sysoev,[NGINX](http://nginx.org)的作者。 + +* Roman Arutyunyan,[nginx-rtmp-module](https://github.com/arut/nginx-rtmp-module)的作者。 + +* 贡献者,详情见[AUTHORS](https://github.com/winshining/nginx-http-flv-module/blob/master/AUTHORS)。 + # 功能 * [nginx-rtmp-module](https://github.com/arut/nginx-rtmp-module)提供的所有功能。 * nginx-http-flv-module的其他功能与[nginx-rtmp-module](https://github.com/arut/nginx-rtmp-module)的对比: -| 功能 | nginx-http-flv-module | nginx-rtmp-module | 备注 | -| :--------------: | :-------------------: | :---------------: | :--------------------------: | -| HTTP-FLV (播放) | √ | x | 支持HTTPS-FLV和chunked回复 | -| GOP缓存 | √ | x | 仅适用于H.264视频和AAC音频 | -| 虚拟主机 | √ | x | | -| 省略`listen`配置 | √ | x | | +| 功能 | nginx-http-flv-module | nginx-rtmp-module | 备注 | +| :--------------: | :-------------------: | :---------------: | :------------------------------------: | +| HTTP-FLV (播放) | √ | x | 支持HTTPS-FLV和chunked回复 | +| GOP缓存 | √ | x | 仅适用于H.264视频和AAC音频 | +| 虚拟主机 | √ | x | | +| 省略`listen`配置 | √ | 见备注 | 配置中必须有一个`listen` | +| 纯音频支持 | √ | 见备注 | `wait_video`或`wait_key`开启后无法工作 | +| 定时打印访问记录 | √ | x | | +| JSON风格的stat | √ | x | | # 支持的系统 @@ -25,17 +42,21 @@ * [VLC](http://www.videolan.org) (RTMP & HTTP-FLV)/[OBS](https://obsproject.com) (RTMP & HTTP-FLV)/[JW Player](https://www.jwplayer.com) (RTMP)/[flv.js](https://github.com/Bilibili/flv.js) (HTTP-FLV). +## 注意 + +[flv.js](https://github.com/Bilibili/flv.js)只能运行在支持[Media Source Extensions](https://www.w3.org/TR/media-source)的浏览器上。 + # 依赖 * 在类Unix系统上,需要GNU make,用于调用编译器来编译软件。 -* 在类Unix系统上,需要GCC/在Windows上,需要MSVC,用于编译软件。 +* 在类Unix系统上,需要GCC。或者在Windows上,需要MSVC,用于编译软件。 * 在类Unix系统上,需要GDB,用于调试软件(可选)。 -* FFmpeg,用于发布媒体流。 +* [FFmpeg](http://ffmpeg.org)或者[OBS](https://obsproject.com),用于发布媒体流。 -* VLC播放器(推荐),用于播放媒体流。 +* [VLC](http://www.videolan.org)(推荐)或者[flv.js](https://github.com/Bilibili/flv.js)(推荐),用于播放媒体流。 * 如果NGINX要支持正则表达式,需要PCRE库。 @@ -101,6 +122,10 @@ nginx-http-flv-module包含了[nginx-rtmp-module](https://github.com/arut/nginx- http://example.com[:port]/dir?[port=xxx&]app=myapp&stream=mystream +### 注意 + +如果使用[ffplay](http://www.ffmpeg.org/ffplay.html)命令行方式播放流,那么**必须**为上述的url加上引号,否则url中的参数会被丢弃(有些不太智能的shell会把"&"解释为"后台运行")。 + 参数`dir`用于匹配http配置块中的location块(更多详情见下文)。 **HTTP默认端口**为**80**, 如果使用了其他端口,必须指定`:port`。 @@ -161,18 +186,32 @@ nginx-http-flv-module包含了[nginx-rtmp-module](https://github.com/arut/nginx- http://example.com[:port]/dir/streamname.mpd +# 示例图片 + +## RTMP ([JW Player](https://www.jwplayer.com)) & HTTP-FLV ([VLC](http://www.videolan.org)) + +![RTMP & HTTP-FLV](samples/jwplayer_vlc.png) + +## HTTP-FLV ([flv.js](https://github.com/Bilibili/flv.js)) + +![HTTP-FLV](samples/flv.js.png) + +# nginx-http-flv-module的安装包 + +详情见[nginx-http-flv-module-packages](https://github.com/winshining/nginx-http-flv-module-packages)。 + # nginx.conf实例 ## 注意 配置项`rtmp_auto_push`,`rtmp_auto_push_reconnect`和`rtmp_socket_dir`在Windows上不起作用,除了Windows 10 17063以及后续版本之外,因为多进程模式的`relay`需要Unix domain socket的支持,详情请参考[Unix domain socket on Windows 10](https://blogs.msdn.microsoft.com/commandline/2017/12/19/af_unix-comes-to-windows)。 -最好将配置项`worker_processes`设置为1,因为`ngx_rtmp_stat_module`在多进程模式下每次只能获取一个进程的统计数据。如果统计数据不重要,那么可以将它设置为大于1的数字,最好与CPU的核心数保持一致。 +最好将配置项`worker_processes`设置为1,因为`ngx_rtmp_stat_module`和`ngx_rtmp_control_module`在多进程模式下有问题,另外,`vhost`功能在多进程模式下还不能完全正确运行,等待修复。 - worker_processes 4; #运行在Windows上时,设置为1,因为Windows不支持Unix domain socket + worker_processes 1; #运行在Windows上时,设置为1,因为Windows不支持Unix domain socket #worker_processes auto; #1.3.8和1.2.5以及之后的版本 - worker_cpu_affinity 0001 0010 0100 1000; #只能用于FreeBSD和Linux + #worker_cpu_affinity 0001 0010 0100 1000; #只能用于FreeBSD和Linux #worker_cpu_affinity auto; #1.9.10以及之后的版本 error_log logs/error.log error; @@ -180,7 +219,8 @@ nginx-http-flv-module包含了[nginx-rtmp-module](https://github.com/arut/nginx- #如果此模块被编译为动态模块并且要使用与RTMP相关的功 #能时,必须指定下面的配置项并且它必须位于events配置 #项之前,否则NGINX启动时不会加载此模块或者加载失败 - #load_module modules/ngx_rtmp_module.so; + + #load_module modules/ngx_http_flv_live_module.so; events { worker_connections 1024; @@ -239,6 +279,14 @@ nginx-http-flv-module包含了[nginx-rtmp-module](https://github.com/arut/nginx- root /var/www/rtmp; #指定stat.xsl的位置 } + #如果需要JSON风格的stat, 不用指定stat.xsl + #但是需要指定一个新的配置项rtmp_stat_format + + #location /stat { + # rtmp_stat all; + # rtmp_stat_format json; + #} + location /control { rtmp_control all; #rtmp控制模块的配置 } @@ -250,9 +298,13 @@ nginx-http-flv-module包含了[nginx-rtmp-module](https://github.com/arut/nginx- rtmp_socket_dir /tmp; rtmp { - out_queue 4096; - out_cork 8; - max_streams 64; + out_queue 4096; + out_cork 8; + max_streams 128; + timeout 15s; + + log_interval 5s; #log模块在access.log中记录日志的间隔时间,对调试非常有用 + log_size 1m; #log模块用来记录日志的缓冲区大小 server { listen 1935; @@ -296,4 +348,3 @@ nginx-http-flv-module包含了[nginx-rtmp-module](https://github.com/arut/nginx- } } } - diff --git a/README.md b/README.md index 3197bd6..21c437b 100644 --- a/README.md +++ b/README.md @@ -4,18 +4,35 @@ Media streaming server based on [nginx-rtmp-module](https://github.com/arut/nginx-rtmp-module). +[中文说明](https://github.com/winshining/nginx-http-flv-module/blob/master/README.CN.md). + +Donate if you like this module. Many thanks to you! + +Buy Me A Coffee + +### Appreciation + +* Igor Sysoev, the creator of [NGINX](http://nginx.org). + +* Roman Arutyunyan, who created [nginx-rtmp-module](https://github.com/arut/nginx-rtmp-module). + +* Contributors, refer to [AUTHORS](https://github.com/winshining/nginx-http-flv-module/blob/master/AUTHORS) for details. + # Features * All features [nginx-rtmp-module](https://github.com/arut/nginx-rtmp-module) provides. * Other features provided by nginx-http-flv-module vs [nginx-rtmp-module](https://github.com/arut/nginx-rtmp-module): -| Features | nginx-http-flv-module | nginx-rtmp-module | remarks | -| :---------------------: | :-------------------: | :---------------: | :----------------------------------------: | -| HTTP-FLV (subscribe) | √ | x | HTTPS-FLV and chunked response supported | -| GOP cache | √ | x | Only for H.264 video and AAC audio | -| VHOST | √ | x | | -| omit `listen` directive | √ | x | | +| Features | nginx-http-flv-module | nginx-rtmp-module | Remarks | +| :---------------------: | :-------------------: | :---------------: | :---------------------------------------------: | +| HTTP-FLV (subscribe) | √ | x | HTTPS-FLV and chunked response supported | +| GOP cache | √ | x | Only for H.264 video and AAC audio | +| VHOST | √ | x | | +| Omit `listen` directive | √ | See remarks | There MUST be at least one `listen` directive | +| Audio-only support | √ | See remarks | Won't work if `wait_video` or `wait_key` is on | +| Timing log for access | √ | x | | +| JSON style stat | √ | x | | # Systems supported @@ -25,17 +42,21 @@ Media streaming server based on [nginx-rtmp-module](https://github.com/arut/ngin * [VLC](http://www.videolan.org) (RTMP & HTTP-FLV)/[OBS](https://obsproject.com) (RTMP & HTTP-FLV)/[JW Player](https://www.jwplayer.com) (RTMP)/[flv.js](https://github.com/Bilibili/flv.js) (HTTP-FLV). +## Note + +[flv.js](https://github.com/Bilibili/flv.js) can only run with browsers that support [Media Source Extensions](https://www.w3.org/TR/media-source). + # Prerequisites * GNU make for activating compiler on Unix-like systems to compile software. -* GCC for compiling on Unix-like systems/MSVC for compiling on Windows. +* GCC for compilation on Unix-like systems or MSVC for compilation on Windows. -* GDB for debuging on Unix-like systems. +* GDB for debug on Unix-like systems. -* FFmpeg for publishing media streams. +* [FFmpeg](http://ffmpeg.org) or [OBS](https://obsproject.com) for publishing media streams. -* VLC player (recommended) for playing media streams. +* [VLC](http://www.videolan.org) (recommended) or [flv.js](https://github.com/Bilibili/flv.js) (recommended) for playing media streams. * PCRE for NGINX if regular expressions needed. @@ -51,7 +72,7 @@ nginx-http-flv-module has all features that [nginx-rtmp-module](https://github.c ## On Windows -Build steps please refer to [Building nginx on the Win32 platform with Visual C](http://nginx.org/en/docs/howto_build_on_win32.html), and don't forget to add `--add-module=/path/to/nginx-http-flv-module` in `Run configure script` step. +For details of build steps, please refer to [Building nginx on the Win32 platform with Visual C](http://nginx.org/en/docs/howto_build_on_win32.html), and don't forget to add `--add-module=/path/to/nginx-http-flv-module` in `Run configure script` step. ## On Unix-like systems @@ -81,7 +102,7 @@ If the module is compiled as a dynamic module, the [NGINX](http://nginx.org) ver # Usage -For details about usages of [nginx-rtmp-module](https://github.com/arut/nginx-rtmp-module), please refer to [README.md](https://github.com/arut/nginx-rtmp-module/blob/master/README.md). +For details of usages of [nginx-rtmp-module](https://github.com/arut/nginx-rtmp-module), please refer to [README.md](https://github.com/arut/nginx-rtmp-module/blob/master/README.md). ## Publish @@ -101,6 +122,10 @@ The **default port for RTMP** is **1935**, if some other ports were used, `:port http://example.com[:port]/dir?[port=xxx&]app=myapp&stream=mystream +### Note + +If [ffplay](http://www.ffmpeg.org/ffplay.html) is used in command line to play the stream, the url above **MUST** be enclosed by quotation marks, or arguments in url will be discarded (some shells not so smart will interpret "&" as "run in background"). + The `dir` is used to match location blocks in http block (see below for details). The **default port for HTTP** is **80**, if some other ports were used, `:port` must be specified. @@ -141,7 +166,7 @@ And `listen` directive specified in `rtmp` block is: } } -Then the url of play based on HTTP is: +Then the url of playback based on HTTP is: http://example.com:8080/live?port=1985&app=myapp&stream=mystream @@ -161,18 +186,32 @@ Since some players don't support HTTP chunked transmission, it's better to speci http://example.com[:port]/dir/streamname.mpd +# Sample Pictures + +## RTMP ([JW Player](https://www.jwplayer.com)) & HTTP-FLV ([VLC](http://www.videolan.org)) + +![RTMP & HTTP-FLV](samples/jwplayer_vlc.png) + +## HTTP-FLV ([flv.js](https://github.com/Bilibili/flv.js)) + +![HTTP-FLV](samples/flv.js.png) + +# Packages for nginx-http-flv-module + +Please refer to [nginx-http-flv-module-packages](https://github.com/winshining/nginx-http-flv-module-packages). + # Example nginx.conf ## Note The directives `rtmp_auto_push`, `rtmp_auto_push_reconnect` and `rtmp_socket_dir` will not function on Windows except on Windows 10 17063 and later versions, because `relay` in multiple processes mode needs help of Unix domain socket, please refer to [Unix domain socket on Windows 10](https://blogs.msdn.microsoft.com/commandline/2017/12/19/af_unix-comes-to-windows) for details. -The directive `worker_processes` of value 1 is preferable to other values, because `ngx_rtmp_stat_module` can only get the statistics of one process at a time in multi-processes mode. If the statistics is unimportant, it can be set as number greater than 1, it is better to set it as the number of CPU cores. +The directive `worker_processes` of value 1 is preferable to other values, because there are something wrong with `ngx_rtmp_stat_module` and `ngx_rtmp_control_module` in multi-processes mode, in addtion, `vhost` feature is not perfect in multi-processes mode yet, wating to be fixed. - worker_processes 4; #should be 1 for Windows, for it doesn't support Unix domain socket + worker_processes 1; #should be 1 for Windows, for it doesn't support Unix domain socket #worker_processes auto; #from versions 1.3.8 and 1.2.5 - worker_cpu_affinity 0001 0010 0100 1000; #only available on FreeBSD and Linux + #worker_cpu_affinity 0001 0010 0100 1000; #only available on FreeBSD and Linux #worker_cpu_affinity auto; #from version 1.9.10 error_log logs/error.log error; @@ -181,7 +220,8 @@ The directive `worker_processes` of value 1 is preferable to other values, becau #to RTMP are needed, the command below MUST be specified and MUST be #located before events directive, otherwise the module won't be loaded #or will be loaded unsuccessfully when NGINX is started - #load_module modules/ngx_rtmp_module.so; + + #load_module modules/ngx_http_flv_live_module.so; events { worker_connections 1024; @@ -240,6 +280,14 @@ The directive `worker_processes` of value 1 is preferable to other values, becau root /var/www/rtmp; #specify in where stat.xsl located } + #if JSON style stat needed, no need to specify + #stat.xsl but a new directive rtmp_stat_format + + #location /stat { + # rtmp_stat all; + # rtmp_stat_format json; + #} + location /control { rtmp_control all; #configuration of control module of rtmp } @@ -251,9 +299,13 @@ The directive `worker_processes` of value 1 is preferable to other values, becau rtmp_socket_dir /tmp; rtmp { - out_queue 4096; - out_cork 8; - max_streams 64; + out_queue 4096; + out_cork 8; + max_streams 128; + timeout 15s; + + log_interval 5s; #interval used by log module to log in access.log, it is very useful for debug + log_size 1m; #buffer size used by log module to log in access.log server { listen 1935; @@ -297,4 +349,3 @@ The directive `worker_processes` of value 1 is preferable to other values, becau } } } - diff --git a/config b/config index 0d48832..28ca924 100644 --- a/config +++ b/config @@ -1,4 +1,4 @@ -ngx_addon_name="ngx_http_flv_module" +ngx_addon_name="ngx_http_flv_live_module" RTMP_CORE_MODULES=" \ ngx_rtmp_module \ @@ -9,6 +9,7 @@ RTMP_CORE_MODULES=" \ ngx_rtmp_record_module \ ngx_rtmp_gop_cache_module \ ngx_rtmp_live_module \ + ngx_rtmp_flv_live_index_module \ ngx_rtmp_play_module \ ngx_rtmp_flv_module \ ngx_rtmp_mp4_module \ @@ -44,14 +45,12 @@ RTMP_DEPS=" \ $ngx_addon_dir/ngx_rtmp_netcall_module.h \ $ngx_addon_dir/ngx_rtmp_play_module.h \ $ngx_addon_dir/ngx_rtmp_record_module.h \ - $ngx_addon_dir/ngx_rtmp_notify_module.h \ $ngx_addon_dir/ngx_rtmp_gop_cache_module.h \ $ngx_addon_dir/ngx_rtmp_relay_module.h \ $ngx_addon_dir/ngx_rtmp_streams.h \ $ngx_addon_dir/ngx_rtmp_bitop.h \ $ngx_addon_dir/ngx_rtmp_proxy_protocol.h \ $ngx_addon_dir/ngx_rtmp_variables.h \ - $ngx_addon_dir/ngx_rtmp_script.h \ $ngx_addon_dir/hls/ngx_rtmp_mpegts.h \ $ngx_addon_dir/dash/ngx_rtmp_mp4.h \ " @@ -74,6 +73,7 @@ RTMP_CORE_SRCS=" \ $ngx_addon_dir/ngx_rtmp_record_module.c \ $ngx_addon_dir/ngx_rtmp_gop_cache_module.c \ $ngx_addon_dir/ngx_rtmp_live_module.c \ + $ngx_addon_dir/ngx_rtmp_flv_live_index_module.c \ $ngx_addon_dir/ngx_rtmp_play_module.c \ $ngx_addon_dir/ngx_rtmp_flv_module.c \ $ngx_addon_dir/ngx_rtmp_mp4_module.c \ @@ -88,7 +88,6 @@ RTMP_CORE_SRCS=" \ $ngx_addon_dir/ngx_rtmp_bitop.c \ $ngx_addon_dir/ngx_rtmp_proxy_protocol.c \ $ngx_addon_dir/ngx_rtmp_variables.c \ - $ngx_addon_dir/ngx_rtmp_script.c \ $ngx_addon_dir/ngx_rtmp_parse.c \ $ngx_addon_dir/hls/ngx_rtmp_hls_module.c \ $ngx_addon_dir/dash/ngx_rtmp_dash_module.c \ @@ -108,11 +107,21 @@ if [ -f auto/module ] ; then ngx_module_deps=$RTMP_DEPS if [ $ngx_module_link = DYNAMIC ] ; then - ngx_module_name="$RTMP_CORE_MODULES $RTMP_HTTP_MODULES" + ngx_module_name="$ngx_addon_name $RTMP_CORE_MODULES $RTMP_HTTP_MODULES" ngx_module_srcs="$RTMP_CORE_SRCS $RTMP_HTTP_SRCS" . auto/module + dynamic_modules=`eval echo '$'"${ngx_module}_MODULES" | sed -e "s/ \{0,\}$ngx_addon_name//"` + eval ${ngx_module}_MODULES=\"$dynamic_modules\" + unset dynamic_modules + + order_modules=`eval echo '$'"${ngx_module}_ORDER"` + if [ -n "$order_modules" ] + then + eval ${ngx_module}_ORDER=\"`echo "$order_modules" | sed -e "s/ \{0,\}$ngx_addon_name//"`\" + unset order_modules + fi else ngx_module_type=CORE ngx_module_name=$RTMP_CORE_MODULES diff --git a/dash/ngx_rtmp_dash_module.c b/dash/ngx_rtmp_dash_module.c index 4d7e595..4d282fa 100644 --- a/dash/ngx_rtmp_dash_module.c +++ b/dash/ngx_rtmp_dash_module.c @@ -597,12 +597,12 @@ ngx_rtmp_dash_close_fragment(ngx_rtmp_session_t *s, ngx_rtmp_dash_track_t *t) while (left > 0) { n = ngx_read_fd(t->fd, buffer, ngx_min(sizeof(buffer), left)); - if (n == NGX_ERROR) { + if (n == 0 || n == NGX_ERROR) { break; } n = ngx_write_fd(fd, buffer, (size_t) n); - if (n == NGX_ERROR) { + if (n == 0 || n == NGX_ERROR) { break; } diff --git a/hls/ngx_rtmp_hls_module.h b/hls/ngx_rtmp_hls_module.h index c0c52f4..b2e01d6 100644 --- a/hls/ngx_rtmp_hls_module.h +++ b/hls/ngx_rtmp_hls_module.h @@ -1,6 +1,6 @@ /* - * Copyright (C) Winshining + * Copyright (C) Winshining */ diff --git a/ngx_http_flv_live_module.c b/ngx_http_flv_live_module.c index 3a8cc09..23479b3 100644 --- a/ngx_http_flv_live_module.c +++ b/ngx_http_flv_live_module.c @@ -7,10 +7,7 @@ #include #include #include "ngx_http_flv_live_module.h" -#include "ngx_rtmp_relay_module.h" -#include "ngx_rtmp_notify_module.h" #include "ngx_rtmp_bandwidth.h" -#include "ngx_rtmp_gop_cache_module.h" static ngx_rtmp_play_pt next_play; @@ -20,7 +17,7 @@ static ngx_rtmp_close_stream_pt next_close_stream; static ngx_int_t ngx_http_flv_live_init(ngx_conf_t *cf); static void *ngx_http_flv_live_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_flv_live_merge_loc_conf(ngx_conf_t *cf, - void *parent, void *child); + void *parent, void *child); static ngx_int_t ngx_http_flv_live_handler(ngx_http_request_t *r); @@ -28,16 +25,29 @@ static void ngx_http_flv_live_cleanup(void *data); static ngx_int_t ngx_http_flv_live_init_process(ngx_cycle_t *cycle); static void ngx_http_flv_live_send_tail(ngx_rtmp_session_t *s); +static ngx_int_t ngx_http_flv_live_send_message(ngx_rtmp_session_t *s, + ngx_chain_t *out, ngx_uint_t priority); static ngx_chain_t *ngx_http_flv_live_meta_message(ngx_rtmp_session_t *, - ngx_chain_t *in); + ngx_chain_t *in); static ngx_chain_t *ngx_http_flv_live_append_message(ngx_rtmp_session_t *s, - ngx_rtmp_header_t *h, ngx_rtmp_header_t *lh, ngx_chain_t *in); + ngx_rtmp_header_t *h, ngx_rtmp_header_t *lh, ngx_chain_t *in); static void ngx_http_flv_live_free_message(ngx_rtmp_session_t *s, - ngx_chain_t *in); + ngx_chain_t *in); +static ngx_int_t ngx_http_flv_live_join(ngx_rtmp_session_t *s, u_char *name, + unsigned int publisher); +static ngx_chain_t *ngx_http_flv_live_append_shared_bufs( + ngx_rtmp_core_srv_conf_t *cscf, ngx_rtmp_header_t *h, ngx_chain_t *in, + ngx_flag_t chunked); + static void ngx_http_flv_live_close_http_request(ngx_rtmp_session_t *s); static ngx_int_t ngx_http_flv_live_headers_filter(ngx_rtmp_session_t *s); static ngx_int_t ngx_http_flv_live_header_filter(ngx_rtmp_session_t *s); +#if (nginx_version <= 1003014) +static void ngx_http_do_free_request(ngx_http_request_t *r, ngx_int_t rc); +static void ngx_http_do_log_request(ngx_http_request_t *r); +#endif + typedef struct ngx_http_header_val_s ngx_http_header_val_t; @@ -57,7 +67,9 @@ struct ngx_http_header_val_s { ngx_str_t key; ngx_http_set_header_pt handler; ngx_uint_t offset; +#if (nginx_version >= 1007005) ngx_uint_t always; /* unsigned always:1 */ +#endif }; @@ -69,7 +81,9 @@ typedef enum { typedef struct { ngx_http_expires_t expires; time_t expires_time; +#if (nginx_version >= 1007009) ngx_http_complex_value_t *expires_value; +#endif ngx_array_t *headers; } ngx_http_headers_conf_t; @@ -182,28 +196,23 @@ static ngx_int_t ngx_http_flv_live_init_handlers(ngx_cycle_t *cycle); static ngx_int_t ngx_http_flv_live_request(ngx_rtmp_session_t *s, - ngx_rtmp_header_t *h, ngx_chain_t *in); + ngx_rtmp_header_t *h, ngx_chain_t *in); -static ngx_int_t ngx_http_flv_live_play(ngx_rtmp_session_t *s, - ngx_rtmp_play_t *v); -static ngx_int_t ngx_http_flv_live_close_stream(ngx_rtmp_session_t *s, - ngx_rtmp_close_stream_t *v); static void ngx_http_flv_live_free_request(ngx_rtmp_session_t *s); -static void ngx_http_flv_live_play_handler(ngx_event_t *ev); static void ngx_http_flv_live_read_handler(ngx_event_t *rev); static void ngx_http_flv_live_write_handler(ngx_event_t *wev); static ngx_int_t ngx_http_flv_live_preprocess(ngx_http_request_t *r, - ngx_rtmp_connection_t *rconn); + ngx_rtmp_connection_t *rconn); static ngx_rtmp_session_t *ngx_http_flv_live_init_connection( - ngx_http_request_t *r, ngx_rtmp_connection_t *rconn); + ngx_http_request_t *r, ngx_rtmp_connection_t *rconn); static ngx_rtmp_session_t *ngx_http_flv_live_init_session( - ngx_http_request_t *r, ngx_rtmp_addr_conf_t *add_conf); + ngx_http_request_t *r, ngx_rtmp_addr_conf_t *add_conf); static ngx_int_t ngx_http_flv_live_connect_init(ngx_rtmp_session_t *s, - ngx_str_t *app, ngx_str_t *stream); + ngx_str_t *app, ngx_str_t *stream); static ngx_http_module_t ngx_http_flv_live_module_ctx = { @@ -226,13 +235,6 @@ static ngx_command_t ngx_http_flv_live_commands[] = { offsetof(ngx_http_flv_live_conf_t, flv_live), NULL }, - { ngx_string("poll_interval"), - NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_msec_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_flv_live_conf_t, poll_interval), - NULL }, - ngx_null_command }; @@ -253,7 +255,7 @@ ngx_module_t ngx_http_flv_live_module = { }; -ngx_int_t +static ngx_int_t ngx_http_flv_live_init(ngx_conf_t *cf) { ngx_http_handler_pt *h; @@ -273,7 +275,7 @@ ngx_http_flv_live_init(ngx_conf_t *cf) } -void * +static void * ngx_http_flv_live_create_loc_conf(ngx_conf_t *cf) { ngx_http_flv_live_conf_t *conf; @@ -284,13 +286,12 @@ ngx_http_flv_live_create_loc_conf(ngx_conf_t *cf) } conf->flv_live = NGX_CONF_UNSET; - conf->poll_interval = NGX_CONF_UNSET_MSEC; return (void *) conf; } -char * +static char * ngx_http_flv_live_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) { @@ -298,16 +299,6 @@ ngx_http_flv_live_merge_loc_conf(ngx_conf_t *cf, ngx_http_flv_live_conf_t *conf = child; ngx_conf_merge_value(conf->flv_live, prev->flv_live, 0); - ngx_conf_merge_msec_value(conf->poll_interval, prev->poll_interval, 20); - - if (conf->poll_interval == 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid value \"%ui\" in \"poll_interval\" directive, " - "it must be greater than 0", - conf->poll_interval); - - return NGX_CONF_ERROR; - } return NGX_CONF_OK; } @@ -328,17 +319,17 @@ ngx_http_flv_live_init_handlers(ngx_cycle_t *cycle) h = ngx_array_push(&cmcf->events[NGX_HTTP_FLV_LIVE_REQUEST]); *h = ngx_http_flv_live_request; - next_play = ngx_rtmp_play; - ngx_rtmp_play = ngx_http_flv_live_play; + next_play = http_flv_live_next_play; + next_close_stream = http_flv_live_next_close_stream; - next_close_stream = ngx_rtmp_close_stream; - ngx_rtmp_close_stream = ngx_http_flv_live_close_stream; + http_flv_live_next_play = NULL; + http_flv_live_next_close_stream = NULL; return NGX_OK; } -ngx_int_t +static ngx_int_t ngx_http_flv_live_init_process(ngx_cycle_t *cycle) { return ngx_http_flv_live_init_handlers(cycle); @@ -512,7 +503,7 @@ ngx_http_flv_live_send_header(ngx_rtmp_session_t *s) /** * for adding non-standard HTTP headers **/ -ngx_int_t +static ngx_int_t ngx_http_flv_live_headers_filter(ngx_rtmp_session_t *s) { ngx_str_t value; @@ -554,9 +545,11 @@ ngx_http_flv_live_headers_filter(ngx_rtmp_session_t *s) h = conf->headers->elts; for (i = 0; i < conf->headers->nelts; i++) { +#if (nginx_version >= 1007005) if (!safe_status && !h[i].always) { continue; } +#endif if (ngx_http_complex_value(r, &h[i].value, &value) != NGX_OK) { return NGX_ERROR; @@ -572,7 +565,7 @@ ngx_http_flv_live_headers_filter(ngx_rtmp_session_t *s) } -ngx_int_t +static ngx_int_t ngx_http_flv_live_header_filter(ngx_rtmp_session_t *s) { u_char *p; @@ -884,7 +877,8 @@ ngx_http_flv_live_header_filter(ngx_rtmp_session_t *s) "%*s", (size_t) (b->last - b->pos), b->pos); /* the end of HTTP header */ - *b->last++ = CR; *b->last++ = LF; + *b->last++ = CR; + *b->last++ = LF; r->header_size = b->last - b->pos; @@ -905,7 +899,7 @@ ngx_http_flv_live_header_filter(ngx_rtmp_session_t *s) } -void +static void ngx_http_flv_live_send_tail(ngx_rtmp_session_t *s) { ngx_rtmp_core_srv_conf_t *cscf; @@ -930,13 +924,13 @@ ngx_http_flv_live_send_tail(ngx_rtmp_session_t *s) } -ngx_int_t +static ngx_int_t ngx_http_flv_live_send_message(ngx_rtmp_session_t *s, - ngx_chain_t *out, ngx_uint_t priority) + ngx_chain_t *out, ngx_uint_t priority) { ngx_uint_t nmsg; - nmsg = (s->out_last - s->out_pos) % s->out_queue + 1; + nmsg = (s->out_last + s->out_queue - s->out_pos) % s->out_queue + 1; if (priority > 3) { priority = 3; @@ -946,13 +940,9 @@ ngx_http_flv_live_send_message(ngx_rtmp_session_t *s, * Note we always leave 1 slot free */ if (nmsg + priority * s->out_queue / 4 >= s->out_queue) { ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "flv live: HTTP drop message bufs='%ui', priority='%ui'", + "flv live: HTTP drop message bufs=%ui, priority=%ui", nmsg, priority); - if (s->gop_cache.out[s->out_last].set) { - ngx_rtmp_gop_cache_exec_handler(s, s->out_last, out); - } - return NGX_AGAIN; } @@ -962,7 +952,7 @@ ngx_http_flv_live_send_message(ngx_rtmp_session_t *s, ngx_rtmp_acquire_shared_chain(out); ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "flv live: HTTP send nmsg='%ui', priority='%ui' '#%ui'", + "flv live: HTTP send nmsg=%ui, priority=%ui #%ui", nmsg, priority, s->out_last); if (priority && s->out_buffer && nmsg < s->out_cork) { @@ -977,24 +967,30 @@ ngx_http_flv_live_send_message(ngx_rtmp_session_t *s, } -ngx_int_t +static ngx_int_t ngx_http_flv_live_request(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, - ngx_chain_t *in) + ngx_chain_t *in) { static ngx_rtmp_play_t v; + ngx_int_t rc; ngx_http_request_t *r; ngx_http_flv_live_ctx_t *ctx; r = s->data; ctx = ngx_http_get_module_ctx(r, ngx_http_flv_live_module); - if (ngx_http_flv_live_connect_init(s, &ctx->app, &ctx->stream) != NGX_OK) - { - s->wait_notify_connect = 0; + rc = ngx_http_flv_live_connect_init(s, &ctx->app, &ctx->stream); + if (rc != NGX_OK) { return NGX_ERROR; } + if (s->notify_connect) { + r->main->count++; + + return NGX_OK; + } + ngx_memzero(&v, sizeof(ngx_rtmp_play_t)); ngx_memcpy(v.name, ctx->stream.data, ngx_min(ctx->stream.len, @@ -1003,26 +999,18 @@ ngx_http_flv_live_request(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, sizeof(v.args) - 1)); ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, - "flv live: name='%s' args='%s' start='%i' duration='%i' " - "reset='%i' silent='%i'", + "flv live: name='%s' args='%s' start=%i duration=%i " + "reset=%i silent=%i", v.name, v.args, (ngx_int_t) v.start, (ngx_int_t) v.duration, (ngx_int_t) v.reset, (ngx_int_t) v.silent); - if (s->wait_notify_connect) { - ngx_memzero(&ctx->play, sizeof(ngx_event_t)); - ctx->play.handler = ngx_http_flv_live_play_handler; - ctx->play.log = s->connection->log; - ctx->play.data = s->connection; - + rc = ngx_rtmp_play(s, &v); + if (rc == NGX_OK && s->notify_play) { r->main->count++; - - ngx_http_flv_live_play_handler(&ctx->play); - - return NGX_OK; } - return ngx_rtmp_play(s, &v); + return rc; } @@ -1064,17 +1052,14 @@ ngx_http_flv_live_set_status(ngx_rtmp_session_t *s, unsigned active) } -ngx_int_t +static ngx_int_t ngx_http_flv_live_join(ngx_rtmp_session_t *s, u_char *name, - unsigned int publisher) + unsigned int publisher) { ngx_rtmp_live_ctx_t *ctx; ngx_rtmp_live_stream_t **stream; ngx_rtmp_live_app_conf_t *lacf; - ngx_rtmp_relay_app_conf_t *racf; - ngx_flag_t create; - /* only for subscribers */ if (publisher) { return NGX_DECLINED; @@ -1101,52 +1086,21 @@ ngx_http_flv_live_join(ngx_rtmp_session_t *s, u_char *name, ngx_memzero(ctx, sizeof(*ctx)); ctx->session = s; - create = 0; ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "flv live: join '%s'", name); - racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_relay_module); - if (racf && racf->pulls.nelts) { - create = 1; - } - - stream = ngx_rtmp_live_get_stream(s, name, - lacf->idle_streams || s->wait_notify_play || create); + stream = ngx_rtmp_live_get_stream(s, name, lacf->idle_streams); if (stream == NULL || - !(publisher || (*stream)->publishing || lacf->idle_streams || - s->wait_notify_play || create)) + !(publisher || (*stream)->publishing || lacf->idle_streams)) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "flv live: stream not found"); - s->wait_notify_play = 0; return NGX_ERROR; } - if ((*stream)->pub_ctx == NULL || !(*stream)->pub_ctx->publishing) { - ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, - "flv live: stream not publishing, check relay pulls"); - - do { - if (s->wait_notify_play) { - break; - } - - ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, - "flv live: no on_play, check relay pulls"); - - /* check if there are some pulls */ - if (!create) { - ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, - "flv live: no on_play or relay pull, quit"); - - return NGX_ERROR; - } - } while (0); - } - ctx->stream = *stream; ctx->publishing = publisher; ctx->next = (*stream)->ctx; @@ -1177,42 +1131,32 @@ ngx_int_t ngx_http_flv_live_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v) { ngx_rtmp_live_app_conf_t *lacf; - ngx_rtmp_notify_app_conf_t *nacf; ngx_http_request_t *r; - lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_live_module); - if (lacf == NULL || !lacf->live) { + r = s->data; + if (r == NULL) { goto next; } - nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module); - if (!s->relay && nacf && nacf->url[NGX_RTMP_NOTIFY_PLAY]) { - s->wait_notify_play = 1; - } - - r = s->data; - if (r == NULL) { + lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_live_module); + if (lacf == NULL || !lacf->live) { goto next; } r->main->count++; #if (nginx_version >= 1013001) - /** - * when playing from pull, the downstream requests on the most - * of time return before the upstream requests, flv.js always - * sends HTTP header 'Connection: keep-alive', but Nginx has - * deleted r->blocked in ngx_http_finalize_request, that causes - * ngx_http_set_keepalive to run the cleanup handlers to close + /** + * when playing from pull, the downstream requests on the most + * of time return before the upstream requests, flv.js always + * sends HTTP header 'Connection: keep-alive', but Nginx has + * deleted r->blocked in ngx_http_finalize_request, that causes + * ngx_http_set_keepalive to run the cleanup handlers to close * the connection between downstream and server, so play fails **/ r->keepalive = 0; #endif - if (s->wait_notify_play) { - goto next; - } - /* join stream as a subscriber */ if (ngx_http_flv_live_join(s, v->name, 0) == NGX_ERROR) { @@ -1221,16 +1165,8 @@ ngx_http_flv_live_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v) return NGX_ERROR; } - if (ngx_rtmp_process_request_line(s, v->name, v->args, - (const u_char *) "flv live play") != NGX_OK) - { - r->main->count--; - - return NGX_ERROR; - } - ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "flv live play: name='%s' start='%uD' duration='%uD' reset='%d'", + "flv live play: name='%s' start=%uD duration=%uD reset=%d", v->name, (uint32_t) v->start, (uint32_t) v->duration, (uint32_t) v->reset); @@ -1257,7 +1193,7 @@ ngx_http_flv_live_close_http_request(ngx_rtmp_session_t *s) ngx_int_t ngx_http_flv_live_close_stream(ngx_rtmp_session_t *s, - ngx_rtmp_close_stream_t *v) + ngx_rtmp_close_stream_t *v) { ngx_rtmp_live_ctx_t *ctx, **cctx, *unlink; ngx_http_request_t *r; @@ -1337,6 +1273,7 @@ ngx_http_flv_live_close_stream(ngx_rtmp_session_t *s, ctx->stream = NULL; ngx_http_flv_live_free_request(s); + s->connection->destroyed = 1; break; } else { @@ -1345,16 +1282,17 @@ ngx_http_flv_live_close_stream(ngx_rtmp_session_t *s, } } - /** - * close only http requests here, the other - * requests were left for next_clost_stream + /** + * close only http requests here, the other + * requests were left for next_clost_stream **/ next: - if (s->wait_notify_connect || s->wait_notify_play) { + if (s->notify_connect || s->notify_play) { r = s->data; if (r) { ngx_http_flv_live_free_request(s); + s->connection->destroyed = 1; } } @@ -1367,7 +1305,6 @@ ngx_http_flv_live_free_request(ngx_rtmp_session_t *s) { ngx_http_request_t *r; ngx_http_cleanup_t **cln; - ngx_http_flv_live_ctx_t *ctx; r = s->data; if (r) { @@ -1380,12 +1317,11 @@ ngx_http_flv_live_free_request(ngx_rtmp_session_t *s) cln = &(*cln)->next; } - ctx = ngx_http_get_module_ctx(r, ngx_http_flv_live_module); - if (ctx && ctx->play.timer_set) { - ngx_del_timer(&ctx->play); - } - +#if (nginx_version <= 1003014) + ngx_http_do_free_request(r, 0); +#else ngx_http_free_request(r, 0); +#endif #if (NGX_HTTP_SSL) if (r->connection->ssl) { @@ -1399,56 +1335,115 @@ ngx_http_flv_live_free_request(ngx_rtmp_session_t *s) } -void -ngx_http_flv_live_play_handler(ngx_event_t *ev) +#if (nginx_version <= 1003014) +static void +ngx_http_do_free_request(ngx_http_request_t *r, ngx_int_t rc) { - static ngx_rtmp_play_t v; + ngx_log_t *log; + ngx_pool_t *pool; + struct linger linger; + ngx_http_cleanup_t *cln; + ngx_http_log_ctx_t *ctx; + ngx_http_core_loc_conf_t *clcf; - ngx_connection_t *c; - ngx_http_request_t *r; - ngx_rtmp_session_t *s; - ngx_http_flv_live_ctx_t *ctx; - ngx_http_flv_live_conf_t *hfcf; + log = r->connection->log; - c = ev->data; - if (c->destroyed) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http close request"); + + if (r->pool == NULL) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "http request already closed"); return; } - r = c->data; - ctx = ngx_http_get_module_ctx(r, ngx_http_flv_live_module); - s = ctx->s; + cln = r->cleanup; + r->cleanup = NULL; + + while (cln) { + if (cln->handler) { + cln->handler(cln->data); + } - if (ev->timer_set) { - ngx_del_timer(ev); + cln = cln->next; } - if (!s->wait_notify_connect) { - ngx_memzero(&v, sizeof(ngx_rtmp_play_t)); +#if (NGX_STAT_STUB) - ngx_memcpy(v.name, ctx->stream.data, ngx_min(ctx->stream.len, - sizeof(v.name) - 1)); - ngx_memcpy(v.args, s->args.data, ngx_min(s->args.len, - sizeof(v.args) - 1)); + if (r->stat_reading) { + (void) ngx_atomic_fetch_add(ngx_stat_reading, -1); + } - ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, - "flv live: name='%s' args='%s' start='%i' duration='%i' " - "reset='%i' silent='%i'", - v.name, v.args, (ngx_int_t) v.start, - (ngx_int_t) v.duration, (ngx_int_t) v.reset, - (ngx_int_t) v.silent); + if (r->stat_writing) { + (void) ngx_atomic_fetch_add(ngx_stat_writing, -1); + } - r->main->count--; +#endif - ngx_rtmp_play(s, &v); - } else { - hfcf = ngx_http_get_module_loc_conf(r, ngx_http_flv_live_module); - ngx_add_timer(ev, hfcf->poll_interval); + if (rc > 0 && (r->headers_out.status == 0 || r->connection->sent == 0)) { + r->headers_out.status = rc; + } + + log->action = "logging request"; + + ngx_http_do_log_request(r); + + log->action = "closing request"; + + if (r->connection->timedout) { + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (clcf->reset_timedout_connection) { + linger.l_onoff = 1; + linger.l_linger = 0; + + if (setsockopt(r->connection->fd, SOL_SOCKET, SO_LINGER, + (const void *) &linger, sizeof(struct linger)) == -1) + { + ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, + "setsockopt(SO_LINGER) failed"); + } + } } + + /* the various request strings were allocated from r->pool */ + ctx = log->data; + ctx->request = NULL; + + r->request_line.len = 0; + + r->connection->destroyed = 1; + + /* + * Setting r->pool to NULL will increase probability to catch double close + * of request since the request object is allocated from its own pool. + */ + + pool = r->pool; + r->pool = NULL; + + ngx_destroy_pool(pool); } -void +static void +ngx_http_do_log_request(ngx_http_request_t *r) +{ + ngx_uint_t i, n; + ngx_http_handler_pt *log_handler; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); + + log_handler = cmcf->phases[NGX_HTTP_LOG_PHASE].handlers.elts; + n = cmcf->phases[NGX_HTTP_LOG_PHASE].handlers.nelts; + + for (i = 0; i < n; i++) { + log_handler[i](r); + } +} +#endif + + +static void ngx_http_flv_live_read_handler(ngx_event_t *rev) { ngx_connection_t *c; @@ -1459,29 +1454,34 @@ ngx_http_flv_live_read_handler(ngx_event_t *rev) u_char buf[NGX_BUFF_MAX_SIZE]; c = rev->data; - r = c->data; if (c->destroyed) { return; } + r = c->data; ctx = ngx_http_get_module_ctx(r, ngx_http_flv_live_module); s = ctx->s; - n = c->recv(c, buf, sizeof(buf)); + for ( ;; ) { + n = c->recv(c, buf, sizeof(buf)); + + if (n == NGX_AGAIN) { + ngx_add_timer(c->read, s->timeout); - if (n == NGX_AGAIN) { - ngx_add_timer(c->read, s->timeout); + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_rtmp_finalize_session(s); + } - if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + break; + } else if (n == 0 || n == -1) { ngx_rtmp_finalize_session(s); + break; } - } else { - ngx_rtmp_finalize_session(s); } } -void +static void ngx_http_flv_live_write_handler(ngx_event_t *wev) { ngx_connection_t *c; @@ -1492,15 +1492,14 @@ ngx_http_flv_live_write_handler(ngx_event_t *wev) ngx_http_flv_live_ctx_t *ctx; c = wev->data; - r = c->data; - - ctx = ngx_http_get_module_ctx(r, ngx_http_flv_live_module); - s = ctx->s; - if (c->destroyed) { return; } + r = c->data; + ctx = ngx_http_get_module_ctx(r, ngx_http_flv_live_module); + s = ctx->s; + if (wev->timedout) { ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT, "flv live: client timed out"); @@ -1542,14 +1541,8 @@ ngx_http_flv_live_write_handler(ngx_event_t *wev) if (s->out_bpos == s->out_chain->buf->last) { s->out_chain = s->out_chain->next; if (s->out_chain == NULL) { - if (s->gop_cache.out[s->out_pos].set) { - ngx_rtmp_gop_cache_exec_handler(s, s->out_pos, - s->out[s->out_pos]); - } else { - cscf = ngx_rtmp_get_module_srv_conf(s, - ngx_rtmp_core_module); - ngx_rtmp_free_shared_chain(cscf, s->out[s->out_pos]); - } + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + ngx_rtmp_free_shared_chain(cscf, s->out[s->out_pos]); s->out[s->out_pos] = NULL; ++s->out_pos; s->out_pos %= s->out_queue; @@ -1570,7 +1563,7 @@ ngx_http_flv_live_write_handler(ngx_event_t *wev) } -ngx_int_t +static ngx_int_t ngx_http_flv_live_preprocess(ngx_http_request_t *r, ngx_rtmp_connection_t *rconn) { @@ -1601,9 +1594,9 @@ ngx_http_flv_live_preprocess(ngx_http_request_t *r, ctx = ngx_http_get_module_ctx(r, ngx_http_flv_live_module); - /** - * if requested args are escaped, for example, urls in the - * history list of vlc for Android (or all mobile platforms) + /** + * if requested args are escaped, for example, urls in the + * history list of vlc for Android (or all mobile platforms) **/ if (r->args.len == 0 && r->uri.len) { ngx_http_split_args(r, &r->uri, &r->args); @@ -1632,10 +1625,24 @@ ngx_http_flv_live_preprocess(ngx_http_request_t *r, for (n = 0; n < ngx_cycle->listening.nelts; ++n, ++ls) { if (ls->handler == ngx_rtmp_init_connection) { local_sockaddr = r->connection->local_sockaddr; - sa_family = ls->sockaddr->sa_family; + sa_family = local_sockaddr->sa_family; - if (local_sockaddr->sa_family != sa_family) { - continue; + if (sa_family != ls->sockaddr->sa_family) { +#if (NGX_HAVE_INET6) + if (ls->sockaddr->sa_family == AF_INET6) { + if (ls->ipv6only) { +#endif + continue; +#if (NGX_HAVE_INET6) + } else { + if (local_sockaddr->sa_family != AF_INET) { + continue; + } + + sa_family = AF_INET6; + } + } +#endif } switch (sa_family) { @@ -1811,13 +1818,19 @@ ngx_http_flv_live_init_connection(ngx_http_request_t *r, c->write->handler = ngx_http_flv_live_write_handler; c->read->handler = ngx_http_flv_live_read_handler; + if (c->write->active) { + if (ngx_del_event(c->write, NGX_WRITE_EVENT, 0) != NGX_OK) { + return NULL; + } + } + return s; } -ngx_rtmp_session_t * +static ngx_rtmp_session_t * ngx_http_flv_live_init_session(ngx_http_request_t *r, - ngx_rtmp_addr_conf_t *addr_conf) + ngx_rtmp_addr_conf_t *addr_conf) { ngx_rtmp_session_t *s; ngx_rtmp_core_srv_conf_t *cscf; @@ -1829,7 +1842,7 @@ ngx_http_flv_live_init_session(ngx_http_request_t *r, s = ngx_pcalloc(c->pool, sizeof(ngx_rtmp_session_t)); if (s == NULL) { /* let other handlers process */ - return NULL; + goto failed; } s->rtmp_connection = c->data; @@ -1843,7 +1856,7 @@ ngx_http_flv_live_init_session(ngx_http_request_t *r, ctx = ngx_palloc(c->pool, sizeof(ngx_rtmp_error_log_ctx_t)); if (ctx == NULL) { - return NULL; + goto failed; } ctx->client = &c->addr_text; @@ -1858,12 +1871,12 @@ ngx_http_flv_live_init_session(ngx_http_request_t *r, s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_rtmp_max_module); if (s->ctx == NULL) { - return NULL; + goto failed; } s->out_pool = ngx_create_pool(4096, c->log); if (s->out_pool == NULL) { - return NULL; + goto failed; } s->out = ngx_pcalloc(s->out_pool, sizeof(ngx_chain_t *) @@ -1871,21 +1884,12 @@ ngx_http_flv_live_init_session(ngx_http_request_t *r, addr_conf->default_server->ctx->srv_conf [ngx_rtmp_core_module.ctx_index])->out_queue); if (s->out == NULL) { - return NULL; - } - - s->gop_cache.out = ngx_pcalloc(s->out_pool, - sizeof(ngx_rtmp_gop_cache_free_t) - * ((ngx_rtmp_core_srv_conf_t *) - addr_conf->default_server->ctx->srv_conf - [ngx_rtmp_core_module.ctx_index])->out_queue); - if (s->gop_cache.out == NULL) { - return NULL; + goto failed; } s->in_streams_pool = ngx_create_pool(4096, c->log); if (s->in_streams_pool == NULL) { - return NULL; + goto failed; } cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); @@ -1895,7 +1899,7 @@ ngx_http_flv_live_init_session(ngx_http_request_t *r, s->in_streams = ngx_pcalloc(s->in_streams_pool, sizeof(ngx_rtmp_stream_t) * cscf->max_streams); if (s->in_streams == NULL) { - return NULL; + goto failed; } #if (nginx_version >= 1007005) @@ -1905,26 +1909,38 @@ ngx_http_flv_live_init_session(ngx_http_request_t *r, s->epoch = ngx_current_msec; s->timeout = cscf->timeout; s->buflen = cscf->buflen; - s->gop_cache.count = 0; ngx_rtmp_set_chunk_size(s, NGX_RTMP_DEFAULT_CHUNK_SIZE); if (ngx_rtmp_fire_event(s, NGX_RTMP_CONNECT, NULL, NULL) != NGX_OK) { - return NULL; + goto failed; } s->data = (void *) r; return s; + +failed: + if (s->out_pool) { + ngx_destroy_pool(s->out_pool); + s->out_pool = NULL; + } + + if (s->in_streams_pool) { + ngx_destroy_pool(s->in_streams_pool); + s->in_streams_pool = NULL; + } + + return NULL; } -ngx_int_t +static ngx_int_t ngx_http_flv_live_connect_init(ngx_rtmp_session_t *s, ngx_str_t *app, - ngx_str_t *stream) + ngx_str_t *stream) { ngx_rtmp_connect_t v; ngx_http_request_t *r; - ngx_rtmp_notify_srv_conf_t *nscf; + u_char name[NGX_RTMP_MAX_NAME]; r = s->data; @@ -1949,6 +1965,15 @@ ngx_http_flv_live_connect_init(ngx_rtmp_session_t *s, ngx_str_t *app, #undef NGX_RTMP_SET_STRPAR + ngx_memzero(name, NGX_RTMP_MAX_NAME); + ngx_memcpy(name, stream->data, stream->len); + + if (ngx_rtmp_process_request_line(s, name, v.args, + (const u_char *) "flv live connect") != NGX_OK) + { + return NGX_ERROR; + } + if (ngx_rtmp_process_virtual_host(s) != NGX_OK) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "flv live: failed to process virtual host"); @@ -1956,11 +1981,6 @@ ngx_http_flv_live_connect_init(ngx_rtmp_session_t *s, ngx_str_t *app, return NGX_ERROR; } - nscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_notify_module); - if (nscf && nscf->url[NGX_RTMP_NOTIFY_CONNECT]) { - s->wait_notify_connect = 1; - } - s->stream.len = stream->len; s->stream.data = ngx_pstrdup(s->connection->pool, stream); @@ -1968,7 +1988,7 @@ ngx_http_flv_live_connect_init(ngx_rtmp_session_t *s, ngx_str_t *app, } -ngx_chain_t * +static ngx_chain_t * ngx_http_flv_live_meta_message(ngx_rtmp_session_t *s, ngx_chain_t *in) { ngx_rtmp_core_srv_conf_t *cscf; @@ -1982,7 +2002,6 @@ ngx_http_flv_live_meta_message(ngx_rtmp_session_t *s, ngx_chain_t *in) r = s->data; if (r == NULL || (r->connection && r->connection->destroyed)) { - ngx_rtmp_free_shared_chain(cscf, in); return NULL; } @@ -1993,9 +2012,9 @@ ngx_http_flv_live_meta_message(ngx_rtmp_session_t *s, ngx_chain_t *in) } -ngx_chain_t * +static ngx_chain_t * ngx_http_flv_live_append_message(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, - ngx_rtmp_header_t *lh, ngx_chain_t *in) + ngx_rtmp_header_t *lh, ngx_chain_t *in) { ngx_rtmp_core_srv_conf_t *cscf; ngx_http_request_t *r; @@ -2007,7 +2026,6 @@ ngx_http_flv_live_append_message(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, r = s->data; if (r == NULL || (r->connection && r->connection->destroyed)) { - ngx_rtmp_free_shared_chain(cscf, in); return NULL; } @@ -2022,9 +2040,9 @@ ngx_http_flv_live_append_message(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, * |Reserved(2b)+Filter(1b)+TagType(5b)|DataLength(3B)|TimeStamp(3B)| * TimeStampExt(1B)|StreamID(3B)|Data(DataLengthB)|PreviousTagSize| */ -ngx_chain_t * +static ngx_chain_t * ngx_http_flv_live_append_shared_bufs(ngx_rtmp_core_srv_conf_t *cscf, - ngx_rtmp_header_t *h, ngx_chain_t *in, ngx_flag_t chunked) + ngx_rtmp_header_t *h, ngx_chain_t *in, ngx_flag_t chunked) { ngx_chain_t *tag, *chunk_head, *chunk_tail, chunk, *iter, *last_in, **tail, prev_tag_size; @@ -2158,7 +2176,7 @@ ngx_http_flv_live_append_shared_bufs(ngx_rtmp_core_srv_conf_t *cscf, } -void +static void ngx_http_flv_live_free_message(ngx_rtmp_session_t *s, ngx_chain_t *in) { ngx_rtmp_core_srv_conf_t *cscf; @@ -2199,9 +2217,7 @@ ngx_http_flv_live_close_session_handler(ngx_rtmp_session_t *s) } while (s->out_pos != s->out_last) { - if (!s->gop_cache.out[s->out_pos].set) { - ngx_rtmp_free_shared_chain(cscf, s->out[s->out_pos]); - } + ngx_rtmp_free_shared_chain(cscf, s->out[s->out_pos]); s->out_pos++; s->out_pos %= s->out_queue; @@ -2231,7 +2247,7 @@ ngx_http_flv_live_cleanup(void *data) } -ngx_int_t +static ngx_int_t ngx_http_flv_live_handler(ngx_http_request_t *r) { ngx_int_t rc; @@ -2241,6 +2257,15 @@ ngx_http_flv_live_handler(ngx_http_request_t *r) ngx_rtmp_session_t *s; ngx_rtmp_connection_t *rconn; + if (ngx_exiting || ngx_terminate) { + return NGX_HTTP_CLOSE; + } + + hfcf = ngx_http_get_module_loc_conf(r, ngx_http_flv_live_module); + if (!hfcf->flv_live) { + return NGX_DECLINED; + } + if (!(r->method & (NGX_HTTP_GET))) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "flv live: HTTP method was not \"GET\""); @@ -2259,11 +2284,6 @@ ngx_http_flv_live_handler(ngx_http_request_t *r) return NGX_DECLINED; } - hfcf = ngx_http_get_module_loc_conf(r, ngx_http_flv_live_module); - if (!hfcf->flv_live) { - return NGX_DECLINED; - } - rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { @@ -2317,4 +2337,3 @@ ngx_http_flv_live_handler(ngx_http_request_t *r) return NGX_OK; } - diff --git a/ngx_http_flv_live_module.h b/ngx_http_flv_live_module.h index fbc6690..e0f3ada 100644 --- a/ngx_http_flv_live_module.h +++ b/ngx_http_flv_live_module.h @@ -21,6 +21,10 @@ extern ngx_module_t ngx_rtmp_module; +ngx_rtmp_play_pt http_flv_live_next_play; +ngx_rtmp_close_stream_pt http_flv_live_next_close_stream; + + #define ngx_rtmp_cycle_get_module_main_conf(cycle, module) \ (cycle->conf_ctx[ngx_rtmp_module.index] ? \ ((ngx_rtmp_conf_ctx_t *) cycle->conf_ctx[ngx_rtmp_module.index]) \ @@ -36,14 +40,11 @@ typedef struct ngx_http_flv_live_ctx_s { ngx_str_t app; ngx_str_t port; ngx_str_t stream; - - ngx_event_t play; } ngx_http_flv_live_ctx_t; typedef struct ngx_http_flv_live_conf_s { ngx_flag_t flv_live; - ngx_msec_t poll_interval; } ngx_http_flv_live_conf_t; @@ -54,28 +55,24 @@ typedef struct { ngx_chain_t *rpkt; ngx_int_t (*send_message_pt)(ngx_rtmp_session_t *s, - ngx_chain_t *out, ngx_uint_t priority); + ngx_chain_t *out, ngx_uint_t priority); ngx_chain_t *(*meta_message_pt)(ngx_rtmp_session_t *s, - ngx_chain_t *in); + ngx_chain_t *in); ngx_chain_t *(*append_message_pt)(ngx_rtmp_session_t *s, - ngx_rtmp_header_t *h, ngx_rtmp_header_t *lh, - ngx_chain_t *in); + ngx_rtmp_header_t *h, ngx_rtmp_header_t *lh, + ngx_chain_t *in); void (*free_message_pt)(ngx_rtmp_session_t *s, - ngx_chain_t *in); + ngx_chain_t *in); } ngx_rtmp_live_proc_handler_t; -ngx_int_t ngx_http_flv_live_join(ngx_rtmp_session_t *s, u_char *name, - unsigned int publisher); +ngx_int_t ngx_http_flv_live_play(ngx_rtmp_session_t *s, + ngx_rtmp_play_t *v); +ngx_int_t ngx_http_flv_live_close_stream(ngx_rtmp_session_t *s, + ngx_rtmp_close_stream_t *v); + ngx_int_t ngx_http_flv_live_send_header(ngx_rtmp_session_t *s); void ngx_http_flv_live_set_status(ngx_rtmp_session_t *s, unsigned active); -ngx_chain_t *ngx_http_flv_live_append_shared_bufs( - ngx_rtmp_core_srv_conf_t *cscf, - ngx_rtmp_header_t *h, - ngx_chain_t *in, - ngx_flag_t chunked); -ngx_int_t ngx_http_flv_live_send_message(ngx_rtmp_session_t *s, - ngx_chain_t *out, ngx_uint_t priority); #endif diff --git a/ngx_rtmp.c b/ngx_rtmp.c index 44465f5..2c564ad 100644 --- a/ngx_rtmp.c +++ b/ngx_rtmp.c @@ -777,7 +777,7 @@ ngx_rtmp_init_listening(ngx_conf_t *cf, ngx_rtmp_conf_port_t *port) break; } -#if (NGX_HAVE_REUSEPORT) +#if (nginx_version >= 1009001 && nginx_version <= 1015001) if (ngx_clone_listening(cf, ls) != NGX_OK) { return NGX_ERROR; } @@ -1321,12 +1321,6 @@ ngx_rtmp_set_virtual_server(ngx_rtmp_session_t *s, ngx_str_t *host) cscf->ctx->srv_conf[ngx_rtmp_core_module .ctx_index])->out_queue); - s->gop_cache.out = ngx_pcalloc(s->out_pool, - sizeof(ngx_rtmp_gop_cache_free_t) - * ((ngx_rtmp_core_srv_conf_t *) - cscf->ctx->srv_conf[ngx_rtmp_core_module - .ctx_index])->out_queue); - s->out_queue = cscf->out_queue; } diff --git a/ngx_rtmp.h b/ngx_rtmp.h index fa9e0e6..036a1ee 100644 --- a/ngx_rtmp.h +++ b/ngx_rtmp.h @@ -25,7 +25,6 @@ typedef struct ngx_rtmp_virtual_names_s ngx_rtmp_virtual_names_t; #include "ngx_rtmp_variables.h" -#include "ngx_rtmp_script.h" #if (NGX_WIN32) @@ -265,20 +264,6 @@ typedef struct { #endif -typedef void (*free_message_pt)(ngx_rtmp_session_t *s, ngx_chain_t *in); - -typedef struct { - free_message_pt free; - ngx_flag_t set; -} ngx_rtmp_gop_cache_free_t; - - -typedef struct { - ngx_rtmp_gop_cache_free_t *out; - ngx_uint_t count; -} ngx_rtmp_gop_cache_handler_t; - - struct ngx_rtmp_session_s { uint32_t signature; /* "RTMP" */ /* <-- FIXME wtf */ @@ -368,9 +353,7 @@ struct ngx_rtmp_session_s { u_char *port_end; unsigned keepalive:1; - unsigned lingering_close:1; - unsigned valid_application:1; unsigned valid_unparsed_uri:1; #if (NGX_PCRE) @@ -379,9 +362,6 @@ struct ngx_rtmp_session_s { u_char *captures_data; #endif - size_t limit_rate; - size_t limit_rate_after; - ngx_rtmp_connection_t *rtmp_connection; ngx_rtmp_session_t *publisher; @@ -393,10 +373,8 @@ struct ngx_rtmp_session_s { ngx_pool_t *out_temp_pool; unsigned server_changed:1; - unsigned wait_notify_connect:1; - unsigned wait_notify_play:1; - - ngx_rtmp_gop_cache_handler_t gop_cache; + unsigned notify_connect:1; + unsigned notify_play:1; /* input stream 0 (reserved by RTMP spec) * is used as free chain link */ @@ -509,7 +487,6 @@ struct ngx_rtmp_core_srv_conf_s { size_t connection_pool_size; ngx_flag_t merge_slashes; - ngx_flag_t listen_parsed; unsigned listen:1; #if (NGX_PCRE) @@ -535,25 +512,12 @@ typedef struct { ngx_rtmp_regex_t *regex; #endif - unsigned noname:1; /* "if () {}" block or limit_except */ - unsigned named:1; - size_t send_lowat; - size_t postpone_output; - size_t limit_rate; - size_t limit_rate_after; - size_t sendfile_max_chunk; ngx_msec_t send_timeout; - ngx_msec_t keepalive_timeout; - ngx_msec_t lingering_time; - ngx_msec_t lingering_timeout; ngx_msec_t resolver_timeout; ngx_resolver_t *resolver; - - ngx_flag_t tcp_nopush; - ngx_flag_t tcp_nodelay; } ngx_rtmp_core_app_conf_t; diff --git a/ngx_rtmp_auto_push_module.c b/ngx_rtmp_auto_push_module.c index 60c85d7..255cf55 100644 --- a/ngx_rtmp_auto_push_module.c +++ b/ngx_rtmp_auto_push_module.c @@ -121,7 +121,7 @@ ngx_module_t ngx_rtmp_auto_push_index_module = { }; -#define NGX_RTMP_AUTO_PUSH_SOCKNAME "nginx-rtmp" +#define NGX_RTMP_AUTO_PUSH_SOCKNAME "nginx-http-flv" static ngx_int_t diff --git a/ngx_rtmp_cmd_module.c b/ngx_rtmp_cmd_module.c index befb7ad..ac3c9b7 100644 --- a/ngx_rtmp_cmd_module.c +++ b/ngx_rtmp_cmd_module.c @@ -339,7 +339,6 @@ ngx_rtmp_cmd_connect(ngx_rtmp_session_t *s, ngx_rtmp_connect_t *v) { /* found app! */ s->app_conf = (*cacfp)->app_conf; - s->valid_application = 1; break; } } @@ -352,10 +351,6 @@ ngx_rtmp_cmd_connect(ngx_rtmp_session_t *s, ngx_rtmp_connect_t *v) object_encoding = v->object_encoding; - if (s->wait_notify_connect) { - s->wait_notify_connect = 0; - } - return ngx_rtmp_send_ack_size(s, cscf->ack_window) != NGX_OK || ngx_rtmp_send_bandwidth(s, cscf->ack_window, NGX_RTMP_LIMIT_DYNAMIC) != NGX_OK || diff --git a/ngx_rtmp_cmd_module.h b/ngx_rtmp_cmd_module.h index 075f1bd..be448f2 100644 --- a/ngx_rtmp_cmd_module.h +++ b/ngx_rtmp_cmd_module.h @@ -25,7 +25,7 @@ typedef struct { double trans; u_char app[NGX_RTMP_MAX_NAME]; u_char args[NGX_RTMP_MAX_ARGS]; - u_char flashver[32]; + u_char flashver[64]; u_char swf_url[NGX_RTMP_MAX_URL]; u_char tc_url[NGX_RTMP_MAX_URL]; double acodecs; diff --git a/ngx_rtmp_codec_module.c b/ngx_rtmp_codec_module.c index 2502517..b320079 100644 --- a/ngx_rtmp_codec_module.c +++ b/ngx_rtmp_codec_module.c @@ -303,7 +303,7 @@ ngx_rtmp_codec_parse_avc_header_in_keyframe(ngx_rtmp_session_t *s, ftype = (fmt & 0xf0) >> 4; ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "codec: ftype='%uD'", ftype); + "codec: ftype=%uD", ftype); if (ftype != NGX_RTMP_FRAME_IDR) { return NGX_ERROR; @@ -315,7 +315,7 @@ ngx_rtmp_codec_parse_avc_header_in_keyframe(ngx_rtmp_session_t *s, } ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "codec: htype='%uD'", htype); + "codec: htype=%uD", htype); /* proceed only with PICT */ if (htype != 1) { @@ -361,7 +361,7 @@ ngx_rtmp_codec_parse_avc_header_in_keyframe(ngx_rtmp_session_t *s, nal_bytes = ctx->avc_nal_bytes; ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "codec: nal_bytes='%uD'", nal_bytes); + "codec: nal_bytes=%uD", nal_bytes); left = NGX_RTMP_SPS_MAX_LENGTH; @@ -374,11 +374,11 @@ ngx_rtmp_codec_parse_avc_header_in_keyframe(ngx_rtmp_session_t *s, ngx_rtmp_rmemcpy(&len, &rlen, nal_bytes); ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "codec: len='%uD'", len); + "codec: len=%uD", len); if (len == 0) { ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "codec: skip, len='%uD'", len); + "codec: skip, len=%uD", len); continue; } @@ -388,7 +388,7 @@ ngx_rtmp_codec_parse_avc_header_in_keyframe(ngx_rtmp_session_t *s, } ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "codec: src_nal_type='%uD'", src_nal_type); + "codec: src_nal_type=%uD", src_nal_type); /** * +---------------+ @@ -400,7 +400,7 @@ ngx_rtmp_codec_parse_avc_header_in_keyframe(ngx_rtmp_session_t *s, nal_type = src_nal_type & 0x1f; ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "codec: nal_type='%uD'", nal_type); + "codec: nal_type=%uD", nal_type); if (!(nal_type >= NGX_RTMP_NALU_SPS && nal_type <= NGX_RTMP_NALU_PPS)) @@ -410,7 +410,7 @@ ngx_rtmp_codec_parse_avc_header_in_keyframe(ngx_rtmp_session_t *s, } ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "codec: skip non-sps or non-pps, nal_type='%uD'", nal_type); + "codec: skip non-sps or non-pps, nal_type=%uD", nal_type); continue; } @@ -443,7 +443,7 @@ ngx_rtmp_codec_parse_avc_header_in_keyframe(ngx_rtmp_session_t *s, has_sps = 1; ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "codec: has_sps='%uD'", has_sps); + "codec: has_sps=%uD", has_sps); } return (has_sps == 1) ? NGX_OK : NGX_ERROR; @@ -887,7 +887,7 @@ ngx_rtmp_codec_reconstruct_meta(ngx_rtmp_session_t *s) { NGX_RTMP_AMF_STRING, ngx_string("Server"), - "NGINX RTMP (https://github.com/winshining/nginx-http-flv-module)", 0 }, + "NGINX HTTP-FLV (https://github.com/winshining/nginx-http-flv-module)", 0 }, { NGX_RTMP_AMF_NUMBER, ngx_string("width"), diff --git a/ngx_rtmp_core_module.c b/ngx_rtmp_core_module.c index 21b5777..a745955 100644 --- a/ngx_rtmp_core_module.c +++ b/ngx_rtmp_core_module.c @@ -45,8 +45,6 @@ static char *ngx_rtmp_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_rtmp_core_lowat_check(ngx_conf_t *cf, void *post, void *data); static char *ngx_rtmp_core_pool_size(ngx_conf_t *cf, void *post, void *data); -static char *ngx_rtmp_core_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); static ngx_conf_post_t ngx_rtmp_core_lowat_post = @@ -193,20 +191,6 @@ static ngx_command_t ngx_rtmp_core_commands[] = { offsetof(ngx_rtmp_core_srv_conf_t, buflen), NULL }, - { ngx_string("tcp_nopush"), - NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_RTMP_APP_CONF_OFFSET, - offsetof(ngx_rtmp_core_app_conf_t, tcp_nopush), - NULL }, - - { ngx_string("tcp_nodelay"), - NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_RTMP_APP_CONF_OFFSET, - offsetof(ngx_rtmp_core_app_conf_t, tcp_nodelay), - NULL }, - { ngx_string("send_timeout"), NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -221,52 +205,6 @@ static ngx_command_t ngx_rtmp_core_commands[] = { offsetof(ngx_rtmp_core_app_conf_t, send_lowat), &ngx_rtmp_core_lowat_post }, - { ngx_string("postpone_output"), - NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_RTMP_APP_CONF_OFFSET, - offsetof(ngx_rtmp_core_app_conf_t, postpone_output), - NULL }, - - { ngx_string("limit_rate"), - NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF - /*|NGX_RTMP_LIF_CONF*/ - |NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_RTMP_APP_CONF_OFFSET, - offsetof(ngx_rtmp_core_app_conf_t, limit_rate), - NULL }, - - { ngx_string("limit_rate_after"), - NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF - /*|NGX_RTMP_LIF_CONF*/ - |NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_RTMP_APP_CONF_OFFSET, - offsetof(ngx_rtmp_core_app_conf_t, limit_rate_after), - NULL }, - - { ngx_string("keepalive_timeout"), - NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE12, - ngx_rtmp_core_keepalive, - NGX_RTMP_APP_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("lingering_time"), - NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, - ngx_conf_set_msec_slot, - NGX_RTMP_APP_CONF_OFFSET, - offsetof(ngx_rtmp_core_app_conf_t, lingering_time), - NULL }, - - { ngx_string("lingering_timeout"), - NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, - ngx_conf_set_msec_slot, - NGX_RTMP_APP_CONF_OFFSET, - offsetof(ngx_rtmp_core_app_conf_t, lingering_timeout), - NULL }, - { ngx_string("resolver"), NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_1MORE, ngx_rtmp_core_resolver, @@ -526,16 +464,8 @@ ngx_rtmp_core_create_app_conf(ngx_conf_t *cf) return NULL; } - conf->tcp_nopush = NGX_CONF_UNSET; - conf->tcp_nodelay = NGX_CONF_UNSET; conf->send_timeout = NGX_CONF_UNSET_MSEC; conf->send_lowat = NGX_CONF_UNSET_SIZE; - conf->postpone_output = NGX_CONF_UNSET_SIZE; - conf->limit_rate = NGX_CONF_UNSET_SIZE; - conf->limit_rate_after = NGX_CONF_UNSET_SIZE; - conf->keepalive_timeout = NGX_CONF_UNSET_MSEC; - conf->lingering_time = NGX_CONF_UNSET_MSEC; - conf->lingering_timeout = NGX_CONF_UNSET_MSEC; conf->resolver_timeout = NGX_CONF_UNSET_MSEC; return conf; @@ -548,23 +478,9 @@ 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; - ngx_conf_merge_value(conf->tcp_nopush, prev->tcp_nopush, 0); - ngx_conf_merge_value(conf->tcp_nodelay, prev->tcp_nodelay, 1); - ngx_conf_merge_msec_value(conf->send_timeout, prev->send_timeout, 60000); ngx_conf_merge_size_value(conf->send_lowat, prev->send_lowat, 0); - ngx_conf_merge_size_value(conf->postpone_output, prev->postpone_output, - 1460); - ngx_conf_merge_size_value(conf->limit_rate, prev->limit_rate, 0); - ngx_conf_merge_size_value(conf->limit_rate_after, prev->limit_rate_after, - 0); - ngx_conf_merge_msec_value(conf->keepalive_timeout, - prev->keepalive_timeout, 75000); - ngx_conf_merge_msec_value(conf->lingering_time, - prev->lingering_time, 30000); - ngx_conf_merge_msec_value(conf->lingering_timeout, - prev->lingering_timeout, 5000); ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout, 30000); @@ -1135,33 +1051,6 @@ ngx_rtmp_core_pool_size(ngx_conf_t *cf, void *post, void *data) } -static char * -ngx_rtmp_core_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_rtmp_core_app_conf_t *cacf = conf; - - ngx_str_t *value; - - if (cacf->keepalive_timeout != NGX_CONF_UNSET_MSEC) { - return "is duplicate"; - } - - value = cf->args->elts; - - cacf->keepalive_timeout = ngx_parse_time(&value[1], 0); - - if (cacf->keepalive_timeout == (ngx_msec_t) NGX_ERROR) { - return "invalid value"; - } - - if (cf->args->nelts == 2) { - return NGX_CONF_OK; - } - - return NGX_CONF_OK; -} - - static char * ngx_rtmp_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/ngx_rtmp_eval.c b/ngx_rtmp_eval.c index b02c44c..356af8a 100644 --- a/ngx_rtmp_eval.c +++ b/ngx_rtmp_eval.c @@ -166,8 +166,12 @@ ngx_rtmp_eval(void *ctx, ngx_str_t *in, ngx_rtmp_eval_t **e, ngx_str_t *out, case '\\': state = ESCAPE; continue; + default: + break; } + /* fall through */ + case ESCAPE: ngx_rtmp_eval_append(&b, &c, 1, log); state = NORMAL; diff --git a/ngx_rtmp_flv_live_index_module.c b/ngx_rtmp_flv_live_index_module.c new file mode 100644 index 0000000..30a12d8 --- /dev/null +++ b/ngx_rtmp_flv_live_index_module.c @@ -0,0 +1,65 @@ + +/* + * Copyright (C) Winshining + */ + +#include +#include +#include "ngx_http_flv_live_module.h" + + +static ngx_rtmp_play_pt next_play; +static ngx_rtmp_close_stream_pt next_close_stream; + + +static ngx_int_t ngx_rtmp_flv_live_index_postconfiguration(ngx_conf_t *cf); + + +static ngx_rtmp_module_t ngx_rtmp_flv_live_module_ctx = { + NULL, + ngx_rtmp_flv_live_index_postconfiguration, /* postconfiguration */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + + +static ngx_command_t ngx_rtmp_flv_live_index_commands[] = { + ngx_null_command +}; + + +ngx_module_t ngx_rtmp_flv_live_index_module = { + NGX_MODULE_V1, + &ngx_rtmp_flv_live_module_ctx, + ngx_rtmp_flv_live_index_commands, + NGX_RTMP_MODULE, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NGX_MODULE_V1_PADDING +}; + + +static ngx_int_t +ngx_rtmp_flv_live_index_postconfiguration(ngx_conf_t *cf) +{ + next_play = ngx_rtmp_play; + ngx_rtmp_play = ngx_http_flv_live_play; + + next_close_stream = ngx_rtmp_close_stream; + ngx_rtmp_close_stream = ngx_http_flv_live_close_stream; + + http_flv_live_next_play = next_play; + http_flv_live_next_close_stream = next_close_stream; + + return NGX_OK; +} + diff --git a/ngx_rtmp_gop_cache_module.c b/ngx_rtmp_gop_cache_module.c index febbc6b..9b0d856 100644 --- a/ngx_rtmp_gop_cache_module.c +++ b/ngx_rtmp_gop_cache_module.c @@ -2,6 +2,7 @@ /* * Copyright (C) Gnolizuh * Copyright (C) Winshining + * Copyright (C) HeyJupiter */ @@ -31,7 +32,6 @@ static void ngx_rtmp_gop_cache_update(ngx_rtmp_session_t *s); static void ngx_rtmp_gop_cache_frame(ngx_rtmp_session_t *s, ngx_uint_t prio, ngx_rtmp_header_t *ch, ngx_chain_t *frame); static void ngx_rtmp_gop_cache_send(ngx_rtmp_session_t *s); -static void ngx_rtmp_gop_cache_init_handler(ngx_rtmp_session_t *s); static ngx_int_t ngx_rtmp_gop_cache_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in); static ngx_int_t ngx_rtmp_gop_cache_publish(ngx_rtmp_session_t *s, @@ -42,58 +42,15 @@ static ngx_int_t ngx_rtmp_gop_cache_close_stream(ngx_rtmp_session_t *s, ngx_rtmp_close_stream_t *v); -static ngx_chain_t *ngx_rtmp_gop_cache_append_shared_bufs( - ngx_rtmp_gop_cache_ctx_t *ctx, ngx_chain_t *head, ngx_chain_t *in); -static ngx_chain_t *ngx_rtmp_gop_cache_alloc_shared_buf( - ngx_rtmp_gop_cache_ctx_t *ctx); -static void ngx_rtmp_gop_cache_free_shared_chain(ngx_rtmp_gop_cache_ctx_t *ctx, - ngx_chain_t *in); - -static ngx_chain_t *ngx_hfl_gop_cache_meta_message(ngx_rtmp_session_t *s, - ngx_chain_t *in); -static ngx_chain_t *ngx_hfl_gop_cache_append_message(ngx_rtmp_session_t *s, - ngx_rtmp_header_t *h, ngx_rtmp_header_t *lh, ngx_chain_t *in); -static ngx_chain_t *ngx_hfl_gop_cache_append_shared_bufs( - ngx_rtmp_gop_cache_ctx_t *ctx, ngx_rtmp_header_t *h, ngx_chain_t *in, - ngx_flag_t chunked); -static void ngx_hfl_gop_cache_free_message(ngx_rtmp_session_t *s, - ngx_chain_t *in); - - -static ngx_chain_t *ngx_rl_gop_cache_meta_message(ngx_rtmp_session_t *s, - ngx_chain_t *in); -static ngx_chain_t *ngx_rl_gop_cache_append_message(ngx_rtmp_session_t *s, - ngx_rtmp_header_t *h, ngx_rtmp_header_t *lh, ngx_chain_t *in); -static void ngx_rl_gop_cache_free_message(ngx_rtmp_session_t *s, - ngx_chain_t *in); - - static ngx_int_t ngx_rtmp_gop_cache_postconfiguration(ngx_conf_t *cf); static void *ngx_rtmp_gop_cache_create_app_conf(ngx_conf_t *cf); static char *ngx_rtmp_gop_cache_merge_app_conf(ngx_conf_t *cf, void *parent, void *child); -static ngx_rtmp_gop_cache_proc_handler_t ngx_rl_gop_cache_proc_handler = { - ngx_rtmp_live_send_message, - ngx_rl_gop_cache_meta_message, - ngx_rl_gop_cache_append_message, - ngx_rl_gop_cache_free_message -}; - -static ngx_rtmp_gop_cache_proc_handler_t ngx_hfl_gop_cache_proc_handler = { - ngx_http_flv_live_send_message, - ngx_hfl_gop_cache_meta_message, - ngx_hfl_gop_cache_append_message, - ngx_hfl_gop_cache_free_message -}; - -ngx_rtmp_gop_cache_proc_handler_t *ngx_rtmp_gop_cache_proc_handlers[] = { - &ngx_rl_gop_cache_proc_handler, - &ngx_hfl_gop_cache_proc_handler -}; - -extern ngx_module_t ngx_http_flv_live_module; +extern ngx_rtmp_live_proc_handler_t *ngx_rtmp_live_proc_handlers + [NGX_RTMP_PROTOCOL_HTTP + 1]; +extern ngx_module_t ngx_http_flv_live_module; static ngx_command_t ngx_rtmp_gop_cache_commands[] = { @@ -224,15 +181,21 @@ static ngx_rtmp_gop_frame_t * ngx_rtmp_gop_cache_free_frame(ngx_rtmp_session_t *s, ngx_rtmp_gop_frame_t *frame) { + ngx_rtmp_core_srv_conf_t *cscf; ngx_rtmp_gop_cache_ctx_t *ctx; + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + if (cscf == NULL) { + return NULL; + } + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_gop_cache_module); if (ctx == NULL) { return NULL; } if (frame->frame) { - ngx_rtmp_gop_cache_free_shared_chain(ctx, frame->frame); + ngx_rtmp_free_shared_chain(cscf, frame->frame); frame->frame = NULL; } @@ -243,8 +206,8 @@ ngx_rtmp_gop_cache_free_frame(ngx_rtmp_session_t *s, } ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "gop free frame: type='%s' video_frame_in_cache='%uD' " - "audio_frame_in_cache='%uD'", + "gop free frame: type='%s' video_frame_in_cache=%uD " + "audio_frame_in_cache=%uD", frame->h.type == NGX_RTMP_MSG_VIDEO ? "video" : "audio", ctx->video_frame_in_all, ctx->audio_frame_in_all); @@ -288,10 +251,10 @@ ngx_rtmp_gop_cache_link_frame(ngx_rtmp_session_t *s, ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "gop link frame: type='%s' " - "ctx->video_frame_in_all='%uD' " - "ctx->audio_frame_in_all='%uD' " - "cache->video_frame_in_this='%uD' " - "cache->audio_frame_in_this='%uD'", + "ctx->video_frame_in_all=%uD " + "ctx->audio_frame_in_all=%uD " + "cache->video_frame_in_this=%uD " + "cache->audio_frame_in_this=%uD", frame->h.type == NGX_RTMP_MSG_VIDEO ? "video" : "audio", ctx->video_frame_in_all, ctx->audio_frame_in_all, cache->video_frame_in_this, cache->audio_frame_in_this); @@ -356,7 +319,7 @@ ngx_rtmp_gop_cache_alloc_cache(ngx_rtmp_session_t *s) ctx->gop_cache_count++; ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "gop alloc cache: gop_cache_count='%uD'", ctx->gop_cache_count); + "gop alloc cache: gop_cache_count=%uD", ctx->gop_cache_count); return NGX_OK; } @@ -388,7 +351,7 @@ ngx_rtmp_gop_cache_free_cache(ngx_rtmp_session_t *s, ctx->gop_cache_count--; ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "gop free cache: gop_cache_count='%uD'", ctx->gop_cache_count); + "gop free cache: gop_cache_count=%uD", ctx->gop_cache_count); return cache->next; } @@ -409,19 +372,18 @@ ngx_rtmp_gop_cache_cleanup(ngx_rtmp_session_t *s) ngx_rtmp_gop_cache_free_cache(s, cache); } - if (ctx->pool) { - ngx_destroy_pool(ctx->pool); - ctx->pool = NULL; - } - ctx->video_seq_header = NULL; ctx->audio_seq_header = NULL; ctx->meta = NULL; - ctx->cache_tail = ctx->cache_head = NULL; + if (ctx->cache_head) { + ctx->cache_head->next = ctx->free_cache; + ctx->free_cache = ctx->cache_head; + ctx->cache_head = NULL; + } + + ctx->cache_tail = NULL; ctx->gop_cache_count = 0; - ctx->free_cache = NULL; - ctx->free_frame = NULL; ctx->video_frame_in_all = 0; ctx->audio_frame_in_all = 0; } @@ -464,6 +426,7 @@ ngx_rtmp_gop_cache_frame(ngx_rtmp_session_t *s, ngx_uint_t prio, { ngx_rtmp_gop_cache_ctx_t *ctx; ngx_rtmp_codec_ctx_t *codec_ctx; + ngx_rtmp_core_srv_conf_t *cscf; ngx_rtmp_gop_cache_app_conf_t *gacf; ngx_rtmp_gop_frame_t *gf; @@ -472,6 +435,11 @@ ngx_rtmp_gop_cache_frame(ngx_rtmp_session_t *s, ngx_uint_t prio, return; } + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + if (cscf == NULL) { + return; + } + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_gop_cache_module); if (ctx == NULL) { return; @@ -486,7 +454,7 @@ ngx_rtmp_gop_cache_frame(ngx_rtmp_session_t *s, ngx_uint_t prio, // drop video when not H.264 if (codec_ctx->video_codec_id != NGX_RTMP_VIDEO_H264) { ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "drop video non-H.264 encode type timestamp='%uD'", + "drop video non-H.264 encode type timestamp=%uD", ch->timestamp); return; @@ -495,7 +463,7 @@ ngx_rtmp_gop_cache_frame(ngx_rtmp_session_t *s, ngx_uint_t prio, // drop non-IDR if (prio != NGX_RTMP_VIDEO_KEY_FRAME && ctx->cache_head == NULL) { ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "drop video non-keyframe timestamp='%uD'", + "drop video non-keyframe timestamp=%uD", ch->timestamp); return; @@ -505,7 +473,7 @@ ngx_rtmp_gop_cache_frame(ngx_rtmp_session_t *s, ngx_uint_t prio, // pure audio if (ctx->video_frame_in_all == 0 && ch->type == NGX_RTMP_MSG_AUDIO) { ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "drop audio frame timestamp='%uD'", + "drop audio frame timestamp=%uD", ch->timestamp); return; @@ -525,10 +493,10 @@ ngx_rtmp_gop_cache_frame(ngx_rtmp_session_t *s, ngx_uint_t prio, gf->h = *ch; gf->prio = prio; gf->next = NULL; - gf->frame = ngx_rtmp_gop_cache_append_shared_bufs(ctx, NULL, frame); + gf->frame = ngx_rtmp_append_shared_bufs(cscf, NULL, frame); if (ngx_rtmp_gop_cache_link_frame(s, gf) != NGX_OK) { - ngx_rtmp_gop_cache_free_shared_chain(ctx, gf->frame); + ngx_rtmp_free_shared_chain(cscf, gf->frame); return; } @@ -538,9 +506,9 @@ ngx_rtmp_gop_cache_frame(ngx_rtmp_session_t *s, ngx_uint_t prio, > gacf->gop_max_frame_count) { ngx_log_error(NGX_LOG_WARN, s->connection->log, 0, - "gop cache: video_frame_in_cache='%uD' " - "audio_frame_in_cache='%uD' max_video_count='%uD' " - "max_audio_count='%uD' gop_max_frame_count='%uD'", + "gop cache: video_frame_in_cache=%uD " + "audio_frame_in_cache=%uD max_video_count=%uD " + "max_audio_count=%uD gop_max_frame_count=%uD", ctx->video_frame_in_all, ctx->audio_frame_in_all, gacf->gop_max_video_count, gacf->gop_max_audio_count, gacf->gop_max_frame_count); @@ -552,7 +520,7 @@ ngx_rtmp_gop_cache_frame(ngx_rtmp_session_t *s, ngx_uint_t prio, ngx_rtmp_gop_cache_update(s); ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "gop cache: cache packet type='%s' timestamp='%uD'", + "gop cache: cache packet type='%s' timestamp=%uD", gf->h.type == NGX_RTMP_MSG_AUDIO ? "audio" : "video", gf->h.timestamp); } @@ -574,8 +542,9 @@ ngx_rtmp_gop_cache_send(ngx_rtmp_session_t *s) uint32_t delta; ngx_int_t csidx; ngx_rtmp_live_chunk_stream_t *cs; - ngx_rtmp_gop_cache_proc_handler_t *handler; + ngx_rtmp_live_proc_handler_t *handler; ngx_http_request_t *r; + ngx_flag_t error; lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_live_module); if (lacf == NULL) { @@ -598,7 +567,7 @@ ngx_rtmp_gop_cache_send(ngx_rtmp_session_t *s) pub_ctx = ctx->stream->pub_ctx; rs = pub_ctx->session; s->publisher = rs; - handler = ngx_rtmp_gop_cache_proc_handlers[ctx->protocol]; + handler = ngx_rtmp_live_proc_handlers[ctx->protocol]; gctx = ngx_rtmp_get_module_ctx(rs, ngx_rtmp_gop_cache_module); if (gctx == NULL) { @@ -606,9 +575,13 @@ ngx_rtmp_gop_cache_send(ngx_rtmp_session_t *s) } for (cache = gctx->cache_head; cache; cache = cache->next) { + if (s->connection == NULL || s->connection->destroyed) { + return; + } + if (ctx->protocol == NGX_RTMP_PROTOCOL_HTTP) { r = s->data; - if (r == NULL || (r->connection && r->connection->destroyed)) { + if (r == NULL) { return; } @@ -622,6 +595,7 @@ ngx_rtmp_gop_cache_send(ngx_rtmp_session_t *s) if (meta == NULL && meta_version != gctx->meta_version) { meta = handler->meta_message_pt(s, gctx->meta); if (meta == NULL) { + ngx_rtmp_finalize_session(s); return; } } @@ -635,8 +609,6 @@ ngx_rtmp_gop_cache_send(ngx_rtmp_session_t *s) ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "gop cache send: meta"); - ngx_rtmp_gop_cache_init_handler(s); - if (handler->send_message_pt(s, meta, 0) == NGX_ERROR) { ngx_rtmp_finalize_session(s); return; @@ -647,6 +619,10 @@ ngx_rtmp_gop_cache_send(ngx_rtmp_session_t *s) } for (gf = cache->frame_head; gf; gf = gf->next) { + if (s->connection == NULL || s->connection->destroyed) { + return; + } + csidx = !(lacf->interleave || gf->h.type == NGX_RTMP_MSG_VIDEO); cs = &ctx->cs[csidx]; @@ -658,6 +634,7 @@ ngx_rtmp_gop_cache_send(ngx_rtmp_session_t *s) } delta = ch.timestamp - lh.timestamp; + error = 0; if (!cs->active) { switch (gf->h.type) { @@ -671,14 +648,13 @@ ngx_rtmp_gop_cache_send(ngx_rtmp_session_t *s) if (header) { apkt = handler->append_message_pt(s, &lh, NULL, header); if (apkt == NULL) { - return; + error = 1; + goto next; } - - ngx_rtmp_gop_cache_init_handler(s); } if (apkt && handler->send_message_pt(s, apkt, 0) != NGX_OK) { - continue; + goto next; } cs->timestamp = lh.timestamp; @@ -688,29 +664,29 @@ ngx_rtmp_gop_cache_send(ngx_rtmp_session_t *s) pkt = handler->append_message_pt(s, &ch, &lh, gf->frame); if (pkt == NULL) { - return; + error = 1; + goto next; } - ngx_rtmp_gop_cache_init_handler(s); - if (handler->send_message_pt(s, pkt, gf->prio) != NGX_OK) { ++pub_ctx->ndropped; cs->dropped += delta; - ngx_rtmp_finalize_session(s); - return; + goto next; } ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "gop cache send: tag type='%s' prio='%d' ctimestamp='%uD' " - "ltimestamp='%uD'", + "gop cache send: tag type='%s' prio=%d ctimestamp=%uD " + "ltimestamp=%uD", gf->h.type == NGX_RTMP_MSG_AUDIO ? "audio" : "video", gf->prio, ch.timestamp, lh.timestamp); cs->timestamp += delta; s->current_time = cs->timestamp; + next: + if (pkt) { handler->free_message_pt(s, pkt); pkt = NULL; @@ -720,25 +696,12 @@ ngx_rtmp_gop_cache_send(ngx_rtmp_session_t *s) handler->free_message_pt(s, apkt); apkt = NULL; } - } - } -} - -static void -ngx_rtmp_gop_cache_init_handler(ngx_rtmp_session_t *s) -{ - ngx_rtmp_live_ctx_t *ctx; - - ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); - - s->gop_cache.out[s->out_last].set = 1; - s->gop_cache.count++; - - if (ctx->protocol == NGX_RTMP_PROTOCOL_RTMP) { - s->gop_cache.out[s->out_last].free = ngx_rl_gop_cache_free_message; - } else { - s->gop_cache.out[s->out_last].free = ngx_hfl_gop_cache_free_message; + if (error) { + ngx_rtmp_finalize_session(s); + return; + } + } } } @@ -750,10 +713,10 @@ ngx_rtmp_gop_cache_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_rtmp_live_ctx_t *ctx; ngx_rtmp_gop_cache_app_conf_t *gacf; ngx_rtmp_live_app_conf_t *lacf; + ngx_rtmp_live_chunk_stream_t *cs; ngx_rtmp_header_t ch; ngx_uint_t prio; ngx_uint_t csidx; - ngx_rtmp_live_chunk_stream_t *cs; gacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_gop_cache_module); if (gacf == NULL || !gacf->gop_cache) { @@ -803,18 +766,12 @@ ngx_rtmp_gop_cache_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v) { ngx_rtmp_gop_cache_app_conf_t *gacf; ngx_rtmp_gop_cache_ctx_t *ctx; - ngx_rtmp_core_srv_conf_t *cscf; gacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_gop_cache_module); if (gacf == NULL || !gacf->gop_cache) { goto next; } - cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); - if (cscf == NULL) { - goto next; - } - ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "gop cache publish: name='%s' type='%s'", v->name, v->type); @@ -837,8 +794,6 @@ ngx_rtmp_gop_cache_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v) } } - ctx->chunk_size = cscf->chunk_size; - next: return next_publish(s, v); } @@ -848,8 +803,6 @@ static ngx_int_t ngx_rtmp_gop_cache_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v) { ngx_rtmp_gop_cache_app_conf_t *gacf; - ngx_rtmp_gop_cache_ctx_t *ctx; - ngx_rtmp_core_srv_conf_t *cscf; #ifdef NGX_DEBUG ngx_msec_t start, end; #endif @@ -859,39 +812,15 @@ ngx_rtmp_gop_cache_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v) goto next; } - cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); - if (cscf == NULL) { - goto next; - } - - ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_gop_cache_module); - if (ctx == NULL) { - ctx = ngx_palloc(s->connection->pool, - sizeof(ngx_rtmp_gop_cache_ctx_t)); - ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_gop_cache_module); - } - - ngx_memzero(ctx, sizeof(*ctx)); - - if (ctx->pool == NULL) { - ctx->pool = ngx_create_pool(NGX_GOP_CACHE_POOL_CREATE_SIZE, - s->connection->log); - if (ctx->pool == NULL) { - return NGX_ERROR; - } - } - - ctx->chunk_size = cscf->chunk_size; - ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "gop cache play: name='%s' start='%i' duration='%i' reset='%d'", + "gop cache play: name='%s' start=%i duration=%i reset=%d", v->name, (ngx_int_t) v->start, (ngx_int_t) v->duration, (ngx_uint_t) v->reset); #ifdef NGX_DEBUG start = ngx_current_msec; ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "gop cache send: start_time='%uD'", start); + "gop cache send: start_time=%uD", start); #endif ngx_rtmp_gop_cache_send(s); @@ -899,10 +828,10 @@ ngx_rtmp_gop_cache_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v) #ifdef NGX_DEBUG end = ngx_current_msec; ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "gop cache send: end_time='%uD'", end); + "gop cache send: end_time=%uD", end); ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "gop cache send: delta_time='%uD'", end - start); + "gop cache send: delta_time=%uD", end - start); #endif next: @@ -925,12 +854,6 @@ ngx_rtmp_gop_cache_close_stream(ngx_rtmp_session_t *s, } if (ctx->publishing == 0) { - gctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_gop_cache_module); - if (gctx && gctx->pool) { - ngx_destroy_pool(gctx->pool); - gctx->pool = NULL; - } - goto next; } @@ -946,377 +869,18 @@ ngx_rtmp_gop_cache_close_stream(ngx_rtmp_session_t *s, ngx_rtmp_gop_cache_cleanup(s); -next: - return next_close_stream(s, v); -} - - -static ngx_chain_t * -ngx_rtmp_gop_cache_append_shared_bufs(ngx_rtmp_gop_cache_ctx_t *ctx, - ngx_chain_t *head, ngx_chain_t *in) -{ - ngx_chain_t *l, **ll; - u_char *p; - size_t size; - - ll = &head; - p = in->buf->pos; - l = head; - - if (l) { - for(; l->next; l = l->next); - ll = &l->next; - } - - for ( ;; ) { - - if (l == NULL || l->buf->last == l->buf->end) { - l = ngx_rtmp_gop_cache_alloc_shared_buf(ctx); - if (l == NULL || l->buf == NULL) { - break; - } - - *ll = l; - ll = &l->next; - } - - while (l->buf->end - l->buf->last >= in->buf->last - p) { - l->buf->last = ngx_cpymem(l->buf->last, p, - in->buf->last - p); - in = in->next; - if (in == NULL) { - goto done; - } - p = in->buf->pos; - } - - size = l->buf->end - l->buf->last; - l->buf->last = ngx_cpymem(l->buf->last, p, size); - p += size; - } - -done: - *ll = NULL; - - return head; -} - - -static ngx_chain_t * -ngx_rtmp_gop_cache_alloc_shared_buf(ngx_rtmp_gop_cache_ctx_t *ctx) -{ - u_char *p; - ngx_chain_t *out; - ngx_buf_t *b; - size_t size; - - if (ctx->free) { - out = ctx->free; - ctx->free = out->next; - - } else { - - size = ctx->chunk_size + NGX_RTMP_MAX_CHUNK_HEADER; - - p = ngx_pcalloc(ctx->pool, NGX_RTMP_REFCOUNT_BYTES - + sizeof(ngx_chain_t) - + sizeof(ngx_buf_t) - + size); - if (p == NULL) { - return NULL; - } - - p += NGX_RTMP_REFCOUNT_BYTES; - out = (ngx_chain_t *)p; - - p += sizeof(ngx_chain_t); - out->buf = (ngx_buf_t *)p; - - p += sizeof(ngx_buf_t); - out->buf->start = p; - out->buf->end = p + size; - } - - out->next = NULL; - b = out->buf; - b->pos = b->last = b->start + NGX_RTMP_MAX_CHUNK_HEADER; - b->memory = 1; - - /* buffer has refcount =1 when created! */ - ngx_rtmp_ref_set(out, 1); - - return out; -} - - -static void -ngx_rtmp_gop_cache_free_shared_chain(ngx_rtmp_gop_cache_ctx_t *ctx, - ngx_chain_t *in) -{ - ngx_chain_t *cl; - - if (ngx_rtmp_ref_put(in)) { - return; - } - - for (cl = in; ; cl = cl->next) { - if (cl->next == NULL) { - cl->next = ctx->free; - ctx->free = in; - return; - } - } -} - - -static ngx_chain_t * -ngx_hfl_gop_cache_meta_message(ngx_rtmp_session_t *s, ngx_chain_t *in) -{ - ngx_rtmp_gop_cache_ctx_t *ctx; - ngx_http_request_t *r; - ngx_rtmp_header_t ch; - - ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_gop_cache_module); - if (ctx == NULL) { - return NULL; - } - - r = s->data; - if (r == NULL || (r->connection && r->connection->destroyed)) { - ngx_rtmp_gop_cache_free_shared_chain(ctx, in); - return NULL; - } - - ch.timestamp = 0; - ch.type = NGX_RTMP_MSG_AMF_META; - - return ngx_hfl_gop_cache_append_message(s, &ch, NULL, in); -} - - -static ngx_chain_t * -ngx_hfl_gop_cache_append_message(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, - ngx_rtmp_header_t *lh, ngx_chain_t *in) -{ - ngx_rtmp_gop_cache_ctx_t *ctx; - ngx_http_request_t *r; - - ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_gop_cache_module); - if (ctx == NULL) { - return NULL; - } - - r = s->data; - if (r == NULL || (r->connection && r->connection->destroyed)) { - ngx_rtmp_gop_cache_free_shared_chain(ctx, in); - return NULL; - } - - return ngx_hfl_gop_cache_append_shared_bufs(ctx, h, in, r->chunked); -} - - -static ngx_chain_t * -ngx_hfl_gop_cache_append_shared_bufs(ngx_rtmp_gop_cache_ctx_t *ctx, - ngx_rtmp_header_t *h, ngx_chain_t *in, ngx_flag_t chunked) -{ - ngx_chain_t *tag, *ch, *ct, chunk, *iter, *last_in, **tail, - prev_tag_size; - u_char *pos, *p, -#if !(NGX_WIN32) - chunk_item[ngx_strlen("0000000000000000" CRLF) + 1]; -#else - chunk_item[19]; -#endif - uint32_t data_size, size; - off_t tag_size; - ngx_buf_t prev_tag_size_buf, chunk_buf; - - for (data_size = 0, iter = in, last_in = iter; iter; iter = iter->next) { - last_in = iter; - data_size += (iter->buf->last - iter->buf->pos); - } - - tail = &last_in->next; - *tail = &prev_tag_size; - - tag_size = data_size + NGX_FLV_TAG_HEADER_SIZE; - - prev_tag_size.buf = &prev_tag_size_buf; - prev_tag_size.next = NULL; - - prev_tag_size_buf.start = (u_char *) &size; - prev_tag_size_buf.end = prev_tag_size_buf.start + sizeof(uint32_t); - prev_tag_size_buf.pos = prev_tag_size_buf.start; - prev_tag_size_buf.last = prev_tag_size_buf.end; - - pos = prev_tag_size_buf.pos; - p = (u_char *) &tag_size; - *pos++ = p[3]; - *pos++ = p[2]; - *pos++ = p[1]; - *pos++ = p[0]; - - tag = ngx_rtmp_gop_cache_append_shared_bufs(ctx, NULL, in); - if (tag == NULL) { - return NULL; - } - - /* it links to the local variable, unlink it */ - *tail = NULL; - - tag->buf->pos -= NGX_FLV_TAG_HEADER_SIZE; - pos = tag->buf->pos; - - /* type, 5bits */ - *pos++ = (u_char) (h->type & 0x1f); - - /* data length, 3B */ - p = (u_char *) &data_size; - *pos++ = p[2]; - *pos++ = p[1]; - *pos++ = p[0]; - - /* timestamp, 3B + ext, 1B */ - p = (u_char *) &h->timestamp; - *pos++ = p[2]; - *pos++ = p[1]; - *pos++ = p[0]; - *pos++ = p[3]; - - /* streamId, 3B, always be 0 */ - *pos++ = 0; - *pos++ = 0; - *pos++ = 0; - - /* add chunk header and tail */ - if (chunked) { - /* 4 is the size of previous tag size itself */ - *ngx_sprintf(chunk_item, "%xO" CRLF, tag_size + 4) = 0; - - chunk_buf.start = chunk_item; - chunk_buf.pos = chunk_buf.start; - chunk_buf.end = chunk_buf.start + ngx_strlen(chunk_item); - chunk_buf.last = chunk_buf.end; - - chunk.buf = &chunk_buf; - chunk.next = NULL; - - ch = ngx_rtmp_gop_cache_append_shared_bufs(ctx, NULL, &chunk); - if (ch == NULL) { - return NULL; - } - - for (iter = tag, last_in = iter; iter; iter = iter->next) { - last_in = iter; - } - - /* save the memory, very likely */ -#if !(NGX_WIN32) - if (__builtin_expect(last_in->buf->last + 2 <= last_in->buf->end, 1)) { -#else - if (last_in->buf->last + 2 <= last_in->buf->end) { -#endif - *last_in->buf->last++ = CR; - *last_in->buf->last++ = LF; - } else { - *ngx_sprintf(chunk_item, CRLF) = 0; - chunk_buf.start = chunk_item; - chunk_buf.pos = chunk_buf.start; - chunk_buf.end = chunk_buf.start + ngx_strlen(chunk_item); - chunk_buf.last = chunk_buf.end; - - chunk.buf = &chunk_buf; - chunk.next = NULL; - - ct = ngx_rtmp_gop_cache_append_shared_bufs(ctx, NULL, &chunk); - if (ct == NULL) { - return NULL; - } - - tail = &last_in->next; - *tail = ct; - } - - ch->next = tag; - - return ch; - } - - return tag; -} - - -static void -ngx_hfl_gop_cache_free_message(ngx_rtmp_session_t *s, ngx_chain_t *in) -{ - ngx_rtmp_gop_cache_ctx_t *ctx; - - ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_gop_cache_module); - if (ctx == NULL) { - return; - } - - ngx_rtmp_gop_cache_free_shared_chain(ctx, in); -} - - -static ngx_chain_t * -ngx_rl_gop_cache_meta_message(ngx_rtmp_session_t *s, ngx_chain_t *in) -{ - ngx_rtmp_gop_cache_ctx_t *ctx; - - ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_gop_cache_module); - if (ctx == NULL) { - return NULL; - } - - return ngx_rtmp_gop_cache_append_shared_bufs(ctx, NULL, in); -} - - -static ngx_chain_t * -ngx_rl_gop_cache_append_message(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, - ngx_rtmp_header_t *lh, ngx_chain_t *in) -{ - ngx_rtmp_gop_cache_ctx_t *ctx; - ngx_chain_t *pkt; - - ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_gop_cache_module); - if (ctx == NULL) { - return NULL; + gctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_gop_cache_module); + if (gctx == NULL) { + goto next; } - pkt = ngx_rtmp_gop_cache_append_shared_bufs(ctx, NULL, in); - if (pkt != NULL) { - ngx_rtmp_prepare_message(s, h, lh, pkt); + if (gctx->pool) { + ngx_destroy_pool(gctx->pool); + gctx->pool = NULL; } - return pkt; -} - - -static void -ngx_rl_gop_cache_free_message(ngx_rtmp_session_t *s, ngx_chain_t *in) -{ - ngx_rtmp_gop_cache_ctx_t *ctx; - - ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_gop_cache_module); - if (ctx == NULL) { - return; - } - - ngx_rtmp_gop_cache_free_shared_chain(ctx, in); -} - - -void -ngx_rtmp_gop_cache_exec_handler(ngx_rtmp_session_t *s, size_t pos, - ngx_chain_t *in) -{ - s->gop_cache.out[pos].set = 0; - s->gop_cache.out[pos].free(s, in); - s->gop_cache.count--; +next: + return next_close_stream(s, v); } diff --git a/ngx_rtmp_gop_cache_module.h b/ngx_rtmp_gop_cache_module.h index cebf141..7e8d18b 100644 --- a/ngx_rtmp_gop_cache_module.h +++ b/ngx_rtmp_gop_cache_module.h @@ -54,7 +54,6 @@ typedef struct ngx_rtmp_gop_cache_ctx_s { ngx_chain_t *free; ngx_uint_t meta_version; - ngx_int_t chunk_size; size_t gop_cache_count; size_t video_frame_in_all; @@ -62,19 +61,5 @@ typedef struct ngx_rtmp_gop_cache_ctx_s { } ngx_rtmp_gop_cache_ctx_t; -typedef struct { - ngx_int_t (*send_message_pt)(ngx_rtmp_session_t *s, ngx_chain_t *out, - ngx_uint_t priority); - ngx_chain_t *(*meta_message_pt)(ngx_rtmp_session_t *s, ngx_chain_t *in); - ngx_chain_t *(*append_message_pt)(ngx_rtmp_session_t *s, - ngx_rtmp_header_t *h, ngx_rtmp_header_t *lh, ngx_chain_t *in); - void (*free_message_pt)(ngx_rtmp_session_t *s, ngx_chain_t *in); -} ngx_rtmp_gop_cache_proc_handler_t; - - -void ngx_rtmp_gop_cache_exec_handler(ngx_rtmp_session_t *s, size_t pos, - ngx_chain_t *in); - - #endif diff --git a/ngx_rtmp_handler.c b/ngx_rtmp_handler.c index 9a98623..0ed7758 100644 --- a/ngx_rtmp_handler.c +++ b/ngx_rtmp_handler.c @@ -1,7 +1,7 @@ /* - * Copyright (C) Roman Arutyunyan - * Copyright (C) Winshining + * Copyright (C) Roman Arutyunyan + * Copyright (C) Winshining */ @@ -10,7 +10,6 @@ #include "ngx_rtmp.h" #include "ngx_rtmp_amf.h" #include "ngx_rtmp_cmd_module.h" -#include "ngx_rtmp_gop_cache_module.h" static void ngx_rtmp_recv(ngx_event_t *rev); @@ -553,14 +552,8 @@ ngx_rtmp_send(ngx_event_t *wev) if (s->out_bpos == s->out_chain->buf->last) { s->out_chain = s->out_chain->next; if (s->out_chain == NULL) { - if (s->gop_cache.out[s->out_pos].set) { - ngx_rtmp_gop_cache_exec_handler(s, s->out_pos, - s->out[s->out_pos]); - } else { - cscf = ngx_rtmp_get_module_srv_conf(s, - ngx_rtmp_core_module); - ngx_rtmp_free_shared_chain(cscf, s->out[s->out_pos]); - } + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + ngx_rtmp_free_shared_chain(cscf, s->out[s->out_pos]); ++s->out_pos; s->out_pos %= s->out_queue; if (s->out_pos == s->out_last) { @@ -729,10 +722,8 @@ ngx_rtmp_send_message(ngx_rtmp_session_t *s, ngx_chain_t *out, ngx_uint_t priority) { ngx_uint_t nmsg; - ssize_t delta; - delta = s->out_last - s->out_pos; - nmsg = (delta >= 0 ? delta : -delta) % s->out_queue + 1; + nmsg = (s->out_last + s->out_queue - s->out_pos) % s->out_queue + 1; if (priority > 3) { priority = 3; @@ -745,10 +736,6 @@ ngx_rtmp_send_message(ngx_rtmp_session_t *s, ngx_chain_t *out, "RTMP drop message bufs=%ui, priority=%ui", nmsg, priority); - if (s->gop_cache.out[s->out_last].set) { - ngx_rtmp_gop_cache_exec_handler(s, s->out_last, out); - } - return NGX_AGAIN; } diff --git a/ngx_rtmp_init.c b/ngx_rtmp_init.c index c6660c4..ef32d1a 100644 --- a/ngx_rtmp_init.c +++ b/ngx_rtmp_init.c @@ -12,11 +12,8 @@ static void ngx_rtmp_close_connection(ngx_connection_t *c); - static void ngx_rtmp_process_unix_socket(ngx_rtmp_connection_t *rconn); -extern ngx_module_t ngx_rtmp_auto_push_module; - void ngx_rtmp_init_connection(ngx_connection_t *c) @@ -167,8 +164,7 @@ ngx_rtmp_init_session(ngx_connection_t *c, ngx_rtmp_addr_conf_t *addr_conf) s = ngx_pcalloc(c->pool, sizeof(ngx_rtmp_session_t)); if (s == NULL) { - ngx_rtmp_close_connection(c); - return NULL; + goto failed; } s->rtmp_connection = c->data; @@ -183,8 +179,7 @@ ngx_rtmp_init_session(ngx_connection_t *c, ngx_rtmp_addr_conf_t *addr_conf) ctx = ngx_palloc(c->pool, sizeof(ngx_rtmp_error_log_ctx_t)); if (ctx == NULL) { - ngx_rtmp_close_connection(c); - return NULL; + goto failed; } ctx->client = &c->addr_text; @@ -199,14 +194,12 @@ ngx_rtmp_init_session(ngx_connection_t *c, ngx_rtmp_addr_conf_t *addr_conf) s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_rtmp_max_module); if (s->ctx == NULL) { - ngx_rtmp_close_connection(c); - return NULL; + goto failed; } s->out_pool = ngx_create_pool(4096, c->log); if (s->out_pool == NULL) { - ngx_rtmp_close_connection(c); - return NULL; + goto failed; } s->out = ngx_pcalloc(s->out_pool, sizeof(ngx_chain_t *) @@ -214,24 +207,12 @@ ngx_rtmp_init_session(ngx_connection_t *c, ngx_rtmp_addr_conf_t *addr_conf) addr_conf->default_server->ctx->srv_conf [ngx_rtmp_core_module.ctx_index])->out_queue); if (s->out == NULL) { - ngx_rtmp_close_connection(c); - return NULL; - } - - s->gop_cache.out = ngx_pcalloc(s->out_pool, - sizeof(ngx_rtmp_gop_cache_free_t) - * ((ngx_rtmp_core_srv_conf_t *) - addr_conf->default_server->ctx->srv_conf - [ngx_rtmp_core_module.ctx_index])->out_queue); - if (s->gop_cache.out == NULL) { - ngx_rtmp_close_connection(c); - return NULL; + goto failed; } s->in_streams_pool = ngx_create_pool(4096, c->log); if (s->in_streams_pool == NULL) { - ngx_rtmp_close_connection(c); - return NULL; + goto failed; } cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); @@ -241,8 +222,7 @@ ngx_rtmp_init_session(ngx_connection_t *c, ngx_rtmp_addr_conf_t *addr_conf) s->in_streams = ngx_pcalloc(s->in_streams_pool, sizeof(ngx_rtmp_stream_t) * cscf->max_streams); if (s->in_streams == NULL) { - ngx_rtmp_close_connection(c); - return NULL; + goto failed; } #if (nginx_version >= 1007005) @@ -252,7 +232,6 @@ ngx_rtmp_init_session(ngx_connection_t *c, ngx_rtmp_addr_conf_t *addr_conf) s->epoch = ngx_current_msec; s->timeout = cscf->timeout; s->buflen = cscf->buflen; - s->gop_cache.count = 0; ngx_rtmp_set_chunk_size(s, NGX_RTMP_DEFAULT_CHUNK_SIZE); @@ -262,6 +241,20 @@ ngx_rtmp_init_session(ngx_connection_t *c, ngx_rtmp_addr_conf_t *addr_conf) } return s; + +failed: + if (s->out_pool) { + ngx_destroy_pool(s->out_pool); + s->out_pool = NULL; + } + + if (s->in_streams_pool) { + ngx_destroy_pool(s->in_streams_pool); + s->in_streams_pool = NULL; + } + + ngx_rtmp_close_connection(c); + return NULL; } @@ -346,9 +339,7 @@ ngx_rtmp_close_session_handler(ngx_event_t *e) ngx_rtmp_free_handshake_buffers(s); while (s->out_pos != s->out_last) { - if (!s->gop_cache.out[s->out_pos].set) { - ngx_rtmp_free_shared_chain(cscf, s->out[s->out_pos]); - } + ngx_rtmp_free_shared_chain(cscf, s->out[s->out_pos]); s->out_pos++; s->out_pos %= s->out_queue; diff --git a/ngx_rtmp_live_module.c b/ngx_rtmp_live_module.c index 16a1234..c40d76c 100644 --- a/ngx_rtmp_live_module.c +++ b/ngx_rtmp_live_module.c @@ -11,7 +11,6 @@ #include "ngx_rtmp_live_module.h" #include "ngx_rtmp_cmd_module.h" #include "ngx_rtmp_codec_module.h" -#include "ngx_rtmp_gop_cache_module.h" #include "ngx_http_flv_live_module.h" @@ -32,7 +31,8 @@ static char *ngx_rtmp_live_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, static void ngx_rtmp_live_start(ngx_rtmp_session_t *s); static void ngx_rtmp_live_stop(ngx_rtmp_session_t *s); - +static ngx_int_t ngx_rtmp_live_send_message(ngx_rtmp_session_t *s, + ngx_chain_t *in, ngx_uint_t priority); static ngx_chain_t *ngx_rtmp_live_meta_message(ngx_rtmp_session_t *s, ngx_chain_t *in); static ngx_chain_t *ngx_rtmp_live_append_message(ngx_rtmp_session_t *s, @@ -59,7 +59,6 @@ ngx_rtmp_live_proc_handler_t ngx_rtmp_live_proc_handler = { extern ngx_rtmp_live_proc_handler_t *ngx_rtmp_live_proc_handlers [NGX_RTMP_PROTOCOL_HTTP + 1]; extern ngx_module_t ngx_http_flv_live_module; -extern ngx_module_t ngx_rtmp_gop_cache_module; static ngx_command_t ngx_rtmp_live_commands[] = { @@ -804,7 +803,6 @@ ngx_rtmp_live_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_rtmp_live_proc_handler_t *handler; ngx_rtmp_live_ctx_t *ctx, *pctx; ngx_rtmp_codec_ctx_t *codec_ctx; - ngx_rtmp_gop_cache_ctx_t *gctx; ngx_chain_t *header, *coheader; ngx_rtmp_live_app_conf_t *lacf; ngx_rtmp_session_t *ss; @@ -961,14 +959,6 @@ ngx_rtmp_live_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ss = pctx->session; cs = &pctx->cs[csidx]; - if (ss->gop_cache.count == 0) { - gctx = ngx_rtmp_get_module_ctx(ss, ngx_rtmp_gop_cache_module); - if (gctx && gctx->pool) { - ngx_destroy_pool(gctx->pool); - gctx->pool = NULL; - } - } - handler = ngx_rtmp_live_proc_handlers[pctx->protocol]; /* send metadata */ @@ -1026,20 +1016,22 @@ ngx_rtmp_live_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, continue; } - if (lacf->wait_video && h->type == NGX_RTMP_MSG_AUDIO && - !pctx->cs[0].active) - { - ngx_log_debug0(NGX_LOG_DEBUG_RTMP, ss->connection->log, 0, - "live: waiting for video"); - continue; - } + if (codec_ctx->video_codec_id) { + if (lacf->wait_video && h->type == NGX_RTMP_MSG_AUDIO && + !pctx->cs[0].active) + { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, ss->connection->log, 0, + "live: waiting for video"); + continue; + } - if (lacf->wait_key && prio != NGX_RTMP_VIDEO_KEY_FRAME && - (lacf->interleave || h->type == NGX_RTMP_MSG_VIDEO)) - { - ngx_log_debug0(NGX_LOG_DEBUG_RTMP, ss->connection->log, 0, - "live: skip non-key"); - continue; + if (lacf->wait_key && prio != NGX_RTMP_VIDEO_KEY_FRAME && + (lacf->interleave || h->type == NGX_RTMP_MSG_VIDEO)) + { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, ss->connection->log, 0, + "live: skip non-key"); + continue; + } } if (header || coheader) { @@ -1188,6 +1180,7 @@ static ngx_int_t ngx_rtmp_live_data(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in, ngx_rtmp_amf_elt_t *out_elts, ngx_uint_t out_elts_size) { + ngx_rtmp_live_proc_handler_t *handler; ngx_rtmp_live_ctx_t *ctx, *pctx; ngx_chain_t *data, *rpkt; ngx_rtmp_core_srv_conf_t *cscf; @@ -1200,6 +1193,7 @@ ngx_rtmp_live_data(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_uint_t peers; uint32_t delta; ngx_rtmp_live_chunk_stream_t *cs; + ngx_http_request_t *r; #ifdef NGX_DEBUG u_char *msg_type; @@ -1264,7 +1258,6 @@ ngx_rtmp_live_data(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, delta = ch.timestamp - cs->timestamp; rpkt = ngx_rtmp_append_shared_bufs(cscf, data, in); - ngx_rtmp_prepare_message(s, &ch, NULL, rpkt); for (pctx = ctx->stream->ctx; pctx; pctx = pctx->next) { if (pctx == ctx || pctx->paused) { @@ -1272,11 +1265,35 @@ ngx_rtmp_live_data(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, } ss = pctx->session; + handler = ngx_rtmp_live_proc_handlers[pctx->protocol]; + if (pctx->protocol == NGX_RTMP_PROTOCOL_HTTP) { + r = ss->data; + if (r == NULL || (r->connection && r->connection->destroyed)) { + continue; + } - if (ngx_rtmp_send_message(ss, rpkt, prio) != NGX_OK) { - ++pctx->ndropped; - cs->dropped += delta; - continue; + handler->meta = handler->append_message_pt(ss, &ch, NULL, rpkt); + if (handler->meta == NULL) { + continue; + } + + if (handler->send_message_pt(ss, handler->meta, 0) != NGX_OK) { + ++pctx->ndropped; + cs->dropped += delta; + handler->free_message_pt(ss, handler->meta); + handler->meta = NULL; + continue; + } + + handler->free_message_pt(ss, handler->meta); + handler->meta = NULL; + } else { + ngx_rtmp_prepare_message(s, &ch, NULL, rpkt); + if (ngx_rtmp_send_message(ss, rpkt, prio) != NGX_OK) { + ++pctx->ndropped; + cs->dropped += delta; + continue; + } } cs->timestamp += delta; @@ -1504,16 +1521,8 @@ ngx_rtmp_live_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v) /* request from http */ r = s->data; if (r) { - if (s->wait_notify_play) { - if (ngx_http_flv_live_join(s, v->name, 0) == NGX_ERROR) { - r->main->count--; - - return NGX_ERROR; - } - - s->wait_notify_play = 0; - } - + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "live: play from HTTP"); goto next; } } diff --git a/ngx_rtmp_live_module.h b/ngx_rtmp_live_module.h index ea30d35..39591e1 100644 --- a/ngx_rtmp_live_module.h +++ b/ngx_rtmp_live_module.h @@ -86,8 +86,6 @@ extern ngx_module_t ngx_rtmp_live_module; ngx_rtmp_live_stream_t **ngx_rtmp_live_get_stream(ngx_rtmp_session_t *s, u_char *name, int create); -ngx_int_t ngx_rtmp_live_send_message(ngx_rtmp_session_t *s, ngx_chain_t *in, - ngx_uint_t priority); #endif /* _NGX_RTMP_LIVE_H_INCLUDED_ */ diff --git a/ngx_rtmp_log_module.c b/ngx_rtmp_log_module.c index e609eec..38cb49b 100644 --- a/ngx_rtmp_log_module.c +++ b/ngx_rtmp_log_module.c @@ -1,6 +1,7 @@ /* * Copyright (C) Roman Arutyunyan + * Copyright (C) Winshining */ @@ -70,7 +71,8 @@ typedef struct { typedef struct { ngx_array_t *logs; /* ngx_rtmp_log_t */ ngx_uint_t off; - time_t interval; + ngx_msec_t interval; + size_t size; } ngx_rtmp_log_app_conf_t; @@ -81,6 +83,7 @@ typedef struct { typedef struct { + u_char *line; ngx_event_t ev; unsigned play:1; unsigned publish:1; @@ -112,11 +115,19 @@ static ngx_command_t ngx_rtmp_log_commands[] = { { ngx_string("log_interval"), NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, - ngx_conf_set_sec_slot, + ngx_conf_set_msec_slot, NGX_RTMP_APP_CONF_OFFSET, offsetof(ngx_rtmp_log_app_conf_t, interval), NULL }, + { + ngx_string("log_size"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_log_app_conf_t, size), + NULL + }, ngx_null_command }; @@ -588,7 +599,8 @@ ngx_rtmp_log_create_app_conf(ngx_conf_t *cf) return NULL; } - lacf->interval = NGX_CONF_UNSET; + lacf->interval = NGX_CONF_UNSET_MSEC; + lacf->size = NGX_CONF_UNSET_SIZE; return lacf; } @@ -603,7 +615,8 @@ ngx_rtmp_log_merge_app_conf(ngx_conf_t *cf, void *parent, void *child) ngx_rtmp_log_fmt_t *fmt; ngx_rtmp_log_t *log; - ngx_conf_merge_sec_value(conf->interval, prev->interval, 0); + ngx_conf_merge_msec_value(conf->interval, prev->interval, 0); + ngx_conf_merge_size_value(conf->size, prev->size, 1 * 1024 * 1024); if (conf->logs || conf->off) { return NGX_OK; @@ -920,6 +933,13 @@ ngx_rtmp_log_set_names(ngx_rtmp_session_t *s, u_char *name, u_char *args) return NULL; } + ctx->line = ngx_pcalloc(s->connection->pool, lacf->size); + if (ctx->line == NULL) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "failed to allocate buffer for log line"); + return NULL; + } + if (lacf->interval) { ctx->ev.handler = ngx_rtmp_log_split_output_handler; ctx->ev.log = s->connection->log; @@ -1032,8 +1052,9 @@ ngx_rtmp_log_flush(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_rtmp_log_app_conf_t *lacf; ngx_rtmp_log_t *log; ngx_rtmp_log_op_t *op; + ngx_rtmp_log_ctx_t *ctx; ngx_uint_t n, i; - u_char *line, *p; + u_char *p; size_t len; if (s->auto_pushed || s->relay) { @@ -1045,6 +1066,11 @@ ngx_rtmp_log_flush(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, return NGX_OK; } + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_log_module); + if (ctx == NULL) { + return NGX_OK; + } + log = lacf->logs->elts; for (i = 0; i < lacf->logs->nelts; ++i, ++log) { @@ -1057,25 +1083,28 @@ ngx_rtmp_log_flush(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, len = 0; op = log->format->ops->elts; for (n = 0; n < log->format->ops->nelts; ++n, ++op) { - len += op->getlen(s, op); + if (len + NGX_LINEFEED_SIZE <= lacf->size) { + len += op->getlen(s, op); + } else { + break; + } } len += NGX_LINEFEED_SIZE; - line = ngx_palloc(s->connection->pool, len); - if (line == NULL) { - return NGX_OK; - } - - p = line; + p = ctx->line; op = log->format->ops->elts; for (n = 0; n < log->format->ops->nelts; ++n, ++op) { - p = op->getdata(s, p, op); + if (p + NGX_LINEFEED_SIZE <= ctx->line + lacf->size) { + p = op->getdata(s, p, op); + } else { + break; + } } ngx_linefeed(p); - ngx_rtmp_log_write(s, log, line, p - line); + ngx_rtmp_log_write(s, log, ctx->line, p - ctx->line); } return NGX_OK; @@ -1090,7 +1119,7 @@ ngx_rtmp_log_disconnect(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_rtmp_log_t *log; ngx_rtmp_log_op_t *op; ngx_uint_t n, i; - u_char *line, *p; + u_char *p; ngx_rtmp_log_ctx_t *ctx; size_t len; @@ -1103,6 +1132,11 @@ ngx_rtmp_log_disconnect(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, return NGX_OK; } + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_log_module); + if (ctx == NULL) { + return NGX_OK; + } + log = lacf->logs->elts; for (i = 0; i < lacf->logs->nelts; ++i, ++log) { @@ -1115,25 +1149,28 @@ ngx_rtmp_log_disconnect(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, len = 0; op = log->format->ops->elts; for (n = 0; n < log->format->ops->nelts; ++n, ++op) { - len += op->getlen(s, op); + if (len + NGX_LINEFEED_SIZE <= lacf->size) { + len += op->getlen(s, op); + } else { + break; + } } len += NGX_LINEFEED_SIZE; - line = ngx_palloc(s->connection->pool, len); - if (line == NULL) { - return NGX_OK; - } - - p = line; + p = ctx->line; op = log->format->ops->elts; for (n = 0; n < log->format->ops->nelts; ++n, ++op) { - p = op->getdata(s, p, op); + if (p + NGX_LINEFEED_SIZE <= ctx->line + lacf->size) { + p = op->getdata(s, p, op); + } else { + break; + } } ngx_linefeed(p); - ngx_rtmp_log_write(s, log, line, p - line); + ngx_rtmp_log_write(s, log, ctx->line, p - ctx->line); } ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_log_module); diff --git a/ngx_rtmp_netcall_module.c b/ngx_rtmp_netcall_module.c index f772c72..0925248 100644 --- a/ngx_rtmp_netcall_module.c +++ b/ngx_rtmp_netcall_module.c @@ -47,6 +47,7 @@ typedef struct ngx_rtmp_netcall_session_s { typedef struct { + ngx_uint_t nb_cs; ngx_rtmp_netcall_session_t *cs; } ngx_rtmp_netcall_ctx_t; @@ -198,6 +199,11 @@ ngx_rtmp_netcall_create(ngx_rtmp_session_t *s, ngx_rtmp_netcall_init_t *ci) return NGX_ERROR; } ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_netcall_module); + } else { + /* I don't know why? But it works! */ + if (ctx->nb_cs == 0) { + ctx->cs = NULL; + } } /* Create netcall pool, connection, session. @@ -271,6 +277,7 @@ ngx_rtmp_netcall_create(ngx_rtmp_session_t *s, ngx_rtmp_netcall_init_t *ci) if (!cs->detached) { cs->next = ctx->cs; ctx->cs = cs; + ctx->nb_cs++; } ngx_rtmp_netcall_send(cc->write); @@ -318,6 +325,7 @@ ngx_rtmp_netcall_close(ngx_connection_t *cc) for(css = &ctx->cs; *css; css = &((*css)->next)) { if (*css == cs) { *css = cs->next; + ctx->nb_cs--; break; } } diff --git a/ngx_rtmp_notify_module.c b/ngx_rtmp_notify_module.c index 9aa58b9..f28e015 100644 --- a/ngx_rtmp_notify_module.c +++ b/ngx_rtmp_notify_module.c @@ -1,18 +1,19 @@ /* * Copyright (C) Roman Arutyunyan + * Copyright (C) Winshining */ #include #include #include +#include #include "ngx_rtmp.h" #include "ngx_rtmp_cmd_module.h" #include "ngx_rtmp_netcall_module.h" #include "ngx_rtmp_record_module.h" #include "ngx_rtmp_relay_module.h" -#include "ngx_rtmp_notify_module.h" static ngx_rtmp_connect_pt next_connect; @@ -48,6 +49,42 @@ ngx_str_t ngx_rtmp_notify_urlencoded = #define NGX_RTMP_NOTIFY_PLAYING 0x02 +enum { + NGX_RTMP_NOTIFY_CONNECT, + NGX_RTMP_NOTIFY_DISCONNECT, + NGX_RTMP_NOTIFY_SRV_MAX +}; + + +enum { + NGX_RTMP_NOTIFY_PLAY, + NGX_RTMP_NOTIFY_PUBLISH, + NGX_RTMP_NOTIFY_PLAY_DONE, + NGX_RTMP_NOTIFY_PUBLISH_DONE, + NGX_RTMP_NOTIFY_DONE, + NGX_RTMP_NOTIFY_RECORD_DONE, + NGX_RTMP_NOTIFY_UPDATE, + NGX_RTMP_NOTIFY_APP_MAX +}; + + +typedef struct { + ngx_url_t *url[NGX_RTMP_NOTIFY_APP_MAX]; + ngx_flag_t active; + ngx_uint_t method; + ngx_msec_t update_timeout; + ngx_flag_t update_strict; + ngx_flag_t relay_redirect; + ngx_flag_t no_resolve; +} ngx_rtmp_notify_app_conf_t; + + +typedef struct { + ngx_url_t *url[NGX_RTMP_NOTIFY_SRV_MAX]; + ngx_uint_t method; +} ngx_rtmp_notify_srv_conf_t; + + typedef struct { ngx_uint_t flags; u_char name[NGX_RTMP_MAX_NAME]; @@ -157,6 +194,13 @@ static ngx_command_t ngx_rtmp_notify_commands[] = { offsetof(ngx_rtmp_notify_app_conf_t, relay_redirect), NULL }, + { ngx_string("notify_no_resolve"), + 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_notify_app_conf_t, no_resolve), + NULL }, + ngx_null_command }; @@ -208,6 +252,7 @@ ngx_rtmp_notify_create_app_conf(ngx_conf_t *cf) nacf->update_timeout = NGX_CONF_UNSET_MSEC; nacf->update_strict = NGX_CONF_UNSET; nacf->relay_redirect = NGX_CONF_UNSET; + nacf->no_resolve = NGX_CONF_UNSET; return nacf; } @@ -237,6 +282,7 @@ ngx_rtmp_notify_merge_app_conf(ngx_conf_t *cf, void *parent, void *child) 30000); ngx_conf_merge_value(conf->update_strict, prev->update_strict, 0); ngx_conf_merge_value(conf->relay_redirect, prev->relay_redirect, 0); + ngx_conf_merge_value(conf->no_resolve, prev->no_resolve, 1); return NGX_CONF_OK; } @@ -926,11 +972,13 @@ static ngx_int_t ngx_rtmp_notify_connect_handle(ngx_rtmp_session_t *s, void *arg, ngx_chain_t *in) { - ngx_rtmp_connect_t *v = arg; - ngx_int_t rc; - u_char app[NGX_RTMP_MAX_NAME]; + ngx_rtmp_connect_t *v = arg; + ngx_http_request_t *r; + ngx_int_t rc; + u_char app[NGX_RTMP_MAX_NAME]; - static ngx_str_t location = ngx_string("location"); + static ngx_rtmp_play_t p; + static ngx_str_t location = ngx_string("location"); rc = ngx_rtmp_notify_parse_http_retcode(s, in); if (rc == NGX_ERROR) { @@ -950,7 +998,22 @@ ngx_rtmp_notify_connect_handle(ngx_rtmp_session_t *s, } } - return next_connect(s, v); + rc = next_connect(s, v); + if (rc == NGX_OK && s->notify_connect) { + r = s->data; + if (r) { + ngx_memzero(&p, sizeof(ngx_rtmp_play_t)); + ngx_memcpy(p.name, s->stream.data, s->stream.len); + ngx_memcpy(p.args, s->args.data, s->args.len); + r->main->count--; + + rc = ngx_rtmp_play(s, &p); + } + } + + s->notify_connect = 0; + + return rc; } @@ -1033,7 +1096,7 @@ ngx_rtmp_notify_publish_handle(ngx_rtmp_session_t *s, u->url.len = rc - 7; u->default_port = 1935; u->uri_part = 1; - u->no_resolve = 1; /* want ip here */ + u->no_resolve = nacf->no_resolve; /* want ip here */ if (ngx_parse_url(s->connection->pool, u) != NGX_OK) { ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, @@ -1059,10 +1122,20 @@ ngx_rtmp_notify_play_handle(ngx_rtmp_session_t *s, ngx_rtmp_relay_target_t target; ngx_url_t *u; ngx_rtmp_notify_app_conf_t *nacf; + ngx_http_request_t *r; u_char name[NGX_RTMP_MAX_NAME]; static ngx_str_t location = ngx_string("location"); + if (s->notify_play) { + s->notify_play = 0; + + r = s->data; + if (r) { + r->main->count--; + } + } + rc = ngx_rtmp_notify_parse_http_retcode(s, in); if (rc == NGX_ERROR) { ngx_rtmp_notify_clear_flag(s, NGX_RTMP_NOTIFY_PLAYING); @@ -1112,7 +1185,7 @@ ngx_rtmp_notify_play_handle(ngx_rtmp_session_t *s, u->url.len = rc - 7; u->default_port = 1935; u->uri_part = 1; - u->no_resolve = (s->wait_notify_play ? 0 : 1); /* want ip here */ + u->no_resolve = nacf->no_resolve; /* want ip here */ if (ngx_parse_url(s->connection->pool, u) != NGX_OK) { ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, @@ -1164,14 +1237,12 @@ ngx_rtmp_notify_update_handle(ngx_rtmp_session_t *s, static void ngx_rtmp_notify_update(ngx_event_t *e) { - ngx_connection_t *c; ngx_rtmp_session_t *s; ngx_rtmp_notify_app_conf_t *nacf; ngx_rtmp_netcall_init_t ci; ngx_url_t *url; - c = e->data; - s = c->data; + s = e->data; nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module); @@ -1240,7 +1311,7 @@ ngx_rtmp_notify_init(ngx_rtmp_session_t *s, e = &ctx->update_evt; - e->data = s->connection; + e->data = s; e->log = s->connection->log; e->handler = ngx_rtmp_notify_update; @@ -1281,6 +1352,8 @@ ngx_rtmp_notify_connect(ngx_rtmp_session_t *s, ngx_rtmp_connect_t *v) ci.arg = v; ci.argsize = sizeof(*v); + s->notify_connect = 1; + return ngx_rtmp_netcall_create(s, &ci); next: @@ -1398,6 +1471,8 @@ ngx_rtmp_notify_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v) ci.arg = v; ci.argsize = sizeof(*v); + s->notify_play = 1; + return ngx_rtmp_netcall_create(s, &ci); next: diff --git a/ngx_rtmp_notify_module.h b/ngx_rtmp_notify_module.h deleted file mode 100644 index ce1aa90..0000000 --- a/ngx_rtmp_notify_module.h +++ /dev/null @@ -1,49 +0,0 @@ - -/* - * Copyright (C) Winshining - */ - -#ifndef _NGX_RTMP_NOTIFY_H_INCLUDED_ -#define _NGX_RTMP_NOTIFY_H_INCLUDED_ - - -enum { - NGX_RTMP_NOTIFY_CONNECT, - NGX_RTMP_NOTIFY_DISCONNECT, - NGX_RTMP_NOTIFY_SRV_MAX -}; - - -enum { - NGX_RTMP_NOTIFY_PLAY, - NGX_RTMP_NOTIFY_PUBLISH, - NGX_RTMP_NOTIFY_PLAY_DONE, - NGX_RTMP_NOTIFY_PUBLISH_DONE, - NGX_RTMP_NOTIFY_DONE, - NGX_RTMP_NOTIFY_RECORD_DONE, - NGX_RTMP_NOTIFY_UPDATE, - NGX_RTMP_NOTIFY_APP_MAX -}; - - -typedef struct { - ngx_url_t *url[NGX_RTMP_NOTIFY_APP_MAX]; - ngx_flag_t active; - ngx_uint_t method; - ngx_msec_t update_timeout; - ngx_flag_t update_strict; - ngx_flag_t relay_redirect; -} ngx_rtmp_notify_app_conf_t; - - -typedef struct { - ngx_url_t *url[NGX_RTMP_NOTIFY_SRV_MAX]; - ngx_uint_t method; -} ngx_rtmp_notify_srv_conf_t; - - -extern ngx_module_t ngx_rtmp_notify_module; - - -#endif - diff --git a/ngx_rtmp_parse.c b/ngx_rtmp_parse.c index 9017ff9..617a0c8 100644 --- a/ngx_rtmp_parse.c +++ b/ngx_rtmp_parse.c @@ -1,8 +1,8 @@ /* * Copyright (C) Igor Sysoev - * Copyright (C) Nginx, Inc. - * Copyright (C) Winshining + * Copyright (C) Nginx, Inc. + * Copyright (C) Winshining */ diff --git a/ngx_rtmp_relay_module.c b/ngx_rtmp_relay_module.c index b5128eb..3da4626 100644 --- a/ngx_rtmp_relay_module.c +++ b/ngx_rtmp_relay_module.c @@ -1,6 +1,7 @@ /* * Copyright (C) Roman Arutyunyan + * Copyright (C) Winshining */ @@ -337,6 +338,9 @@ ngx_rtmp_relay_create_connection(ngx_rtmp_conf_ctx_t *cctx, ngx_str_t* name, ngx_int_t rc; ngx_str_t v, *uri; u_char *first, *last, *p; +#if (NGX_HAVE_UNIX_DOMAIN) + u_char *client; +#endif racf = ngx_rtmp_get_module_app_conf(cctx, ngx_rtmp_relay_module); @@ -461,7 +465,25 @@ ngx_rtmp_relay_create_connection(ngx_rtmp_conf_ctx_t *cctx, ngx_str_t* name, } c = pc->connection; c->pool = pool; - c->addr_text = rctx->url; + +#if (NGX_HAVE_UNIX_DOMAIN) + if (addr->sockaddr->sa_family == AF_UNIX) { + client = ngx_pcalloc(pool, rctx->url.len + 8); + if (client == NULL) { + goto clear; + } + + *ngx_cpymem(client, rctx->url.data, + ngx_strlen(rctx->url.data)) = 0; + + p = (u_char *) ngx_strchr(client, '.'); + *ngx_snprintf(p + 1, client + rctx->url.len + 8 - (p + 1), "%i", + ngx_process_slot) = 0; + + c->addr_text.data = client; + c->addr_text.len = ngx_strlen(client); + } +#endif addr_conf = ngx_pcalloc(pool, sizeof(ngx_rtmp_addr_conf_t)); if (addr_conf == NULL) { @@ -1441,7 +1463,7 @@ static void ngx_rtmp_relay_close(ngx_rtmp_session_t *s) { ngx_rtmp_relay_app_conf_t *racf; - ngx_rtmp_relay_ctx_t *ctx, **cctx; + ngx_rtmp_relay_ctx_t *ctx, **cctx, **next; ngx_uint_t hash; racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_relay_module); @@ -1511,12 +1533,17 @@ ngx_rtmp_relay_close(ngx_rtmp_session_t *s) ngx_del_timer(&ctx->push_evt); } - for (cctx = &ctx->play; *cctx; cctx = &(*cctx)->next) { + for (cctx = &ctx->play; *cctx; /* cctx = &(*cctx)->next */) { (*cctx)->publish = NULL; ngx_log_debug2(NGX_LOG_DEBUG_RTMP, (*cctx)->session->connection->log, 0, "relay: play disconnect orphan app='%V' name='%V'", &(*cctx)->app, &(*cctx)->name); + + next = &(*cctx)->next; + ngx_rtmp_finalize_session((*cctx)->session); + + cctx = next; } ctx->publish = NULL; diff --git a/ngx_rtmp_script.c b/ngx_rtmp_script.c deleted file mode 100644 index 86a4fc7..0000000 --- a/ngx_rtmp_script.c +++ /dev/null @@ -1,1257 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Nginx, Inc. - * Copyright (C) Winshining - */ - - -#include -#include -#include "ngx_rtmp.h" - - -static ngx_int_t ngx_rtmp_script_init_arrays(ngx_rtmp_script_compile_t *sc); -static ngx_int_t ngx_rtmp_script_done(ngx_rtmp_script_compile_t *sc); -static ngx_int_t ngx_rtmp_script_add_copy_code(ngx_rtmp_script_compile_t *sc, - ngx_str_t *value, ngx_uint_t last); -static ngx_int_t ngx_rtmp_script_add_var_code(ngx_rtmp_script_compile_t *sc, - ngx_str_t *name); -static ngx_int_t ngx_rtmp_script_add_args_code(ngx_rtmp_script_compile_t *sc); -#if (NGX_PCRE) -static ngx_int_t ngx_rtmp_script_add_capture_code(ngx_rtmp_script_compile_t *sc, - ngx_uint_t n); -#endif -static ngx_int_t - ngx_rtmp_script_add_full_name_code(ngx_rtmp_script_compile_t *sc); -static size_t ngx_rtmp_script_full_name_len_code(ngx_rtmp_script_engine_t *e); -static void ngx_rtmp_script_full_name_code(ngx_rtmp_script_engine_t *e); - - -#define ngx_rtmp_script_exit (u_char *) &ngx_rtmp_script_exit_code - -static uintptr_t ngx_rtmp_script_exit_code = (uintptr_t) NULL; - - -void -ngx_rtmp_script_flush_complex_value(ngx_rtmp_session_t *s, - ngx_rtmp_complex_value_t *val) -{ - ngx_uint_t *index; - - index = val->flushes; - - if (index) { - while (*index != (ngx_uint_t) -1) { - - if (s->variables[*index].no_cacheable) { - s->variables[*index].valid = 0; - s->variables[*index].not_found = 0; - } - - index++; - } - } -} - - -ngx_int_t -ngx_rtmp_complex_value(ngx_rtmp_session_t *s, ngx_rtmp_complex_value_t *val, - ngx_str_t *value) -{ - size_t len; - ngx_rtmp_script_code_pt code; - ngx_rtmp_script_len_code_pt lcode; - ngx_rtmp_script_engine_t e; - - if (val->lengths == NULL) { - *value = val->value; - return NGX_OK; - } - - ngx_rtmp_script_flush_complex_value(s, val); - - ngx_memzero(&e, sizeof(ngx_rtmp_script_engine_t)); - - e.ip = val->lengths; - e.request = s; - e.flushed = 1; - - len = 0; - - while (*(uintptr_t *) e.ip) { - lcode = *(ngx_rtmp_script_len_code_pt *) e.ip; - len += lcode(&e); - } - - value->len = len; - value->data = ngx_pnalloc(s->connection->pool, len); - if (value->data == NULL) { - return NGX_ERROR; - } - - e.ip = val->values; - e.pos = value->data; - e.buf = *value; - - while (*(uintptr_t *) e.ip) { - code = *(ngx_rtmp_script_code_pt *) e.ip; - code((ngx_rtmp_script_engine_t *) &e); - } - - *value = e.buf; - - return NGX_OK; -} - - -ngx_int_t -ngx_rtmp_compile_complex_value(ngx_rtmp_compile_complex_value_t *ccv) -{ - ngx_str_t *v; - ngx_uint_t i, n, nv, nc; - ngx_array_t flushes, lengths, values, *pf, *pl, *pv; - ngx_rtmp_script_compile_t sc; - - v = ccv->value; - - nv = 0; - nc = 0; - - for (i = 0; i < v->len; i++) { - if (v->data[i] == '$') { - if (v->data[i + 1] >= '1' && v->data[i + 1] <= '9') { - nc++; - - } else { - nv++; - } - } - } - - if ((v->len == 0 || v->data[0] != '$') - && (ccv->conf_prefix || ccv->root_prefix)) - { - if (ngx_conf_full_name(ccv->cf->cycle, v, ccv->conf_prefix) != NGX_OK) { - return NGX_ERROR; - } - - ccv->conf_prefix = 0; - ccv->root_prefix = 0; - } - - ccv->complex_value->value = *v; - ccv->complex_value->flushes = NULL; - ccv->complex_value->lengths = NULL; - ccv->complex_value->values = NULL; - - if (nv == 0 && nc == 0) { - return NGX_OK; - } - - n = nv + 1; - - if (ngx_array_init(&flushes, ccv->cf->pool, n, sizeof(ngx_uint_t)) - != NGX_OK) - { - return NGX_ERROR; - } - - n = nv * (2 * sizeof(ngx_rtmp_script_copy_code_t) - + sizeof(ngx_rtmp_script_var_code_t)) - + sizeof(uintptr_t); - - if (ngx_array_init(&lengths, ccv->cf->pool, n, 1) != NGX_OK) { - return NGX_ERROR; - } - - n = (nv * (2 * sizeof(ngx_rtmp_script_copy_code_t) - + sizeof(ngx_rtmp_script_var_code_t)) - + sizeof(uintptr_t) - + v->len - + sizeof(uintptr_t) - 1) - & ~(sizeof(uintptr_t) - 1); - - if (ngx_array_init(&values, ccv->cf->pool, n, 1) != NGX_OK) { - return NGX_ERROR; - } - - pf = &flushes; - pl = &lengths; - pv = &values; - - ngx_memzero(&sc, sizeof(ngx_rtmp_script_compile_t)); - - sc.cf = ccv->cf; - sc.source = v; - sc.flushes = &pf; - sc.lengths = &pl; - sc.values = &pv; - sc.complete_lengths = 1; - sc.complete_values = 1; - sc.zero = ccv->zero; - sc.conf_prefix = ccv->conf_prefix; - sc.root_prefix = ccv->root_prefix; - - if (ngx_rtmp_script_compile(&sc) != NGX_OK) { - return NGX_ERROR; - } - - if (flushes.nelts) { - ccv->complex_value->flushes = flushes.elts; - ccv->complex_value->flushes[flushes.nelts] = (ngx_uint_t) -1; - } - - ccv->complex_value->lengths = lengths.elts; - ccv->complex_value->values = values.elts; - - return NGX_OK; -} - - -char * -ngx_rtmp_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - char *p = conf; - - ngx_str_t *value; - ngx_rtmp_complex_value_t **cv; - ngx_rtmp_compile_complex_value_t ccv; - - cv = (ngx_rtmp_complex_value_t **) (p + cmd->offset); - - if (*cv != NULL) { - return "duplicate"; - } - - *cv = ngx_palloc(cf->pool, sizeof(ngx_rtmp_complex_value_t)); - if (*cv == NULL) { - return NGX_CONF_ERROR; - } - - value = cf->args->elts; - - ngx_memzero(&ccv, sizeof(ngx_rtmp_compile_complex_value_t)); - - ccv.cf = cf; - ccv.value = &value[1]; - ccv.complex_value = *cv; - - if (ngx_rtmp_compile_complex_value(&ccv) != NGX_OK) { - return NGX_CONF_ERROR; - } - - return NGX_CONF_OK; -} - - -ngx_int_t -ngx_rtmp_test_predicates(ngx_rtmp_session_t *s, ngx_array_t *predicates) -{ - ngx_str_t val; - ngx_uint_t i; - ngx_rtmp_complex_value_t *cv; - - if (predicates == NULL) { - return NGX_OK; - } - - cv = predicates->elts; - - for (i = 0; i < predicates->nelts; i++) { - if (ngx_rtmp_complex_value(s, &cv[i], &val) != NGX_OK) { - return NGX_ERROR; - } - - if (val.len && (val.len != 1 || val.data[0] != '0')) { - return NGX_DECLINED; - } - } - - return NGX_OK; -} - - -char * -ngx_rtmp_set_predicate_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - char *p = conf; - - ngx_str_t *value; - ngx_uint_t i; - ngx_array_t **a; - ngx_rtmp_complex_value_t *cv; - ngx_rtmp_compile_complex_value_t ccv; - - a = (ngx_array_t **) (p + cmd->offset); - - if (*a == NGX_CONF_UNSET_PTR) { - *a = ngx_array_create(cf->pool, 1, sizeof(ngx_rtmp_complex_value_t)); - if (*a == NULL) { - return NGX_CONF_ERROR; - } - } - - value = cf->args->elts; - - for (i = 1; i < cf->args->nelts; i++) { - cv = ngx_array_push(*a); - if (cv == NULL) { - return NGX_CONF_ERROR; - } - - ngx_memzero(&ccv, sizeof(ngx_rtmp_compile_complex_value_t)); - - ccv.cf = cf; - ccv.value = &value[i]; - ccv.complex_value = cv; - - if (ngx_rtmp_compile_complex_value(&ccv) != NGX_OK) { - return NGX_CONF_ERROR; - } - } - - return NGX_CONF_OK; -} - - -ngx_uint_t -ngx_rtmp_script_variables_count(ngx_str_t *value) -{ - ngx_uint_t i, n; - - for (n = 0, i = 0; i < value->len; i++) { - if (value->data[i] == '$') { - n++; - } - } - - return n; -} - - -ngx_int_t -ngx_rtmp_script_compile(ngx_rtmp_script_compile_t *sc) -{ - u_char ch; - ngx_str_t name; - ngx_uint_t i, bracket; - - if (ngx_rtmp_script_init_arrays(sc) != NGX_OK) { - return NGX_ERROR; - } - - for (i = 0; i < sc->source->len; /* void */ ) { - - name.len = 0; - - if (sc->source->data[i] == '$') { - - if (++i == sc->source->len) { - goto invalid_variable; - } - - if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') { -#if (NGX_PCRE) - ngx_uint_t n; - - n = sc->source->data[i] - '0'; - - if (sc->captures_mask & ((ngx_uint_t) 1 << n)) { - sc->dup_capture = 1; - } - - sc->captures_mask |= (ngx_uint_t) 1 << n; - - if (ngx_rtmp_script_add_capture_code(sc, n) != NGX_OK) { - return NGX_ERROR; - } - - i++; - - continue; -#else - ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, - "using variable \"$%c\" requires " - "PCRE library", sc->source->data[i]); - return NGX_ERROR; -#endif - } - - if (sc->source->data[i] == '{') { - bracket = 1; - - if (++i == sc->source->len) { - goto invalid_variable; - } - - name.data = &sc->source->data[i]; - - } else { - bracket = 0; - name.data = &sc->source->data[i]; - } - - for ( /* void */ ; i < sc->source->len; i++, name.len++) { - ch = sc->source->data[i]; - - if (ch == '}' && bracket) { - i++; - bracket = 0; - break; - } - - if ((ch >= 'A' && ch <= 'Z') - || (ch >= 'a' && ch <= 'z') - || (ch >= '0' && ch <= '9') - || ch == '_') - { - continue; - } - - break; - } - - if (bracket) { - ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, - "the closing bracket in \"%V\" " - "variable is missing", &name); - return NGX_ERROR; - } - - if (name.len == 0) { - goto invalid_variable; - } - - sc->variables++; - - if (ngx_rtmp_script_add_var_code(sc, &name) != NGX_OK) { - return NGX_ERROR; - } - - continue; - } - - if (sc->source->data[i] == '?' && sc->compile_args) { - sc->args = 1; - sc->compile_args = 0; - - if (ngx_rtmp_script_add_args_code(sc) != NGX_OK) { - return NGX_ERROR; - } - - i++; - - continue; - } - - name.data = &sc->source->data[i]; - - while (i < sc->source->len) { - - if (sc->source->data[i] == '$') { - break; - } - - if (sc->source->data[i] == '?') { - - sc->args = 1; - - if (sc->compile_args) { - break; - } - } - - i++; - name.len++; - } - - sc->size += name.len; - - if (ngx_rtmp_script_add_copy_code(sc, &name, (i == sc->source->len)) - != NGX_OK) - { - return NGX_ERROR; - } - } - - return ngx_rtmp_script_done(sc); - -invalid_variable: - - ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, "invalid variable name"); - - return NGX_ERROR; -} - - -u_char * -ngx_rtmp_script_run(ngx_rtmp_session_t *s, ngx_str_t *value, - void *code_lengths, size_t len, void *code_values) -{ - ngx_uint_t i; - ngx_rtmp_script_code_pt code; - ngx_rtmp_script_len_code_pt lcode; - ngx_rtmp_script_engine_t e; - ngx_rtmp_core_main_conf_t *cmcf; - - cmcf = ngx_rtmp_get_module_main_conf(s, ngx_rtmp_core_module); - - for (i = 0; i < cmcf->variables.nelts; i++) { - if (s->variables[i].no_cacheable) { - s->variables[i].valid = 0; - s->variables[i].not_found = 0; - } - } - - ngx_memzero(&e, sizeof(ngx_rtmp_script_engine_t)); - - e.ip = code_lengths; - e.request = s; - e.flushed = 1; - - while (*(uintptr_t *) e.ip) { - lcode = *(ngx_rtmp_script_len_code_pt *) e.ip; - len += lcode(&e); - } - - - value->len = len; - value->data = ngx_pnalloc(s->connection->pool, len); - if (value->data == NULL) { - return NULL; - } - - e.ip = code_values; - e.pos = value->data; - - while (*(uintptr_t *) e.ip) { - code = *(ngx_rtmp_script_code_pt *) e.ip; - code((ngx_rtmp_script_engine_t *) &e); - } - - return e.pos; -} - - -void -ngx_rtmp_script_flush_no_cacheable_variables(ngx_rtmp_session_t *s, - ngx_array_t *indices) -{ - ngx_uint_t n, *index; - - if (indices) { - index = indices->elts; - for (n = 0; n < indices->nelts; n++) { - if (s->variables[index[n]].no_cacheable) { - s->variables[index[n]].valid = 0; - s->variables[index[n]].not_found = 0; - } - } - } -} - - -static ngx_int_t -ngx_rtmp_script_init_arrays(ngx_rtmp_script_compile_t *sc) -{ - ngx_uint_t n; - - if (sc->flushes && *sc->flushes == NULL) { - n = sc->variables ? sc->variables : 1; - *sc->flushes = ngx_array_create(sc->cf->pool, n, sizeof(ngx_uint_t)); - if (*sc->flushes == NULL) { - return NGX_ERROR; - } - } - - if (*sc->lengths == NULL) { - n = sc->variables * (2 * sizeof(ngx_rtmp_script_copy_code_t) - + sizeof(ngx_rtmp_script_var_code_t)) - + sizeof(uintptr_t); - - *sc->lengths = ngx_array_create(sc->cf->pool, n, 1); - if (*sc->lengths == NULL) { - return NGX_ERROR; - } - } - - if (*sc->values == NULL) { - n = (sc->variables * (2 * sizeof(ngx_rtmp_script_copy_code_t) - + sizeof(ngx_rtmp_script_var_code_t)) - + sizeof(uintptr_t) - + sc->source->len - + sizeof(uintptr_t) - 1) - & ~(sizeof(uintptr_t) - 1); - - *sc->values = ngx_array_create(sc->cf->pool, n, 1); - if (*sc->values == NULL) { - return NGX_ERROR; - } - } - - sc->variables = 0; - - return NGX_OK; -} - - -static ngx_int_t -ngx_rtmp_script_done(ngx_rtmp_script_compile_t *sc) -{ - ngx_str_t zero; - uintptr_t *code; - - if (sc->zero) { - - zero.len = 1; - zero.data = (u_char *) "\0"; - - if (ngx_rtmp_script_add_copy_code(sc, &zero, 0) != NGX_OK) { - return NGX_ERROR; - } - } - - if (sc->conf_prefix || sc->root_prefix) { - if (ngx_rtmp_script_add_full_name_code(sc) != NGX_OK) { - return NGX_ERROR; - } - } - - if (sc->complete_lengths) { - code = ngx_rtmp_script_add_code(*sc->lengths, sizeof(uintptr_t), NULL); - if (code == NULL) { - return NGX_ERROR; - } - - *code = (uintptr_t) NULL; - } - - if (sc->complete_values) { - code = ngx_rtmp_script_add_code(*sc->values, sizeof(uintptr_t), - &sc->main); - if (code == NULL) { - return NGX_ERROR; - } - - *code = (uintptr_t) NULL; - } - - return NGX_OK; -} - - -void * -ngx_rtmp_script_start_code(ngx_pool_t *pool, ngx_array_t **codes, size_t size) -{ - if (*codes == NULL) { - *codes = ngx_array_create(pool, 256, 1); - if (*codes == NULL) { - return NULL; - } - } - - return ngx_array_push_n(*codes, size); -} - - -void * -ngx_rtmp_script_add_code(ngx_array_t *codes, size_t size, void *code) -{ - u_char *elts, **p; - void *new; - - elts = codes->elts; - - new = ngx_array_push_n(codes, size); - if (new == NULL) { - return NULL; - } - - if (code) { - if (elts != codes->elts) { - p = code; - *p += (u_char *) codes->elts - elts; - } - } - - return new; -} - - -static ngx_int_t -ngx_rtmp_script_add_copy_code(ngx_rtmp_script_compile_t *sc, ngx_str_t *value, - ngx_uint_t last) -{ - u_char *p; - size_t size, len, zero; - ngx_rtmp_script_copy_code_t *code; - - zero = (sc->zero && last); - len = value->len + zero; - - code = ngx_rtmp_script_add_code(*sc->lengths, - sizeof(ngx_rtmp_script_copy_code_t), NULL); - if (code == NULL) { - return NGX_ERROR; - } - - code->code = (ngx_rtmp_script_code_pt) ngx_rtmp_script_copy_len_code; - code->len = len; - - size = (sizeof(ngx_rtmp_script_copy_code_t) + len + sizeof(uintptr_t) - 1) - & ~(sizeof(uintptr_t) - 1); - - code = ngx_rtmp_script_add_code(*sc->values, size, &sc->main); - if (code == NULL) { - return NGX_ERROR; - } - - code->code = ngx_rtmp_script_copy_code; - code->len = len; - - p = ngx_cpymem((u_char *) code + sizeof(ngx_rtmp_script_copy_code_t), - value->data, value->len); - - if (zero) { - *p = '\0'; - sc->zero = 0; - } - - return NGX_OK; -} - - -size_t -ngx_rtmp_script_copy_len_code(ngx_rtmp_script_engine_t *e) -{ - ngx_rtmp_script_copy_code_t *code; - - code = (ngx_rtmp_script_copy_code_t *) e->ip; - - e->ip += sizeof(ngx_rtmp_script_copy_code_t); - - return code->len; -} - - -void -ngx_rtmp_script_copy_code(ngx_rtmp_script_engine_t *e) -{ - u_char *p; - ngx_rtmp_script_copy_code_t *code; - - code = (ngx_rtmp_script_copy_code_t *) e->ip; - - p = e->pos; - - if (!e->skip) { - e->pos = ngx_copy(p, e->ip + sizeof(ngx_rtmp_script_copy_code_t), - code->len); - } - - e->ip += sizeof(ngx_rtmp_script_copy_code_t) - + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1)); - - ngx_log_debug2(NGX_LOG_DEBUG_RTMP, e->request->connection->log, 0, - "rtmp script copy: \"%*s\"", e->pos - p, p); -} - - -static ngx_int_t -ngx_rtmp_script_add_var_code(ngx_rtmp_script_compile_t *sc, ngx_str_t *name) -{ - ngx_int_t index, *p; - ngx_rtmp_script_var_code_t *code; - - index = ngx_rtmp_get_variable_index(sc->cf, name); - - if (index == NGX_ERROR) { - return NGX_ERROR; - } - - if (sc->flushes) { - p = ngx_array_push(*sc->flushes); - if (p == NULL) { - return NGX_ERROR; - } - - *p = index; - } - - code = ngx_rtmp_script_add_code(*sc->lengths, - sizeof(ngx_rtmp_script_var_code_t), NULL); - if (code == NULL) { - return NGX_ERROR; - } - - code->code = (ngx_rtmp_script_code_pt) ngx_rtmp_script_copy_var_len_code; - code->index = (uintptr_t) index; - - code = ngx_rtmp_script_add_code(*sc->values, - sizeof(ngx_rtmp_script_var_code_t), - &sc->main); - if (code == NULL) { - return NGX_ERROR; - } - - code->code = ngx_rtmp_script_copy_var_code; - code->index = (uintptr_t) index; - - return NGX_OK; -} - - -size_t -ngx_rtmp_script_copy_var_len_code(ngx_rtmp_script_engine_t *e) -{ - ngx_rtmp_variable_value_t *value; - ngx_rtmp_script_var_code_t *code; - - code = (ngx_rtmp_script_var_code_t *) e->ip; - - e->ip += sizeof(ngx_rtmp_script_var_code_t); - - if (e->flushed) { - value = ngx_rtmp_get_indexed_variable(e->request, code->index); - - } else { - value = ngx_rtmp_get_flushed_variable(e->request, code->index); - } - - if (value && !value->not_found) { - return value->len; - } - - return 0; -} - - -void -ngx_rtmp_script_copy_var_code(ngx_rtmp_script_engine_t *e) -{ - u_char *p; - ngx_rtmp_variable_value_t *value; - ngx_rtmp_script_var_code_t *code; - - code = (ngx_rtmp_script_var_code_t *) e->ip; - - e->ip += sizeof(ngx_rtmp_script_var_code_t); - - if (!e->skip) { - - if (e->flushed) { - value = ngx_rtmp_get_indexed_variable(e->request, code->index); - - } else { - value = ngx_rtmp_get_flushed_variable(e->request, code->index); - } - - if (value && !value->not_found) { - p = e->pos; - e->pos = ngx_copy(p, value->data, value->len); - - ngx_log_debug2(NGX_LOG_DEBUG_RTMP, - e->request->connection->log, 0, - "rtmp script var: \"%*s\"", e->pos - p, p); - } - } -} - - -static ngx_int_t -ngx_rtmp_script_add_args_code(ngx_rtmp_script_compile_t *sc) -{ - uintptr_t *code; - - code = ngx_rtmp_script_add_code(*sc->lengths, sizeof(uintptr_t), NULL); - if (code == NULL) { - return NGX_ERROR; - } - - *code = (uintptr_t) ngx_rtmp_script_mark_args_code; - - code = ngx_rtmp_script_add_code(*sc->values, sizeof(uintptr_t), &sc->main); - if (code == NULL) { - return NGX_ERROR; - } - - *code = (uintptr_t) ngx_rtmp_script_start_args_code; - - return NGX_OK; -} - - -size_t -ngx_rtmp_script_mark_args_code(ngx_rtmp_script_engine_t *e) -{ - e->is_args = 1; - e->ip += sizeof(uintptr_t); - - return 1; -} - - -void -ngx_rtmp_script_start_args_code(ngx_rtmp_script_engine_t *e) -{ - ngx_log_debug0(NGX_LOG_DEBUG_RTMP, e->request->connection->log, 0, - "rtmp script args"); - - e->is_args = 1; - e->args = e->pos; - e->ip += sizeof(uintptr_t); -} - - -#if (NGX_PCRE) - -static ngx_int_t -ngx_rtmp_script_add_capture_code(ngx_rtmp_script_compile_t *sc, ngx_uint_t n) -{ - ngx_rtmp_script_copy_capture_code_t *code; - - code = ngx_rtmp_script_add_code(*sc->lengths, - sizeof(ngx_rtmp_script_copy_capture_code_t), - NULL); - if (code == NULL) { - return NGX_ERROR; - } - - code->code = (ngx_rtmp_script_code_pt) - ngx_rtmp_script_copy_capture_len_code; - code->n = 2 * n; - - - code = ngx_rtmp_script_add_code(*sc->values, - sizeof(ngx_rtmp_script_copy_capture_code_t), - &sc->main); - if (code == NULL) { - return NGX_ERROR; - } - - code->code = ngx_rtmp_script_copy_capture_code; - code->n = 2 * n; - - if (sc->ncaptures < n) { - sc->ncaptures = n; - } - - return NGX_OK; -} - - -size_t -ngx_rtmp_script_copy_capture_len_code(ngx_rtmp_script_engine_t *e) -{ - int *cap; - u_char *p; - ngx_uint_t n; - ngx_rtmp_session_t *s; - ngx_rtmp_script_copy_capture_code_t *code; - - s = e->request; - - code = (ngx_rtmp_script_copy_capture_code_t *) e->ip; - - e->ip += sizeof(ngx_rtmp_script_copy_capture_code_t); - - n = code->n; - - if (n < s->ncaptures) { - - cap = s->captures; - - if ((e->is_args || e->quote) - && (e->request->quoted_uri || e->request->plus_in_uri)) - { - p = s->captures_data; - - return cap[n + 1] - cap[n] - + 2 * ngx_escape_uri(NULL, &p[cap[n]], cap[n + 1] - cap[n], - NGX_ESCAPE_ARGS); - } else { - return cap[n + 1] - cap[n]; - } - } - - return 0; -} - - -void -ngx_rtmp_script_copy_capture_code(ngx_rtmp_script_engine_t *e) -{ - int *cap; - u_char *p, *pos; - ngx_uint_t n; - ngx_rtmp_session_t *s; - ngx_rtmp_script_copy_capture_code_t *code; - - s = e->request; - - code = (ngx_rtmp_script_copy_capture_code_t *) e->ip; - - e->ip += sizeof(ngx_rtmp_script_copy_capture_code_t); - - n = code->n; - - pos = e->pos; - - if (n < s->ncaptures) { - - cap = s->captures; - p = s->captures_data; - - if ((e->is_args || e->quote) - && (e->request->quoted_uri || e->request->plus_in_uri)) - { - e->pos = (u_char *) ngx_escape_uri(pos, &p[cap[n]], - cap[n + 1] - cap[n], - NGX_ESCAPE_ARGS); - } else { - e->pos = ngx_copy(pos, &p[cap[n]], cap[n + 1] - cap[n]); - } - } - - ngx_log_debug2(NGX_LOG_DEBUG_RTMP, e->request->connection->log, 0, - "rtmp script capture: \"%*s\"", e->pos - pos, pos); -} - -#endif - - -static ngx_int_t -ngx_rtmp_script_add_full_name_code(ngx_rtmp_script_compile_t *sc) -{ - ngx_rtmp_script_full_name_code_t *code; - - code = ngx_rtmp_script_add_code(*sc->lengths, - sizeof(ngx_rtmp_script_full_name_code_t), - NULL); - if (code == NULL) { - return NGX_ERROR; - } - - code->code = (ngx_rtmp_script_code_pt) ngx_rtmp_script_full_name_len_code; - code->conf_prefix = sc->conf_prefix; - - code = ngx_rtmp_script_add_code(*sc->values, - sizeof(ngx_rtmp_script_full_name_code_t), - &sc->main); - if (code == NULL) { - return NGX_ERROR; - } - - code->code = ngx_rtmp_script_full_name_code; - code->conf_prefix = sc->conf_prefix; - - return NGX_OK; -} - - -static size_t -ngx_rtmp_script_full_name_len_code(ngx_rtmp_script_engine_t *e) -{ - ngx_rtmp_script_full_name_code_t *code; - - code = (ngx_rtmp_script_full_name_code_t *) e->ip; - - e->ip += sizeof(ngx_rtmp_script_full_name_code_t); - - return code->conf_prefix ? ngx_cycle->conf_prefix.len: - ngx_cycle->prefix.len; -} - - -static void -ngx_rtmp_script_full_name_code(ngx_rtmp_script_engine_t *e) -{ - ngx_rtmp_script_full_name_code_t *code; - - ngx_str_t value; - -#if (nginx_version >= 1005003) - ngx_str_t *prefix; -#endif - - code = (ngx_rtmp_script_full_name_code_t *) e->ip; - - value.data = e->buf.data; - value.len = e->pos - e->buf.data; - -#if (nginx_version >= 1005003) - prefix = code->conf_prefix ? (ngx_str_t *) &ngx_cycle->conf_prefix: - (ngx_str_t *) &ngx_cycle->prefix; - - if (ngx_get_full_name(e->request->connection->pool, prefix, - &value) != NGX_OK) -#else - if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &value, - code->conf_prefix) != NGX_OK) -#endif - { - e->ip = ngx_rtmp_script_exit; - e->status = NGX_RTMP_INTERNAL_SERVER_ERROR; - return; - } - - e->buf = value; - - ngx_log_debug1(NGX_LOG_DEBUG_RTMP, e->request->connection->log, 0, - "rtmp script fullname: \"%V\"", &value); - - e->ip += sizeof(ngx_rtmp_script_full_name_code_t); -} - - -void -ngx_rtmp_script_complex_value_code(ngx_rtmp_script_engine_t *e) -{ - size_t len; - ngx_rtmp_script_engine_t le; - ngx_rtmp_script_len_code_pt lcode; - ngx_rtmp_script_complex_value_code_t *code; - - code = (ngx_rtmp_script_complex_value_code_t *) e->ip; - - e->ip += sizeof(ngx_rtmp_script_complex_value_code_t); - - ngx_log_debug0(NGX_LOG_DEBUG_RTMP, e->request->connection->log, 0, - "rtmp script complex value"); - - ngx_memzero(&le, sizeof(ngx_rtmp_script_engine_t)); - - le.ip = code->lengths->elts; - le.line = e->line; - le.request = e->request; - le.quote = e->quote; - - for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) { - lcode = *(ngx_rtmp_script_len_code_pt *) le.ip; - } - - e->buf.len = len; - e->buf.data = ngx_pnalloc(e->request->connection->pool, len); - if (e->buf.data == NULL) { - e->ip = ngx_rtmp_script_exit; - return; - } - - e->pos = e->buf.data; - - e->sp->len = e->buf.len; - e->sp->data = e->buf.data; - e->sp++; -} - - -void -ngx_rtmp_script_value_code(ngx_rtmp_script_engine_t *e) -{ - ngx_rtmp_script_value_code_t *code; - - code = (ngx_rtmp_script_value_code_t *) e->ip; - - e->ip += sizeof(ngx_rtmp_script_value_code_t); - - e->sp->len = code->text_len; - e->sp->data = (u_char *) code->text_data; - - ngx_log_debug1(NGX_LOG_DEBUG_RTMP, e->request->connection->log, 0, - "rtmp script value: \"%v\"", e->sp); - - e->sp++; -} - - -void -ngx_rtmp_script_set_var_code(ngx_rtmp_script_engine_t *e) -{ - ngx_rtmp_session_t *s; - ngx_rtmp_script_var_code_t *code; - - code = (ngx_rtmp_script_var_code_t *) e->ip; - - e->ip += sizeof(ngx_rtmp_script_var_code_t); - - s = e->request; - - e->sp--; - - s->variables[code->index].len = e->sp->len; - s->variables[code->index].valid = 1; - s->variables[code->index].no_cacheable = 0; - s->variables[code->index].not_found = 0; - s->variables[code->index].data = e->sp->data; - -#if (NGX_DEBUG) - { - ngx_rtmp_variable_t *v; - ngx_rtmp_core_main_conf_t *cmcf; - - cmcf = ngx_rtmp_get_module_main_conf(s, ngx_rtmp_core_module); - - v = cmcf->variables.elts; - - ngx_log_debug1(NGX_LOG_DEBUG_RTMP, e->request->connection->log, 0, - "rtmp script set $%V", &v[code->index].name); - } -#endif -} - - -void -ngx_rtmp_script_var_set_handler_code(ngx_rtmp_script_engine_t *e) -{ - ngx_rtmp_script_var_handler_code_t *code; - - ngx_log_debug0(NGX_LOG_DEBUG_RTMP, e->request->connection->log, 0, - "rtmp script set var handler"); - - code = (ngx_rtmp_script_var_handler_code_t *) e->ip; - - e->ip += sizeof(ngx_rtmp_script_var_handler_code_t); - - e->sp--; - - code->handler(e->request, e->sp, code->data); -} - - -void -ngx_rtmp_script_var_code(ngx_rtmp_script_engine_t *e) -{ - ngx_rtmp_variable_value_t *value; - ngx_rtmp_script_var_code_t *code; - - ngx_log_debug0(NGX_LOG_DEBUG_RTMP, e->request->connection->log, 0, - "rtmp script var"); - - code = (ngx_rtmp_script_var_code_t *) e->ip; - - e->ip += sizeof(ngx_rtmp_script_var_code_t); - - value = ngx_rtmp_get_flushed_variable(e->request, code->index); - - if (value && !value->not_found) { - ngx_log_debug1(NGX_LOG_DEBUG_RTMP, e->request->connection->log, 0, - "rtmp script var: \"%v\"", value); - - *e->sp = *value; - e->sp++; - - return; - } - - *e->sp = ngx_rtmp_variable_null_value; - e->sp++; -} - - -void -ngx_rtmp_script_nop_code(ngx_rtmp_script_engine_t *e) -{ - e->ip += sizeof(uintptr_t); -} - diff --git a/ngx_rtmp_script.h b/ngx_rtmp_script.h deleted file mode 100644 index fa21a41..0000000 --- a/ngx_rtmp_script.h +++ /dev/null @@ -1,216 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) Nginx, Inc. - * Copyright (C) Winshining - */ - - -#ifndef _NGX_RTMP_SCRIPT_H_INCLUDED_ -#define _NGX_RTMP_SCRIPT_H_INCLUDED_ - - -#include -#include -#include "ngx_rtmp.h" - - -typedef struct { - u_char *ip; - u_char *pos; - ngx_rtmp_variable_value_t *sp; - - ngx_str_t buf; - ngx_str_t line; - - /* the start of the rewritten arguments */ - u_char *args; - - unsigned flushed:1; - unsigned skip:1; - unsigned quote:1; - unsigned is_args:1; - unsigned log:1; - - ngx_int_t status; - ngx_rtmp_session_t *request; -} ngx_rtmp_script_engine_t; - - -typedef struct { - ngx_conf_t *cf; - ngx_str_t *source; - - ngx_array_t **flushes; - ngx_array_t **lengths; - ngx_array_t **values; - - ngx_uint_t variables; - ngx_uint_t ncaptures; - ngx_uint_t captures_mask; - ngx_uint_t size; - - void *main; - - unsigned compile_args:1; - unsigned complete_lengths:1; - unsigned complete_values:1; - unsigned zero:1; - unsigned conf_prefix:1; - unsigned root_prefix:1; - - unsigned dup_capture:1; - unsigned args:1; -} ngx_rtmp_script_compile_t; - - -typedef struct { - ngx_str_t value; - ngx_uint_t *flushes; - void *lengths; - void *values; -} ngx_rtmp_complex_value_t; - - -typedef struct { - ngx_conf_t *cf; - ngx_str_t *value; - ngx_rtmp_complex_value_t *complex_value; - - unsigned zero:1; - unsigned conf_prefix:1; - unsigned root_prefix:1; -} ngx_rtmp_compile_complex_value_t; - - -typedef void (*ngx_rtmp_script_code_pt) (ngx_rtmp_script_engine_t *e); -typedef size_t (*ngx_rtmp_script_len_code_pt) (ngx_rtmp_script_engine_t *e); - - -typedef struct { - ngx_rtmp_script_code_pt code; - uintptr_t len; -} ngx_rtmp_script_copy_code_t; - - -typedef struct { - ngx_rtmp_script_code_pt code; - uintptr_t index; -} ngx_rtmp_script_var_code_t; - - -typedef struct { - ngx_rtmp_script_code_pt code; - ngx_rtmp_set_variable_pt handler; - uintptr_t data; -} ngx_rtmp_script_var_handler_code_t; - - -typedef struct { - ngx_rtmp_script_code_pt code; - uintptr_t n; -} ngx_rtmp_script_copy_capture_code_t; - - -#if (NGX_PCRE) - -typedef struct { - ngx_rtmp_script_code_pt code; - ngx_rtmp_regex_t *regex; - ngx_array_t *lengths; - uintptr_t size; - uintptr_t status; - uintptr_t next; - - unsigned test:1; - unsigned negative_test:1; - unsigned uri:1; - unsigned args:1; - - /* add the s->args to the new arguments */ - unsigned add_args:1; - - unsigned redirect:1; - unsigned break_cycle:1; - - ngx_str_t name; -} ngx_rtmp_script_regex_code_t; - - -typedef struct { - ngx_rtmp_script_code_pt code; - - unsigned uri:1; - unsigned args:1; - - /* add the s->args to the new arguments */ - unsigned add_args:1; - - unsigned redirect:1; -} ngx_rtmp_script_regex_end_code_t; - -#endif - - -typedef struct { - ngx_rtmp_script_code_pt code; - uintptr_t conf_prefix; -} ngx_rtmp_script_full_name_code_t; - - -typedef struct { - ngx_rtmp_script_code_pt code; - ngx_array_t *lengths; -} ngx_rtmp_script_complex_value_code_t; - - -typedef struct { - ngx_rtmp_script_code_pt code; - uintptr_t value; - uintptr_t text_len; - uintptr_t text_data; -} ngx_rtmp_script_value_code_t; - - -void ngx_rtmp_script_flush_complex_value(ngx_rtmp_session_t *s, - ngx_rtmp_complex_value_t *val); -ngx_int_t ngx_rtmp_complex_value(ngx_rtmp_session_t *s, - ngx_rtmp_complex_value_t *val, ngx_str_t *value); -ngx_int_t ngx_rtmp_compile_complex_value(ngx_rtmp_compile_complex_value_t *ccv); -char *ngx_rtmp_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - - -ngx_int_t ngx_rtmp_test_predicates(ngx_rtmp_session_t *s, - ngx_array_t *predicates); -char *ngx_rtmp_set_predicate_slot(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - -ngx_uint_t ngx_rtmp_script_variables_count(ngx_str_t *value); -ngx_int_t ngx_rtmp_script_compile(ngx_rtmp_script_compile_t *sc); -u_char *ngx_rtmp_script_run(ngx_rtmp_session_t *s, ngx_str_t *value, - void *code_lengths, size_t reserved, void *code_values); -void ngx_rtmp_script_flush_no_cacheable_variables(ngx_rtmp_session_t *s, - ngx_array_t *indices); - -void *ngx_rtmp_script_start_code(ngx_pool_t *pool, ngx_array_t **codes, - size_t size); -void *ngx_rtmp_script_add_code(ngx_array_t *codes, size_t size, void *code); - -size_t ngx_rtmp_script_copy_len_code(ngx_rtmp_script_engine_t *e); -void ngx_rtmp_script_copy_code(ngx_rtmp_script_engine_t *e); -size_t ngx_rtmp_script_copy_var_len_code(ngx_rtmp_script_engine_t *e); -void ngx_rtmp_script_copy_var_code(ngx_rtmp_script_engine_t *e); -size_t ngx_rtmp_script_copy_capture_len_code(ngx_rtmp_script_engine_t *e); -void ngx_rtmp_script_copy_capture_code(ngx_rtmp_script_engine_t *e); -size_t ngx_rtmp_script_mark_args_code(ngx_rtmp_script_engine_t *e); -void ngx_rtmp_script_start_args_code(ngx_rtmp_script_engine_t *e); -void ngx_rtmp_script_complex_value_code(ngx_rtmp_script_engine_t *e); -void ngx_rtmp_script_value_code(ngx_rtmp_script_engine_t *e); -void ngx_rtmp_script_set_var_code(ngx_rtmp_script_engine_t *e); -void ngx_rtmp_script_var_set_handler_code(ngx_rtmp_script_engine_t *e); -void ngx_rtmp_script_var_code(ngx_rtmp_script_engine_t *e); -void ngx_rtmp_script_nop_code(ngx_rtmp_script_engine_t *e); - - -#endif /* _NGX_RTMP_SCRIPT_H_INCLUDED_ */ diff --git a/ngx_rtmp_stat_module.c b/ngx_rtmp_stat_module.c index 326a811..b31fde3 100644 --- a/ngx_rtmp_stat_module.c +++ b/ngx_rtmp_stat_module.c @@ -32,6 +32,9 @@ static time_t start_time; #define NGX_RTMP_STAT_CLIENTS 0x04 #define NGX_RTMP_STAT_PLAY 0x08 +#define NGX_RTMP_STAT_FORMAT_XML 0x01 +#define NGX_RTMP_STAT_FORMAT_JSON 0x02 + /* * global: stat-{bufs-{total,free,used}, total bytes in/out, bw in/out} - cscf */ @@ -40,6 +43,7 @@ static time_t start_time; typedef struct { ngx_uint_t stat; ngx_str_t stylesheet; + ngx_uint_t format; } ngx_rtmp_stat_loc_conf_t; @@ -51,6 +55,11 @@ static ngx_conf_bitmask_t ngx_rtmp_stat_masks[] = { { ngx_null_string, 0 } }; +static ngx_conf_bitmask_t ngx_rtmp_stat_format_masks[] = { + { ngx_string("xml"), NGX_RTMP_STAT_FORMAT_XML }, + { ngx_string("json"), NGX_RTMP_STAT_FORMAT_JSON }, + { ngx_null_string, 0 } +}; static ngx_command_t ngx_rtmp_stat_commands[] = { @@ -67,6 +76,13 @@ static ngx_command_t ngx_rtmp_stat_commands[] = { NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_rtmp_stat_loc_conf_t, stylesheet), NULL }, + + { ngx_string("rtmp_stat_format"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_rtmp_stat, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_rtmp_stat_loc_conf_t, format), + ngx_rtmp_stat_format_masks }, ngx_null_command }; @@ -158,6 +174,7 @@ ngx_rtmp_stat_escape(ngx_http_request_t *r, void *data, size_t len) return new_data; } + #if (NGX_WIN32) /* * Fix broken MSVC memcpy optimization for 4-byte data @@ -166,6 +183,7 @@ ngx_rtmp_stat_escape(ngx_http_request_t *r, void *data, size_t len) __declspec(noinline) #endif + static void ngx_rtmp_stat_output(ngx_http_request_t *r, ngx_chain_t ***lll, void *data, size_t len, ngx_uint_t escape) @@ -255,28 +273,47 @@ ngx_rtmp_stat_bw(ngx_http_request_t *r, ngx_chain_t ***lll, ngx_rtmp_bandwidth_t *bw, char *name, ngx_uint_t flags) { - u_char buf[NGX_INT64_LEN + 9]; + u_char buf[NGX_INT64_LEN + 9]; + ngx_rtmp_stat_loc_conf_t *slcf; + + slcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_stat_module); ngx_rtmp_update_bandwidth(bw, 0); if (flags & NGX_RTMP_STAT_BW) { - NGX_RTMP_STAT_L("%uLbandwidth * 8) - - buf); - NGX_RTMP_STAT_CS(name); - NGX_RTMP_STAT_L(">\r\n"); + if(slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L("%uLbandwidth * 8) + - buf); + NGX_RTMP_STAT_CS(name); + NGX_RTMP_STAT_L(">\r\n"); + } else { + NGX_RTMP_STAT_L("\"bw_"); + NGX_RTMP_STAT_CS(name); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), "\":%uL,", + bw->bandwidth * 8) + - buf); + } } if (flags & NGX_RTMP_STAT_BYTES) { - NGX_RTMP_STAT_L("%uLbytes) - - buf); - NGX_RTMP_STAT_CS(name); - NGX_RTMP_STAT_L(">\r\n"); + if(slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L("%uLbytes) + - buf); + NGX_RTMP_STAT_CS(name); + NGX_RTMP_STAT_L(">\r\n"); + } else { + NGX_RTMP_STAT_L("\"bytes_"); + NGX_RTMP_STAT_CS(name); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), "\":%uL,", + bw->bytes) + - buf); + } } } @@ -323,46 +360,81 @@ ngx_rtmp_stat_dump_pool(ngx_http_request_t *r, ngx_chain_t ***lll, #endif - static void ngx_rtmp_stat_client(ngx_http_request_t *r, ngx_chain_t ***lll, ngx_rtmp_session_t *s) { - u_char buf[NGX_INT_T_LEN]; + u_char buf[NGX_INT_T_LEN]; + ngx_rtmp_stat_loc_conf_t *slcf; + + slcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_stat_module); #ifdef NGX_RTMP_POOL_DEBUG ngx_rtmp_stat_dump_pool(r, lll, s->connection->pool); #endif - NGX_RTMP_STAT_L(""); - NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), "%ui", - (ngx_uint_t) s->connection->number) - buf); - NGX_RTMP_STAT_L(""); - NGX_RTMP_STAT_L("
"); - NGX_RTMP_STAT_ES(&s->connection->addr_text); - NGX_RTMP_STAT_L("
"); + if(slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), "%ui", + (ngx_uint_t) s->connection->number) - buf); + NGX_RTMP_STAT_L(""); + + NGX_RTMP_STAT_L("
"); + NGX_RTMP_STAT_ES(&s->connection->addr_text); + NGX_RTMP_STAT_L("
"); + + NGX_RTMP_STAT_L(""); + + if (s->flashver.len) { + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT_ES(&s->flashver); + NGX_RTMP_STAT_L(""); + } - NGX_RTMP_STAT_L(""); + if (s->page_url.len) { + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT_ES(&s->page_url); + NGX_RTMP_STAT_L(""); + } - if (s->flashver.len) { - NGX_RTMP_STAT_L(""); - NGX_RTMP_STAT_ES(&s->flashver); - NGX_RTMP_STAT_L(""); - } + if (s->swf_url.len) { + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT_ES(&s->swf_url); + NGX_RTMP_STAT_L(""); + } + } else { + NGX_RTMP_STAT_L("\"id\":"); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), "%ui", + (ngx_uint_t) s->connection->number) - buf); + + NGX_RTMP_STAT_L(",\"address\":\""); + NGX_RTMP_STAT_ES(&s->connection->addr_text); + + NGX_RTMP_STAT_L("\",\"time\":"); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), "%i", + (ngx_int_t) (ngx_current_msec - s->epoch)) - buf); + NGX_RTMP_STAT_L(","); + + if (s->flashver.len) { + NGX_RTMP_STAT_L("\"flashver\":\""); + NGX_RTMP_STAT_ES(&s->flashver); + NGX_RTMP_STAT_L("\","); + } - if (s->page_url.len) { - NGX_RTMP_STAT_L(""); - NGX_RTMP_STAT_ES(&s->page_url); - NGX_RTMP_STAT_L(""); - } + if (s->page_url.len) { + NGX_RTMP_STAT_L("\"pageurl\":\""); + NGX_RTMP_STAT_ES(&s->page_url); + NGX_RTMP_STAT_L("\","); + } - if (s->swf_url.len) { - NGX_RTMP_STAT_L(""); - NGX_RTMP_STAT_ES(&s->swf_url); - NGX_RTMP_STAT_L(""); + if (s->swf_url.len) { + NGX_RTMP_STAT_L("\"swfurl\":\""); + NGX_RTMP_STAT_ES(&s->swf_url); + NGX_RTMP_STAT_L("\","); + } } } @@ -417,6 +489,7 @@ ngx_rtmp_stat_live(ngx_http_request_t *r, ngx_chain_t ***lll, ngx_rtmp_session_t *s; ngx_int_t n; ngx_uint_t nclients, total_nclients; + ngx_uint_t f; u_char buf[NGX_INT_T_LEN]; u_char bbuf[NGX_INT32_LEN]; ngx_rtmp_stat_loc_conf_t *slcf; @@ -428,22 +501,48 @@ ngx_rtmp_stat_live(ngx_http_request_t *r, ngx_chain_t ***lll, slcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_stat_module); - NGX_RTMP_STAT_L("\r\n"); + if(slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L("\r\n"); + } else { + NGX_RTMP_STAT_L("\"live\":{"); + NGX_RTMP_STAT_L("\"streams\":["); + } total_nclients = 0; for (n = 0; n < lacf->nbuckets; ++n) { for (stream = lacf->streams[n]; stream; stream = stream->next) { - NGX_RTMP_STAT_L("\r\n"); - - NGX_RTMP_STAT_L(""); - NGX_RTMP_STAT_ECS(stream->name); - NGX_RTMP_STAT_L("\r\n"); + + if(total_nclients > 0) { + NGX_RTMP_STAT_L(","); + } + + if(slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L("\r\n"); + } else { + NGX_RTMP_STAT_L("{"); + } - NGX_RTMP_STAT_L(""); + if(slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT_ECS(stream->name); + NGX_RTMP_STAT_L("\r\n"); + + NGX_RTMP_STAT_L(""); + } else { + NGX_RTMP_STAT_L("\"name\":\""); + NGX_RTMP_STAT_ECS(stream->name); + NGX_RTMP_STAT_L("\","); + + NGX_RTMP_STAT_L("\"time\":"); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), "%i", + (ngx_int_t) (ngx_current_msec - stream->epoch)) + - buf); + NGX_RTMP_STAT_L(","); + } ngx_rtmp_stat_bw(r, lll, &stream->bw_in, "in", NGX_RTMP_STAT_BW_BYTES); @@ -456,148 +555,316 @@ ngx_rtmp_stat_live(ngx_http_request_t *r, ngx_chain_t ***lll, nclients = 0; codec = NULL; + + if (slcf->stat & NGX_RTMP_STAT_CLIENTS && slcf->format & NGX_RTMP_STAT_FORMAT_JSON) { + NGX_RTMP_STAT_L("\"clients\":["); + } + for (ctx = stream->ctx; ctx; ctx = ctx->next, ++nclients) { s = ctx->session; if (slcf->stat & NGX_RTMP_STAT_CLIENTS) { - NGX_RTMP_STAT_L(""); - + + if (slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L(""); + } else { + NGX_RTMP_STAT_L("{"); + } + ngx_rtmp_stat_client(r, lll, s); - - NGX_RTMP_STAT_L(""); - NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), - "%ui", ctx->ndropped) - buf); - NGX_RTMP_STAT_L(""); - - NGX_RTMP_STAT_L(""); - if (!lacf->interleave) { + + if (slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), + "%ui", ctx->ndropped) - buf); + NGX_RTMP_STAT_L(""); + + NGX_RTMP_STAT_L(""); + if (!lacf->interleave) { + NGX_RTMP_STAT(bbuf, ngx_snprintf(bbuf, sizeof(bbuf), + "%D", ctx->cs[1].timestamp - + ctx->cs[0].timestamp) - bbuf); + } + NGX_RTMP_STAT_L(""); + + NGX_RTMP_STAT_L(""); NGX_RTMP_STAT(bbuf, ngx_snprintf(bbuf, sizeof(bbuf), - "%D", ctx->cs[1].timestamp - - ctx->cs[0].timestamp) - bbuf); - } - NGX_RTMP_STAT_L(""); - - NGX_RTMP_STAT_L(""); - NGX_RTMP_STAT(bbuf, ngx_snprintf(bbuf, sizeof(bbuf), - "%D", s->current_time) - bbuf); - NGX_RTMP_STAT_L(""); - - if (ctx->publishing) { - NGX_RTMP_STAT_L(""); + "%D", s->current_time) - bbuf); + NGX_RTMP_STAT_L(""); + + if (ctx->publishing) { + NGX_RTMP_STAT_L(""); + } + + if (ctx->active) { + NGX_RTMP_STAT_L(""); + } + } else { + NGX_RTMP_STAT_L("\"dropped\":"); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), + "%ui", ctx->ndropped) - buf); + + NGX_RTMP_STAT_L(",\"avsync\":"); + if (!lacf->interleave) { + NGX_RTMP_STAT(bbuf, ngx_snprintf(bbuf, sizeof(bbuf), + "%D", ctx->cs[1].timestamp - + ctx->cs[0].timestamp) - bbuf); + } + + NGX_RTMP_STAT_L(",\"timestamp\":"); + NGX_RTMP_STAT(bbuf, ngx_snprintf(bbuf, sizeof(bbuf), + "%D", s->current_time) - bbuf); + + NGX_RTMP_STAT_L(",\"publishing\":"); + if (ctx->publishing) { + NGX_RTMP_STAT_L("true"); + } else { + NGX_RTMP_STAT_L("false"); + } + + NGX_RTMP_STAT_L(",\"active\":"); + if (ctx->active) { + NGX_RTMP_STAT_L("true"); + } else { + NGX_RTMP_STAT_L("false"); + } } - - if (ctx->active) { - NGX_RTMP_STAT_L(""); + + + if (slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L("\r\n"); + } else { + NGX_RTMP_STAT_L("}"); + if(ctx->next) { + NGX_RTMP_STAT_L(","); + } } - - NGX_RTMP_STAT_L("\r\n"); } if (ctx->publishing) { codec = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); } } total_nclients += nclients; - + + if (slcf->stat & NGX_RTMP_STAT_CLIENTS && slcf->format & NGX_RTMP_STAT_FORMAT_JSON) { + NGX_RTMP_STAT_L("],"); + } + if (codec) { - NGX_RTMP_STAT_L(""); + if(slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L(""); - NGX_RTMP_STAT_L(""); - - NGX_RTMP_STAT_L(""); + "%ui", codec->height) - buf); + NGX_RTMP_STAT_L(",\"frame_rate\":"); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), + "%ui", codec->frame_rate) - buf); - NGX_RTMP_STAT_L("\r\n"); - } + cname = ngx_rtmp_get_video_codec_name(codec->video_codec_id); + if (*cname) { + NGX_RTMP_STAT_L(",\"codec\":\""); + NGX_RTMP_STAT_ECS(cname); + } - NGX_RTMP_STAT_L(""); - NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), - "%ui", nclients) - buf); - NGX_RTMP_STAT_L("\r\n"); + if (codec->avc_profile) { + NGX_RTMP_STAT_L("\",\"profile\":\""); + NGX_RTMP_STAT_CS(ngx_rtmp_stat_get_avc_profile(codec->avc_profile)); - if (stream->publishing) { - NGX_RTMP_STAT_L("\r\n"); - } + } + if (codec->avc_compat) { + NGX_RTMP_STAT_L("\",\"compat\":\""); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), + "%ui", codec->avc_compat) - buf); + } + if (codec->avc_level) { + NGX_RTMP_STAT_L("\",\"level\":\""); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), + "%.1f", codec->avc_level / 10.) - buf); + } + NGX_RTMP_STAT_L("\""); - if (stream->active) { - NGX_RTMP_STAT_L("\r\n"); + + NGX_RTMP_STAT_L("}, \"audio\": {"); + cname = ngx_rtmp_get_audio_codec_name(codec->audio_codec_id); + f = 0; + if (*cname) { + f = 1; + NGX_RTMP_STAT_L("\"codec\":\""); + NGX_RTMP_STAT_ECS(cname); + } + if (codec->aac_profile) { + if(f == 1) NGX_RTMP_STAT_L("\","); + f = 2; + NGX_RTMP_STAT_L("\"profile\":\""); + NGX_RTMP_STAT_CS( + ngx_rtmp_stat_get_aac_profile(codec->aac_profile, + codec->aac_sbr, + codec->aac_ps)); + } + if (codec->aac_chan_conf) { + if(f >= 1) NGX_RTMP_STAT_L("\","); + f = 3; + NGX_RTMP_STAT_L("\"channels\":\""); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), + "%ui", codec->aac_chan_conf) - buf); + } else if (codec->audio_channels) { + if(f >= 1) NGX_RTMP_STAT_L("\","); + f = 3; + NGX_RTMP_STAT_L("\"channels\":\""); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), + "%ui", codec->audio_channels) - buf); + } + if (codec->sample_rate) { + if(f >= 1) NGX_RTMP_STAT_L("\","); + f = 4; + NGX_RTMP_STAT_L("\"sample_rate\":"); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), + "%ui", codec->sample_rate) - buf); + } + if (f >= 1 && f <= 3) { + NGX_RTMP_STAT_L("\""); + } + NGX_RTMP_STAT_L("}"); + + NGX_RTMP_STAT_L("}"); + } } + + if(slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), + "%ui", nclients) - buf); + NGX_RTMP_STAT_L("\r\n"); - NGX_RTMP_STAT_L("\r\n"); - } - } + if (stream->publishing) { + NGX_RTMP_STAT_L("\r\n"); + } + + if (stream->active) { + NGX_RTMP_STAT_L("\r\n"); + } - NGX_RTMP_STAT_L(""); - NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), - "%ui", total_nclients) - buf); - NGX_RTMP_STAT_L("\r\n"); + NGX_RTMP_STAT_L("\r\n"); + } else { + if(codec) { + NGX_RTMP_STAT_L(","); + } + NGX_RTMP_STAT_L("\"nclients\":"); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), + "%ui", nclients) - buf); + + NGX_RTMP_STAT_L(",\"publishing\":"); + if (stream->publishing) { + NGX_RTMP_STAT_L("true"); + } else { + NGX_RTMP_STAT_L("false"); + } + + NGX_RTMP_STAT_L(",\"active\":"); + if (stream->active) { + NGX_RTMP_STAT_L("true"); + } else { + NGX_RTMP_STAT_L("false"); + } - NGX_RTMP_STAT_L("\r\n"); + NGX_RTMP_STAT_L("}"); + } + } + } + + if(slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), + "%ui", total_nclients) - buf); + NGX_RTMP_STAT_L("\r\n"); + NGX_RTMP_STAT_L("\r\n"); + } else { + NGX_RTMP_STAT_L("],\"nclients\":"); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), + "%ui", total_nclients) - buf); + NGX_RTMP_STAT_L("}"); + } + } @@ -617,21 +884,33 @@ ngx_rtmp_stat_play(ngx_http_request_t *r, ngx_chain_t ***lll, } slcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_stat_module); - - NGX_RTMP_STAT_L("\r\n"); + + if(slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L("\r\n"); + } else { + NGX_RTMP_STAT_L("\"play\":{"); + NGX_RTMP_STAT_L("\"streams\":["); + } total_nclients = 0; for (n = 0; n < pacf->nbuckets; ++n) { for (ctx = pacf->ctx[n]; ctx; ) { - NGX_RTMP_STAT_L("\r\n"); - - NGX_RTMP_STAT_L(""); - NGX_RTMP_STAT_ECS(ctx->name); - NGX_RTMP_STAT_L("\r\n"); + + if(slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L("\r\n"); + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT_ECS(ctx->name); + NGX_RTMP_STAT_L("\r\n"); + } else { + NGX_RTMP_STAT_L("{\"name\":\""); + NGX_RTMP_STAT_ECS(ctx->name); + NGX_RTMP_STAT_L("\",\"clients\":["); + } nclients = 0; sctx = ctx; for (; ctx; ctx = ctx->next) { + if (ngx_strcmp(ctx->name, sctx->name)) { break; } @@ -640,36 +919,65 @@ ngx_rtmp_stat_play(ngx_http_request_t *r, ngx_chain_t ***lll, s = ctx->session; if (slcf->stat & NGX_RTMP_STAT_CLIENTS) { - NGX_RTMP_STAT_L(""); + if(slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L(""); - ngx_rtmp_stat_client(r, lll, s); + ngx_rtmp_stat_client(r, lll, s); + + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(bbuf, ngx_snprintf(bbuf, sizeof(bbuf), + "%D", s->current_time) - bbuf); + NGX_RTMP_STAT_L(""); + + NGX_RTMP_STAT_L("\r\n"); + } else { + NGX_RTMP_STAT_L("{"); - NGX_RTMP_STAT_L(""); - NGX_RTMP_STAT(bbuf, ngx_snprintf(bbuf, sizeof(bbuf), - "%D", s->current_time) - bbuf); - NGX_RTMP_STAT_L(""); + ngx_rtmp_stat_client(r, lll, s); - NGX_RTMP_STAT_L("\r\n"); + NGX_RTMP_STAT_L("\"timestamp\":"); + NGX_RTMP_STAT(bbuf, ngx_snprintf(bbuf, sizeof(bbuf), + "%D", s->current_time) - bbuf); + + NGX_RTMP_STAT_L("}"); + if(ctx->next) { + NGX_RTMP_STAT_L(","); + } + } } } total_nclients += nclients; - - NGX_RTMP_STAT_L(""); - NGX_RTMP_STAT_L(""); - NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), - "%ui", nclients) - buf); - NGX_RTMP_STAT_L("\r\n"); - - NGX_RTMP_STAT_L("\r\n"); + if(slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), + "%ui", nclients) - buf); + NGX_RTMP_STAT_L("\r\n"); + + NGX_RTMP_STAT_L("\r\n"); + } else { + NGX_RTMP_STAT_L("],"); + NGX_RTMP_STAT_L("\"active\":true,"); + NGX_RTMP_STAT_L("\"nclients\":"); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), + "%ui", nclients) - buf); + NGX_RTMP_STAT_L("}"); + } } } - NGX_RTMP_STAT_L(""); - NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), - "%ui", total_nclients) - buf); - NGX_RTMP_STAT_L("\r\n"); - - NGX_RTMP_STAT_L("\r\n"); + if(slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), + "%ui", total_nclients) - buf); + NGX_RTMP_STAT_L("\r\n"); + NGX_RTMP_STAT_L("\r\n"); + } else { + NGX_RTMP_STAT_L("],\"nclients\":"); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), + "%ui", total_nclients) - buf); + NGX_RTMP_STAT_L("}"); + } } @@ -678,13 +986,25 @@ ngx_rtmp_stat_application(ngx_http_request_t *r, ngx_chain_t ***lll, ngx_rtmp_core_app_conf_t *cacf) { ngx_rtmp_stat_loc_conf_t *slcf; - - NGX_RTMP_STAT_L("\r\n"); - NGX_RTMP_STAT_L(""); - NGX_RTMP_STAT_ES(&cacf->name); - NGX_RTMP_STAT_L("\r\n"); - + slcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_stat_module); + + if(slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L("\r\n"); + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT_ES(&cacf->name); + NGX_RTMP_STAT_L("\r\n"); + } else { + NGX_RTMP_STAT_L("{"); + NGX_RTMP_STAT_L("\"name\":\""); + NGX_RTMP_STAT_ES(&cacf->name); + + if (slcf->stat & NGX_RTMP_STAT_LIVE || slcf->stat & NGX_RTMP_STAT_PLAY) { + NGX_RTMP_STAT_L("\","); + } else { + NGX_RTMP_STAT_L("\""); + } + } if (slcf->stat & NGX_RTMP_STAT_LIVE) { ngx_rtmp_stat_live(r, lll, @@ -696,7 +1016,11 @@ ngx_rtmp_stat_application(ngx_http_request_t *r, ngx_chain_t ***lll, cacf->app_conf[ngx_rtmp_play_module.ctx_index]); } - NGX_RTMP_STAT_L("\r\n"); + if(slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L("\r\n"); + } else { + NGX_RTMP_STAT_L("}"); + } } @@ -706,8 +1030,15 @@ ngx_rtmp_stat_server(ngx_http_request_t *r, ngx_chain_t ***lll, { ngx_rtmp_core_app_conf_t **cacf; size_t n; - - NGX_RTMP_STAT_L("\r\n"); + ngx_rtmp_stat_loc_conf_t *slcf; + + slcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_stat_module); + + if (slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L("\r\n"); + } else { + NGX_RTMP_STAT_L("["); + } #ifdef NGX_RTMP_POOL_DEBUG ngx_rtmp_stat_dump_pool(r, lll, cscf->pool); @@ -716,9 +1047,17 @@ ngx_rtmp_stat_server(ngx_http_request_t *r, ngx_chain_t ***lll, cacf = cscf->applications.elts; for (n = 0; n < cscf->applications.nelts; ++n, ++cacf) { ngx_rtmp_stat_application(r, lll, *cacf); + + if (slcf->format & NGX_RTMP_STAT_FORMAT_JSON && n < cscf->applications.nelts-1) { + NGX_RTMP_STAT_L(","); + } + } + + if (slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L("\r\n"); + } else { + NGX_RTMP_STAT_L("]"); } - - NGX_RTMP_STAT_L("\r\n"); } @@ -735,9 +1074,14 @@ ngx_rtmp_stat_handler(ngx_http_request_t *r) static u_char nbuf[NGX_INT_T_LEN]; slcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_stat_module); + if (slcf->stat == 0) { return NGX_DECLINED; } + + if (slcf->format == 0) { + slcf->format = NGX_RTMP_STAT_FORMAT_XML; + } cmcf = ngx_rtmp_core_main_conf; if (cmcf == NULL) { @@ -747,59 +1091,111 @@ ngx_rtmp_stat_handler(ngx_http_request_t *r) cl = NULL; ll = &cl; lll = ≪ + + if (slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L("\r\n"); + if (slcf->stylesheet.len) { + NGX_RTMP_STAT_L("stylesheet); + NGX_RTMP_STAT_L("\" ?>\r\n"); + } - NGX_RTMP_STAT_L("\r\n"); - if (slcf->stylesheet.len) { - NGX_RTMP_STAT_L("stylesheet); - NGX_RTMP_STAT_L("\" ?>\r\n"); + NGX_RTMP_STAT_L("\r\n"); + + #ifdef NGINX_VERSION + NGX_RTMP_STAT_L("" NGINX_VERSION "\r\n"); + #endif + + #ifdef NGINX_RTMP_VERSION + NGX_RTMP_STAT_L("" + NGINX_RTMP_VERSION + "\r\n"); + #endif + + #ifdef NGX_COMPILER + NGX_RTMP_STAT_L("" NGX_COMPILER "\r\n"); + #endif + NGX_RTMP_STAT_L("" __DATE__ " " __TIME__ "\r\n"); + + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(nbuf, ngx_snprintf(nbuf, sizeof(nbuf), + "%ui", (ngx_uint_t) ngx_getpid()) - nbuf); + NGX_RTMP_STAT_L("\r\n"); + + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(tbuf, ngx_snprintf(tbuf, sizeof(tbuf), + "%T", ngx_cached_time->sec - start_time) - tbuf); + NGX_RTMP_STAT_L("\r\n"); + + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(nbuf, ngx_snprintf(nbuf, sizeof(nbuf), + "%ui", ngx_rtmp_naccepted) - nbuf); + NGX_RTMP_STAT_L("\r\n"); + } else { + NGX_RTMP_STAT_L("{\"http-flv\":{"); + + #ifdef NGINX_VERSION + NGX_RTMP_STAT_L("\"nginx_version\":\"" NGINX_VERSION "\","); + #endif + + #ifdef NGINX_RTMP_VERSION + NGX_RTMP_STAT_L("\"nginx_http_flv_version\":\"" + NGINX_RTMP_VERSION + "\","); + #endif + + #ifdef NGX_COMPILER + NGX_RTMP_STAT_L("\"compiler\":\"" NGX_COMPILER "\","); + #endif + NGX_RTMP_STAT_L("\"built\":\"" __DATE__ " " __TIME__ "\","); + + NGX_RTMP_STAT_L("\"pid\":"); + NGX_RTMP_STAT(nbuf, ngx_snprintf(nbuf, sizeof(nbuf), + "%ui", (ngx_uint_t) ngx_getpid()) - nbuf); + NGX_RTMP_STAT_L(","); + + NGX_RTMP_STAT_L("\"uptime\":"); + NGX_RTMP_STAT(tbuf, ngx_snprintf(tbuf, sizeof(tbuf), + "%T", ngx_cached_time->sec - start_time) - tbuf); + NGX_RTMP_STAT_L(","); + + NGX_RTMP_STAT_L("\"naccepted\":"); + NGX_RTMP_STAT(nbuf, ngx_snprintf(nbuf, sizeof(nbuf), + "%ui", ngx_rtmp_naccepted) - nbuf); + NGX_RTMP_STAT_L(","); } - NGX_RTMP_STAT_L("\r\n"); - -#ifdef NGINX_VERSION - NGX_RTMP_STAT_L("" NGINX_VERSION "\r\n"); -#endif - -#ifdef NGINX_RTMP_VERSION - NGX_RTMP_STAT_L("" NGINX_RTMP_VERSION "\r\n"); -#endif - -#ifdef NGX_COMPILER - NGX_RTMP_STAT_L("" NGX_COMPILER "\r\n"); -#endif - NGX_RTMP_STAT_L("" __DATE__ " " __TIME__ "\r\n"); - - NGX_RTMP_STAT_L(""); - NGX_RTMP_STAT(nbuf, ngx_snprintf(nbuf, sizeof(nbuf), - "%ui", (ngx_uint_t) ngx_getpid()) - nbuf); - NGX_RTMP_STAT_L("\r\n"); - - NGX_RTMP_STAT_L(""); - NGX_RTMP_STAT(tbuf, ngx_snprintf(tbuf, sizeof(tbuf), - "%T", ngx_cached_time->sec - start_time) - tbuf); - NGX_RTMP_STAT_L("\r\n"); - - NGX_RTMP_STAT_L(""); - NGX_RTMP_STAT(nbuf, ngx_snprintf(nbuf, sizeof(nbuf), - "%ui", ngx_rtmp_naccepted) - nbuf); - NGX_RTMP_STAT_L("\r\n"); - ngx_rtmp_stat_bw(r, lll, &ngx_rtmp_bw_in, "in", NGX_RTMP_STAT_BW_BYTES); ngx_rtmp_stat_bw(r, lll, &ngx_rtmp_bw_out, "out", NGX_RTMP_STAT_BW_BYTES); + + if(slcf->format & NGX_RTMP_STAT_FORMAT_JSON) { + NGX_RTMP_STAT_L("\"servers\":["); + } cscf = cmcf->servers.elts; for (n = 0; n < cmcf->servers.nelts; ++n, ++cscf) { ngx_rtmp_stat_server(r, lll, *cscf); + if(slcf->format & NGX_RTMP_STAT_FORMAT_JSON && n < cmcf->servers.nelts-1) { + NGX_RTMP_STAT_L(","); + } } - - NGX_RTMP_STAT_L("\r\n"); - + + if(slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + NGX_RTMP_STAT_L("\r\n"); + } else { + NGX_RTMP_STAT_L("]}}"); + } + len = 0; for (l = cl; l; l = l->next) { len += (l->buf->last - l->buf->pos); } - ngx_str_set(&r->headers_out.content_type, "text/xml"); + + if(slcf->format & NGX_RTMP_STAT_FORMAT_XML) { + ngx_str_set(&r->headers_out.content_type, "text/xml"); + } else { + ngx_str_set(&r->headers_out.content_type, "application/json"); + } r->headers_out.content_length_n = len; r->headers_out.status = NGX_HTTP_OK; ngx_http_send_header(r); diff --git a/ngx_rtmp_variables.c b/ngx_rtmp_variables.c index d5f546e..9632329 100644 --- a/ngx_rtmp_variables.c +++ b/ngx_rtmp_variables.c @@ -1,8 +1,8 @@ /* * Copyright (C) Igor Sysoev - * Copyright (C) Nginx, Inc. - * Copyright (C) Winshining + * Copyright (C) Nginx, Inc. + * Copyright (C) Winshining */ @@ -16,10 +16,6 @@ static ngx_rtmp_variable_t *ngx_rtmp_add_prefix_variable(ngx_conf_t *cf, static ngx_int_t ngx_rtmp_variable_request(ngx_rtmp_session_t *s, ngx_rtmp_variable_value_t *v, uintptr_t data); -static ngx_int_t ngx_rtmp_variable_request_get_size(ngx_rtmp_session_t *s, - ngx_rtmp_variable_value_t *v, uintptr_t data); -static void ngx_rtmp_variable_request_set_size(ngx_rtmp_session_t *s, - ngx_rtmp_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_rtmp_variable_argument(ngx_rtmp_session_t *s, ngx_rtmp_variable_value_t *v, uintptr_t data); @@ -112,11 +108,6 @@ static ngx_rtmp_variable_t ngx_rtmp_core_variables[] = { ngx_rtmp_variable_request_id, 0, 0, 0 }, - { ngx_string("limit_rate"), ngx_rtmp_variable_request_set_size, - ngx_rtmp_variable_request_get_size, - offsetof(ngx_rtmp_session_t, limit_rate), - NGX_RTMP_VAR_CHANGEABLE|NGX_RTMP_VAR_NOCACHEABLE, 0 }, - { ngx_string("connection"), NULL, ngx_rtmp_variable_connection, 0, 0, 0 }, @@ -515,54 +506,6 @@ ngx_rtmp_variable_request(ngx_rtmp_session_t *s, ngx_rtmp_variable_value_t *v, } -static ngx_int_t -ngx_rtmp_variable_request_get_size(ngx_rtmp_session_t *s, - ngx_rtmp_variable_value_t *v, uintptr_t data) -{ - size_t *sp; - - sp = (size_t *) ((char *) s + data); - - v->data = ngx_pnalloc(s->connection->pool, NGX_SIZE_T_LEN); - if (v->data == NULL) { - return NGX_ERROR; - } - - v->len = ngx_sprintf(v->data, "%uz", *sp) - v->data; - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - - return NGX_OK; -} - - -static void -ngx_rtmp_variable_request_set_size(ngx_rtmp_session_t *s, - ngx_rtmp_variable_value_t *v, uintptr_t data) -{ - ssize_t size, *sp; - ngx_str_t val; - - val.len = v->len; - val.data = v->data; - - size = ngx_parse_size(&val); - - if (size == NGX_ERROR) { - ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, - "invalid size \"%V\"", &val); - return; - } - - sp = (ssize_t *) ((char *) size + data); - - *sp = size; - - return; -} - - ngx_int_t ngx_rtmp_arg(ngx_rtmp_session_t *s, u_char *name, size_t len, ngx_str_t *value) { diff --git a/ngx_rtmp_variables.h b/ngx_rtmp_variables.h index 6cd34dc..9730966 100644 --- a/ngx_rtmp_variables.h +++ b/ngx_rtmp_variables.h @@ -1,8 +1,8 @@ /* * Copyright (C) Igor Sysoev - * Copyright (C) Nginx, Inc. - * Copyright (C) Winshining + * Copyright (C) Nginx, Inc. + * Copyright (C) Winshining */ diff --git a/ngx_rtmp_version.h b/ngx_rtmp_version.h index 4511349..1654931 100644 --- a/ngx_rtmp_version.h +++ b/ngx_rtmp_version.h @@ -1,7 +1,7 @@ /* - * Copyright (C) Roman Arutyunyan - * Copyright (C) Winshining + * Copyright (C) Roman Arutyunyan + * Copyright (C) Winshining */ @@ -9,8 +9,8 @@ #define _NGX_RTMP_VERSION_H_INCLUDED_ -#define nginx_rtmp_version 1002003 -#define NGINX_RTMP_VERSION "1.2.3" +#define nginx_rtmp_version 1002005 +#define NGINX_RTMP_VERSION "1.2.5" #endif /* _NGX_RTMP_VERSION_H_INCLUDED_ */ diff --git a/samples/flv.js.png b/samples/flv.js.png new file mode 100644 index 0000000..69fc85e Binary files /dev/null and b/samples/flv.js.png differ diff --git a/samples/jwplayer_vlc.png b/samples/jwplayer_vlc.png new file mode 100644 index 0000000..26f410f Binary files /dev/null and b/samples/jwplayer_vlc.png differ diff --git a/stat.xsl b/stat.xsl index 2e1a4ce..c0935e7 100644 --- a/stat.xsl +++ b/stat.xsl @@ -13,24 +13,24 @@ - RTMP statistics + HTTP-FLV statistics - +
Generated by - nginx-http-flv-module , - nginx , - pid , - built   + nginx-http-flv-module , + nginx , + pid , + built  
- + - + @@ -78,7 +78,7 @@
RTMPHTTP-FLV #clients Video Audio - +