From f8da609671331b3b020158d41bb8b50d2e5bbe8e Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Thu, 17 Dec 2015 03:36:58 +0300 Subject: [PATCH] Add playlist update notification for HLS/DASH --- dash/ngx_rtmp_dash_module.c | 17 +++++- hls/ngx_rtmp_hls_module.c | 35 +++++++++++- ngx_rtmp_cmd_module.c | 12 +++++ ngx_rtmp_cmd_module.h | 8 +++ ngx_rtmp_notify_module.c | 104 ++++++++++++++++++++++++++++++++++++ ngx_rtmp_version.h | 2 +- 6 files changed, 174 insertions(+), 4 deletions(-) diff --git a/dash/ngx_rtmp_dash_module.c b/dash/ngx_rtmp_dash_module.c index 32c2daa..a6b4c9e 100644 --- a/dash/ngx_rtmp_dash_module.c +++ b/dash/ngx_rtmp_dash_module.c @@ -12,6 +12,7 @@ static ngx_rtmp_publish_pt next_publish; static ngx_rtmp_close_stream_pt next_close_stream; static ngx_rtmp_stream_begin_pt next_stream_begin; static ngx_rtmp_stream_eof_pt next_stream_eof; +static ngx_rtmp_playlist_pt next_playlist; static ngx_int_t ngx_rtmp_dash_postconfiguration(ngx_conf_t *cf); @@ -228,6 +229,8 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) ngx_rtmp_dash_frag_t *f; ngx_rtmp_dash_app_conf_t *dacf; + ngx_rtmp_playlist_t v; + static u_char buffer[NGX_RTMP_DASH_BUFSIZE]; static u_char start_time[sizeof("1970-09-28T12:00:00+06:00")]; static u_char end_time[sizeof("1970-09-28T12:00:00+06:00")]; @@ -491,7 +494,11 @@ ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) return NGX_ERROR; } - return NGX_OK; + ngx_memzero(&v, sizeof(v)); + ngx_str_set(&(v.module), "dash"); + v.playlist.data = ctx->playlist.data; + v.playlist.len = ctx->playlist.len; + return next_playlist(s, &v); } @@ -1464,6 +1471,11 @@ ngx_rtmp_dash_cleanup(void *data) return cleanup->playlen / 500; } +static ngx_int_t +ngx_rtmp_dash_playlist(ngx_rtmp_session_t *s, ngx_rtmp_playlist_t *v) +{ + return next_playlist(s, v); +} static void * ngx_rtmp_dash_create_app_conf(ngx_conf_t *cf) @@ -1565,5 +1577,8 @@ ngx_rtmp_dash_postconfiguration(ngx_conf_t *cf) next_stream_eof = ngx_rtmp_stream_eof; ngx_rtmp_stream_eof = ngx_rtmp_dash_stream_eof; + next_playlist = ngx_rtmp_playlist; + ngx_rtmp_playlist = ngx_rtmp_dash_playlist; + return NGX_OK; } diff --git a/hls/ngx_rtmp_hls_module.c b/hls/ngx_rtmp_hls_module.c index d04ba66..a91ec62 100644 --- a/hls/ngx_rtmp_hls_module.c +++ b/hls/ngx_rtmp_hls_module.c @@ -16,6 +16,7 @@ static ngx_rtmp_publish_pt next_publish; static ngx_rtmp_close_stream_pt next_close_stream; static ngx_rtmp_stream_begin_pt next_stream_begin; static ngx_rtmp_stream_eof_pt next_stream_eof; +static ngx_rtmp_playlist_pt next_playlist; static char * ngx_rtmp_hls_variant(ngx_conf_t *cf, ngx_command_t *cmd, @@ -422,6 +423,8 @@ ngx_rtmp_hls_write_variant_playlist(ngx_rtmp_session_t *s) ngx_rtmp_hls_variant_t *var; ngx_rtmp_hls_app_conf_t *hacf; + ngx_rtmp_playlist_t v; + hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_hls_module); ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module); @@ -497,7 +500,11 @@ ngx_rtmp_hls_write_variant_playlist(ngx_rtmp_session_t *s) return NGX_ERROR; } - return NGX_OK; + ngx_memzero(&v, sizeof(v)); + ngx_str_set(&(v.module), "hls"); + v.playlist.data = ctx->playlist.data; + v.playlist.len = ctx->playlist.len; + return next_playlist(s, &v); } @@ -516,6 +523,10 @@ ngx_rtmp_hls_write_playlist(ngx_rtmp_session_t *s) uint64_t prev_key_id; const char *sep, *key_sep; + ngx_rtmp_playlist_t v; + + ngx_log_error(NGX_LOG_DEBUG, s->connection->log, 0, + "hls: write playlist"); hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_hls_module); ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module); @@ -638,7 +649,11 @@ ngx_rtmp_hls_write_playlist(ngx_rtmp_session_t *s) return ngx_rtmp_hls_write_variant_playlist(s); } - return NGX_OK; + ngx_memzero(&v, sizeof(v)); + ngx_str_set(&(v.module), "hls"); + v.playlist.data = ctx->playlist.data; + v.playlist.len = ctx->playlist.len; + return next_playlist(s, &v); write_err: ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, @@ -1658,6 +1673,9 @@ ngx_rtmp_hls_update_fragment(ngx_rtmp_session_t *s, uint64_t ts, ngx_buf_t *b; int64_t d; + ngx_log_error(NGX_LOG_DEBUG, s->connection->log, 0, + "hls: update fragment"); + hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_hls_module); ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module); f = NULL; @@ -2166,6 +2184,9 @@ ngx_rtmp_hls_stream_begin(ngx_rtmp_session_t *s, ngx_rtmp_stream_begin_t *v) static ngx_int_t ngx_rtmp_hls_stream_eof(ngx_rtmp_session_t *s, ngx_rtmp_stream_eof_t *v) { + ngx_log_error(NGX_LOG_DEBUG, s->connection->log, 0, + "hls: stream eof"); + ngx_rtmp_hls_flush_audio(s); ngx_rtmp_hls_close_fragment(s); @@ -2383,6 +2404,13 @@ ngx_rtmp_hls_variant(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +static ngx_int_t +ngx_rtmp_hls_playlist(ngx_rtmp_session_t *s, ngx_rtmp_playlist_t *v) +{ + return next_playlist(s, v); +} + + static void * ngx_rtmp_hls_create_app_conf(ngx_conf_t *cf) { @@ -2559,5 +2587,8 @@ ngx_rtmp_hls_postconfiguration(ngx_conf_t *cf) next_stream_eof = ngx_rtmp_stream_eof; ngx_rtmp_stream_eof = ngx_rtmp_hls_stream_eof; + next_playlist = ngx_rtmp_playlist; + ngx_rtmp_playlist = ngx_rtmp_hls_playlist; + return NGX_OK; } diff --git a/ngx_rtmp_cmd_module.c b/ngx_rtmp_cmd_module.c index 188a76b..c879fc2 100644 --- a/ngx_rtmp_cmd_module.c +++ b/ngx_rtmp_cmd_module.c @@ -44,6 +44,7 @@ static ngx_int_t ngx_rtmp_cmd_recorded(ngx_rtmp_session_t *s, static ngx_int_t ngx_rtmp_cmd_set_buflen(ngx_rtmp_session_t *s, ngx_rtmp_set_buflen_t *v); +static ngx_int_t ngx_rtmp_cmd_playlist(ngx_rtmp_session_t *s, ngx_rtmp_playlist_t *v); ngx_rtmp_connect_pt ngx_rtmp_connect; ngx_rtmp_disconnect_pt ngx_rtmp_disconnect; @@ -62,6 +63,7 @@ ngx_rtmp_stream_dry_pt ngx_rtmp_stream_dry; ngx_rtmp_recorded_pt ngx_rtmp_recorded; ngx_rtmp_set_buflen_pt ngx_rtmp_set_buflen; +ngx_rtmp_playlist_pt ngx_rtmp_playlist; static ngx_int_t ngx_rtmp_cmd_postconfiguration(ngx_conf_t *cf); @@ -788,6 +790,14 @@ ngx_rtmp_cmd_set_buflen(ngx_rtmp_session_t *s, ngx_rtmp_set_buflen_t *v) } +static ngx_int_t +ngx_rtmp_cmd_playlist(ngx_rtmp_session_t *s, ngx_rtmp_playlist_t *v) +{ + return NGX_OK; +} + + + static ngx_rtmp_amf_handler_t ngx_rtmp_cmd_map[] = { { ngx_string("connect"), ngx_rtmp_cmd_connect_init }, { ngx_string("createStream"), ngx_rtmp_cmd_create_stream_init }, @@ -854,5 +864,7 @@ ngx_rtmp_cmd_postconfiguration(ngx_conf_t *cf) ngx_rtmp_recorded = ngx_rtmp_cmd_recorded; ngx_rtmp_set_buflen = ngx_rtmp_cmd_set_buflen; + ngx_rtmp_playlist = ngx_rtmp_cmd_playlist; + return NGX_OK; } diff --git a/ngx_rtmp_cmd_module.h b/ngx_rtmp_cmd_module.h index 4a0b955..9a24112 100644 --- a/ngx_rtmp_cmd_module.h +++ b/ngx_rtmp_cmd_module.h @@ -59,6 +59,12 @@ typedef struct { } ngx_rtmp_publish_t; +typedef struct { + ngx_str_t playlist; + ngx_str_t module; +} ngx_rtmp_playlist_t; + + typedef struct { u_char name[NGX_RTMP_MAX_NAME]; u_char args[NGX_RTMP_MAX_ARGS]; @@ -130,6 +136,7 @@ typedef ngx_int_t (*ngx_rtmp_recorded_pt)(ngx_rtmp_session_t *s, typedef ngx_int_t (*ngx_rtmp_set_buflen_pt)(ngx_rtmp_session_t *s, ngx_rtmp_set_buflen_t *v); +typedef ngx_int_t (*ngx_rtmp_playlist_pt)(ngx_rtmp_session_t *s, ngx_rtmp_playlist_t *v); extern ngx_rtmp_connect_pt ngx_rtmp_connect; extern ngx_rtmp_disconnect_pt ngx_rtmp_disconnect; @@ -147,5 +154,6 @@ extern ngx_rtmp_stream_dry_pt ngx_rtmp_stream_dry; extern ngx_rtmp_set_buflen_pt ngx_rtmp_set_buflen; extern ngx_rtmp_recorded_pt ngx_rtmp_recorded; +extern ngx_rtmp_playlist_pt ngx_rtmp_playlist; #endif /*_NGX_RTMP_CMD_H_INCLUDED_ */ diff --git a/ngx_rtmp_notify_module.c b/ngx_rtmp_notify_module.c index 76c882a..72207e6 100644 --- a/ngx_rtmp_notify_module.c +++ b/ngx_rtmp_notify_module.c @@ -20,6 +20,7 @@ static ngx_rtmp_publish_pt next_publish; static ngx_rtmp_play_pt next_play; static ngx_rtmp_close_stream_pt next_close_stream; static ngx_rtmp_record_done_pt next_record_done; +static ngx_rtmp_playlist_pt next_playlist; static char *ngx_rtmp_notify_on_srv_event(ngx_conf_t *cf, ngx_command_t *cmd, @@ -57,6 +58,7 @@ enum { NGX_RTMP_NOTIFY_DONE, NGX_RTMP_NOTIFY_RECORD_DONE, NGX_RTMP_NOTIFY_UPDATE, + NGX_RTMP_NOTIFY_PLAYLIST, NGX_RTMP_NOTIFY_APP_MAX }; @@ -167,6 +169,13 @@ static ngx_command_t ngx_rtmp_notify_commands[] = { 0, NULL }, + { ngx_string("on_playlist"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_rtmp_notify_on_app_event, + NGX_RTMP_APP_CONF_OFFSET, + 0, + NULL }, + { ngx_string("notify_method"), NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, ngx_rtmp_notify_method, @@ -862,6 +871,65 @@ ngx_rtmp_notify_record_done_create(ngx_rtmp_session_t *s, void *arg, pl); } +static ngx_chain_t * +ngx_rtmp_notify_playlist_create(ngx_rtmp_session_t *s, void *arg, + ngx_pool_t *pool) +{ + ngx_rtmp_playlist_t *v = arg; + + ngx_rtmp_notify_ctx_t *ctx; + ngx_chain_t *pl; + ngx_buf_t *b; + size_t name_len; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_notify_module); + + pl = ngx_alloc_chain_link(pool); + if (pl == NULL) { + return NULL; + } + + name_len = ngx_strlen(ctx->name); + + b = ngx_create_temp_buf(pool, + sizeof("&call=playlist") + + sizeof("&module=") + v->module.len + + sizeof("&app=") + s->app.len * 3 + + sizeof("&name=") + name_len * 3 + + sizeof("&path=") + v->playlist.len * 3 + + 1); + + if (b == NULL) { + return NULL; + } + + pl->buf = b; + pl->next = NULL; + + b->last = ngx_cpymem(b->last, (u_char*) "&call=playlist", + sizeof("&call=playlist") - 1); + + b->last = ngx_cpymem(b->last, (u_char *) "&module=", + sizeof("&module=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, v->module.data, + v->module.len, NGX_ESCAPE_ARGS); + + b->last = ngx_cpymem(b->last, (u_char*) "&app=", sizeof("&app=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, s->app.data, s->app.len, + NGX_ESCAPE_ARGS); + + b->last = ngx_cpymem(b->last, (u_char*) "&name=", sizeof("&name=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, ctx->name, name_len, + NGX_ESCAPE_ARGS); + + b->last = ngx_cpymem(b->last, (u_char*) "&path=", sizeof("&path=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, v->playlist.data, v->playlist.len, + NGX_ESCAPE_ARGS); + + return ngx_rtmp_notify_create_request(s, pool, NGX_RTMP_NOTIFY_PLAYLIST, + pl); +} + static ngx_int_t ngx_rtmp_notify_parse_http_retcode(ngx_rtmp_session_t *s, @@ -1830,6 +1898,35 @@ ngx_rtmp_notify_parse_url(ngx_conf_t *cf, ngx_str_t *url) } +static ngx_int_t +ngx_rtmp_notify_playlist(ngx_rtmp_session_t *s, ngx_rtmp_playlist_t *v) +{ + ngx_rtmp_netcall_init_t ci; + ngx_rtmp_notify_app_conf_t *nacf; + + nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module); + if (nacf == NULL || nacf->url[NGX_RTMP_NOTIFY_PLAYLIST] == NULL) { + goto next; + } + + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "notify: playlist url='%V'", + &nacf->url[NGX_RTMP_NOTIFY_PLAYLIST]->url); + + ngx_memzero(&ci, sizeof(ci)); + + ci.url = nacf->url[NGX_RTMP_NOTIFY_PLAYLIST]; + ci.create = ngx_rtmp_notify_playlist_create; + ci.arg = v; + + ngx_rtmp_netcall_create(s, &ci); + +next: + return next_playlist(s, v); +} + + + static char * ngx_rtmp_notify_on_srv_event(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { @@ -1899,6 +1996,10 @@ ngx_rtmp_notify_on_app_event(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) n = NGX_RTMP_NOTIFY_UPDATE; break; + case sizeof("on_playlist") - 1: + n = NGX_RTMP_NOTIFY_PLAYLIST; + break; + case sizeof("on_publish") - 1: n = NGX_RTMP_NOTIFY_PUBLISH; break; @@ -2006,5 +2107,8 @@ ngx_rtmp_notify_postconfiguration(ngx_conf_t *cf) next_record_done = ngx_rtmp_record_done; ngx_rtmp_record_done = ngx_rtmp_notify_record_done; + next_playlist = ngx_rtmp_playlist; + ngx_rtmp_playlist = ngx_rtmp_notify_playlist; + return NGX_OK; } diff --git a/ngx_rtmp_version.h b/ngx_rtmp_version.h index 9577e6a..cbfa3df 100644 --- a/ngx_rtmp_version.h +++ b/ngx_rtmp_version.h @@ -9,7 +9,7 @@ #define nginx_rtmp_version 1001007 -#define NGINX_RTMP_VERSION "1.1.7.9" +#define NGINX_RTMP_VERSION "1.1.7.10" #endif /* _NGX_RTMP_VERSION_H_INCLUDED_ */