From a61330014287681b14f39158ef5c645b24b1b1f9 Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Sun, 28 Feb 2016 06:52:02 +0300 Subject: [PATCH 01/19] New module for bandwidth detection --- config | 7 +- ngx_rtmp.h | 3 + ngx_rtmp_bandwidth_detection_module.c | 434 ++++++++++++++++++++++++++ ngx_rtmp_bandwidth_detection_module.h | 50 +++ ngx_rtmp_send.c | 139 +++++++++ ngx_rtmp_transitions.h | 15 + 6 files changed, 646 insertions(+), 2 deletions(-) create mode 100644 ngx_rtmp_bandwidth_detection_module.c create mode 100644 ngx_rtmp_bandwidth_detection_module.h create mode 100644 ngx_rtmp_transitions.h diff --git a/config b/config index cc4f2a30e..0b54a2f17 100644 --- a/config +++ b/config @@ -7,6 +7,7 @@ RTMP_CORE_MODULES=" \ ngx_rtmp_access_module \ ngx_rtmp_record_module \ ngx_rtmp_live_module \ + ngx_rtmp_bandwidth_detection_module \ ngx_rtmp_play_module \ ngx_rtmp_flv_module \ ngx_rtmp_mp4_module \ @@ -33,6 +34,7 @@ RTMP_DEPS=" \ $ngx_addon_dir/ngx_rtmp.h \ $ngx_addon_dir/ngx_rtmp_version.h \ $ngx_addon_dir/ngx_rtmp_live_module.h \ + $ngx_addon_dir/ngx_rtmp_bandwidth_detection_module.h \ $ngx_addon_dir/ngx_rtmp_netcall_module.h \ $ngx_addon_dir/ngx_rtmp_play_module.h \ $ngx_addon_dir/ngx_rtmp_record_module.h \ @@ -59,6 +61,7 @@ RTMP_CORE_SRCS=" \ $ngx_addon_dir/ngx_rtmp_access_module.c \ $ngx_addon_dir/ngx_rtmp_record_module.c \ $ngx_addon_dir/ngx_rtmp_live_module.c \ + $ngx_addon_dir/ngx_rtmp_bandwidth_detection_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 \ @@ -111,6 +114,6 @@ fi USE_OPENSSL=YES -CFLAGS="$CFLAGS -I$ngx_addon_dir" +# CFLAGS="$CFLAGS -I$ngx_addon_dir" # Debug build with all warnings as errors -# CFLAGS="$CFLAGS -I$ngx_addon_dir -Wall -Wpointer-arith -Wno-unused-parameter -Werror" +CFLAGS="$CFLAGS -I$ngx_addon_dir -Wall -Wpointer-arith -Wno-unused-parameter -Werror" diff --git a/ngx_rtmp.h b/ngx_rtmp.h index f3a3d6f18..463b9f3ff 100644 --- a/ngx_rtmp.h +++ b/ngx_rtmp.h @@ -589,6 +589,9 @@ ngx_int_t ngx_rtmp_send_close_method(ngx_rtmp_session_t *s, char *methodName); ngx_int_t ngx_rtmp_send_fcpublish(ngx_rtmp_session_t *s, u_char *desc); ngx_int_t ngx_rtmp_send_fcunpublish(ngx_rtmp_session_t *s, u_char *desc); ngx_int_t ngx_rtmp_send_fi(ngx_rtmp_session_t *s); +ngx_int_t ngx_rtmp_send_bwcheck(ngx_rtmp_session_t *s, u_char *payload); +ngx_int_t ngx_rtmp_send_bwdone(ngx_rtmp_session_t *s, + double kbitDown, ngx_uint_t deltaDown, double deltaTime, ngx_msec_t latency); /* Frame types */ diff --git a/ngx_rtmp_bandwidth_detection_module.c b/ngx_rtmp_bandwidth_detection_module.c new file mode 100644 index 000000000..c8480e1a2 --- /dev/null +++ b/ngx_rtmp_bandwidth_detection_module.c @@ -0,0 +1,434 @@ + +/* + * Copyright (C) Sergey Dryabzhinsky, 2016 + * + * Based on http://permalink.gmane.org/gmane.comp.web.flash.red5/5869 + * And live & stat modules + */ + + +#include +#include +#include "ngx_rtmp_bandwidth_detection_module.h" +#include "ngx_rtmp_live_module.h" +#include "ngx_rtmp_cmd_module.h" +#include "ngx_rtmp_transitions.h" + + +#define NGX_RTMP_BANDWIDTH_DETECTION_PAYLOAD_LENGTH 16*1024 + + +static ngx_int_t ngx_rtmp_bandwidth_detection_postconfiguration(ngx_conf_t *cf); +static void * ngx_rtmp_bandwidth_detection_create_app_conf(ngx_conf_t *cf); +static char * ngx_rtmp_bandwidth_detection_merge_app_conf(ngx_conf_t *cf, + void *parent, void *child); +static char *ngx_rtmp_bandwidth_detection_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static ngx_int_t ngx_rtmp_bandwidth_detection_start(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in); +static ngx_int_t ngx_rtmp_bandwidth_detection_check_result(ngx_rtmp_session_t *s); + + +static ngx_command_t ngx_rtmp_bandwidth_detection_commands[] = { + + { ngx_string("latency_min"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_rtmp_bandwidth_detection_set_msec_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_bandwidth_detection_app_conf_t, latency_min), + NULL }, + + { ngx_string("latency_max"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_rtmp_bandwidth_detection_set_msec_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_bandwidth_detection_app_conf_t, latency_max), + NULL }, + + { ngx_string("latency_undef"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_rtmp_bandwidth_detection_set_msec_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_bandwidth_detection_app_conf_t, latency_undef), + NULL }, + + { ngx_string("test_time"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_rtmp_bandwidth_detection_set_msec_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_bandwidth_detection_app_conf_t, test_time), + NULL }, + + ngx_null_command +}; + + +static ngx_rtmp_module_t ngx_rtmp_bandwidth_detection_module_ctx = { + NULL, /* preconfiguration */ + ngx_rtmp_bandwidth_detection_postconfiguration, /* postconfiguration */ + NULL, /* create main configuration */ + NULL, /* init main configuration */ + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + ngx_rtmp_bandwidth_detection_create_app_conf, /* create app configuration */ + ngx_rtmp_bandwidth_detection_merge_app_conf /* merge app configuration */ +}; + + +ngx_module_t ngx_rtmp_bandwidth_detection_module = { + NGX_MODULE_V1, + &ngx_rtmp_bandwidth_detection_module_ctx, /* module context */ + ngx_rtmp_bandwidth_detection_commands, /* module directives */ + NGX_RTMP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static void * +ngx_rtmp_bandwidth_detection_create_app_conf(ngx_conf_t *cf) +{ + ngx_rtmp_bandwidth_detection_app_conf_t *acf; + ngx_uint_t i; + + acf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_bandwidth_detection_app_conf_t)); + if (acf == NULL) { + return NULL; + } + + acf->latency_max = NGX_CONF_UNSET; + acf->latency_min = NGX_CONF_UNSET_MSEC; + acf->latency_undef = NGX_CONF_UNSET_MSEC; + acf->test_time = NGX_CONF_UNSET_MSEC; + + /* Init payload only once with some random garbage */ + acf->payload = ngx_pcalloc(cf->pool, NGX_RTMP_BANDWIDTH_DETECTION_PAYLOAD_LENGTH + 1); + for (i=0; ipayload[i] = ngx_random(); + } + + return acf; +} + + +static char * +ngx_rtmp_bandwidth_detection_merge_app_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_rtmp_bandwidth_detection_app_conf_t *prev = parent; + ngx_rtmp_bandwidth_detection_app_conf_t *conf = child; + + ngx_conf_merge_msec_value(conf->latency_max, prev->latency_max, 800); + ngx_conf_merge_msec_value(conf->latency_min, prev->latency_min, 10); + ngx_conf_merge_msec_value(conf->latency_undef, prev->latency_undef, 100); + ngx_conf_merge_msec_value(conf->test_time, prev->test_time, 2000); + + // One payload for all + conf->payload = prev->payload; + + return NGX_CONF_OK; +} + + +static char * +ngx_rtmp_bandwidth_detection_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + ngx_str_t *value; + ngx_msec_t *msp; + + msp = (ngx_msec_t *) (p + cmd->offset); + + value = cf->args->elts; + + if (value[1].len == sizeof("off") - 1 && + ngx_strncasecmp(value[1].data, (u_char *) "off", value[1].len) == 0) + { + *msp = 0; + return NGX_CONF_OK; + } + + return ngx_conf_set_msec_slot(cf, cmd, conf); +} + + +static ngx_int_t +ngx_rtmp_bandwidth_detection_on_result(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_rtmp_bandwidth_detection_ctx_t *ctx; + + static struct { + double trans; + ngx_uint_t count; + } v; + + static ngx_rtmp_amf_elt_t in_inf[] = { + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &v.count, 0 }, + + }; + + static ngx_rtmp_amf_elt_t in_elts[] = { + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &v.trans, 0 }, + + { NGX_RTMP_AMF_NULL, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_OBJECT, + ngx_null_string, + in_inf, sizeof(in_inf) }, + }; + + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_bandwidth_detection_module); + if (ctx == NULL || s->relay) { + return NGX_OK; + } + + ngx_memzero(&v, sizeof(v)); + if (ngx_rtmp_receive_amf(s, in, in_elts, + sizeof(in_elts) / sizeof(in_elts[0]))) + { + return NGX_ERROR; + } + + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "relay: _result: level='%s' code='%s' description='%s'", + v.level, v.code, v.desc); + + switch ((ngx_int_t)v.trans) { + case NGX_RTMP_BANDWIDTH_DETECTION_BWCHECK_TRANS: + return ngx_rtmp_bandwidth_detection_check_result(s); + break; + + case NGX_RTMP_BANDWIDTH_DETECTION_BWDONE_TRANS: + /* Need to test it. Maybe need to set this before send bwDone. */ + ctx->active = 0; + break; + default: + return NGX_OK; + } + return NGX_OK; +} + + +/** + * Start bandwidth detection here + */ +static ngx_int_t +ngx_rtmp_bandwidth_detection_start(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) +{ + + ngx_rtmp_bandwidth_detection_app_conf_t *acf; + ngx_rtmp_bandwidth_detection_ctx_t *bw_ctx; + ngx_rtmp_live_ctx_t *lv_ctx; + + static ngx_rtmp_amf_elt_t in_elts[] = { + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + "checkBandwidth", 0 }, + + }; + + if (s->relay) { + ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0, + "bandwidth_detection: start - no relay please!"); + return NGX_ERROR; + } + + acf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_bandwidth_detection_module); + if (acf == NULL) { + ngx_log_error(NGX_LOG_WARN, s->connection->log, 0, + "bandwidth_detection: start - no app config!"); + return NGX_ERROR; + } + + if (!acf->test_time || in == NULL || in->buf == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0, + "bandwidth_detection: start - no test time or no buffer!"); + return NGX_OK; + } + + bw_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_bandwidth_detection_module); + if (bw_ctx == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0, + "bandwidth_detection: start - no bw context!"); + return NGX_OK; + } + if (bw_ctx->active) { + ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0, + "bandwidth_detection: start - already active!"); + return NGX_OK; + } + + lv_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); + if (lv_ctx == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0, + "bandwidth_detection: start - no live context!"); + return NGX_OK; + } + + if (ngx_rtmp_receive_amf(s, in, in_elts, + sizeof(in_elts) / sizeof(in_elts[0])) != NGX_OK) { + ngx_log_error(NGX_LOG_WARN, s->connection->log, 0, + "bandwidth_detection: start - not received command packet!"); + return NGX_ERROR; + } + + bw_ctx->active = 1; + bw_ctx->bw_begin_time = ngx_cached_time->msec; + bw_ctx->pkt_sent = 1; + bw_ctx->pkt_received = 0; + bw_ctx->pkt_recv_time1 = 0; + bw_ctx->pkt_recv_time2 = 0; + bw_ctx->cum_latency = 0; + bw_ctx->latency = acf->latency_min; + bw_ctx->bytes_out = lv_ctx->stream->bw_out.bytes; + + // Send first packet with empty payload - for latency calculation + return ngx_rtmp_send_bwcheck(s, NULL); +} + + +/** + * End bandwidth detection here + */ +static ngx_int_t +ngx_rtmp_bandwidth_detection_check_result(ngx_rtmp_session_t *s) +{ + + ngx_rtmp_bandwidth_detection_app_conf_t *acf; + ngx_rtmp_bandwidth_detection_ctx_t *bw_ctx; + ngx_rtmp_live_ctx_t *lv_ctx; + ngx_uint_t timePassed; + ngx_uint_t deltaDown; + double deltaTime; + double kbitDown; + uint64_t bytesOut; + + acf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_bandwidth_detection_module); + if (acf == NULL) { + ngx_log_error(NGX_LOG_WARN, s->connection->log, 0, + "bandwidth_detection: check - no app config!"); + return NGX_ERROR; + } + + if (!acf->test_time) { + ngx_log_error(NGX_LOG_WARN, s->connection->log, 0, + "bandwidth_detection: check - no test time!"); + return NGX_ERROR; + } + + bw_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_bandwidth_detection_module); + if (bw_ctx == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0, + "bandwidth_detection: check - no bw context!"); + return NGX_OK; + } + if (!bw_ctx->active) { + ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0, + "bandwidth_detection: check - not active!"); + return NGX_OK; + } + + lv_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); + if (lv_ctx == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0, + "bandwidth_detection: check - no live context!"); + return NGX_OK; + } + if (lv_ctx->stream == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0, + "bandwidth_detection: check - no live stream!"); + return NGX_OK; + } + + timePassed = ngx_cached_time->msec - bw_ctx->bw_begin_time; + bw_ctx->pkt_received ++; + + if (bw_ctx->pkt_received == 1) { + bw_ctx->latency = ngx_min(timePassed, acf->latency_max); + bw_ctx->latency = ngx_max(bw_ctx->latency, acf->latency_min); + bw_ctx->pkt_recv_time1 = ngx_cached_time->msec; + } + + if (bw_ctx->pkt_received == 2) { + bw_ctx->pkt_recv_time2 = ngx_cached_time->msec; + } + + // If we have a hi-speed network with low latency send more to determine + // better bandwidth numbers, send no more than 6 packets + if (bw_ctx->pkt_received == 2 && timePassed < acf->test_time) { + + bw_ctx->pkt_sent ++; + bw_ctx->cum_latency ++; + return ngx_rtmp_send_bwcheck(s, acf->payload); + + } else if (bw_ctx->pkt_received == bw_ctx->pkt_sent) { + + // See if we need to normalize latency + if ( bw_ctx->latency >= acf->latency_undef ) { + + // make sure we detect sattelite and modem correctly + if (bw_ctx->pkt_recv_time2 - bw_ctx->pkt_recv_time1 > 1000) { + bw_ctx->latency = acf->latency_undef; + } + + } + + bytesOut = lv_ctx->stream->bw_out.bytes; + deltaDown = (bytesOut - bw_ctx->bytes_out) *8/1000.; + deltaTime = ( (ngx_cached_time->msec - bw_ctx->bw_begin_time) - (bw_ctx->latency*bw_ctx->cum_latency))/1000.; + + if (deltaTime <= 0) deltaTime = (ngx_cached_time->msec - bw_ctx->bw_begin_time)/1000.; + + kbitDown = deltaDown/deltaTime; + + ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0, + "bandwidth_detection: check - done!"); + ngx_log_debug5(NGX_LOG_DEBUG, s->connection->log, 0, + "bandwidth_detection: check - kbitDown=%ui, deltaDown=%.3f, deltaTime=%.3f, latency=%.3f, KBytes=%ui", + kbitDown, deltaDown, deltaTime, bw_ctx->latency, (bytesOut - bw_ctx->bytes_out)/1024); + + return ngx_rtmp_send_bwdone(s, kbitDown, deltaDown, deltaTime, bw_ctx->latency); + } + + if (bw_ctx->pkt_sent == 1 && bw_ctx->pkt_received == 1) { + // First call + return ngx_rtmp_send_bwcheck(s, acf->payload); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_bandwidth_detection_postconfiguration(ngx_conf_t *cf) +{ + ngx_rtmp_core_main_conf_t *cmcf; + ngx_rtmp_amf_handler_t *ch; + + cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module); + + ch = ngx_array_push(&cmcf->amf); + ngx_str_set(&ch->name, "checkBandwidth"); + ch->handler = ngx_rtmp_bandwidth_detection_start; + + ch = ngx_array_push(&cmcf->amf); + ngx_str_set(&ch->name, "_result"); + ch->handler = ngx_rtmp_bandwidth_detection_on_result; + + return NGX_OK; +} diff --git a/ngx_rtmp_bandwidth_detection_module.h b/ngx_rtmp_bandwidth_detection_module.h new file mode 100644 index 000000000..0f2d67084 --- /dev/null +++ b/ngx_rtmp_bandwidth_detection_module.h @@ -0,0 +1,50 @@ + +/* + * Copyright (C) Sergey Dryabzhinsky, 2016 + * + * Based on http://permalink.gmane.org/gmane.comp.web.flash.red5/5869 + * And live & stat modules + */ + + +#ifndef _NGX_RTMP_BANDWIDTH_DETECTION_H_INCLUDED_ +#define _NGX_RTMP_BANDWIDTH_DETECTION_H_INCLUDED_ + +#include +#include +#include "ngx_rtmp.h" +#include "ngx_rtmp_cmd_module.h" +#include "ngx_rtmp_bandwidth.h" +#include "ngx_rtmp_streams.h" + + +typedef struct ngx_rtmp_bandwidth_detection_ctx_s ngx_rtmp_bandwidth_detection_ctx_t; + +struct ngx_rtmp_bandwidth_detection_ctx_s { + ngx_rtmp_session_t *session; + uint64_t bytes_out; + ngx_msec_t bw_begin_time; + ngx_uint_t pkt_sent; + ngx_uint_t pkt_received; + ngx_msec_t pkt_recv_time1; + ngx_msec_t pkt_recv_time2; + ngx_uint_t cum_latency; + ngx_msec_t latency; + unsigned active:1; +}; + +typedef struct { + ngx_msec_t latency_min; // Minimal detectable latency, msec + ngx_msec_t latency_max; // Maximum latency assumed, msec + ngx_msec_t latency_undef; // Default latency for modem, msec + // or satellite connections or undetectable one + ngx_msec_t test_time; // How long test bandwidth, msec + + u_char *payload; // Payload data for all +} ngx_rtmp_bandwidth_detection_app_conf_t; + + +extern ngx_module_t ngx_rtmp_bandwidth_detection_module; + + +#endif /* _NGX_RTMP_BANDWIDTH_DETECTION_H_INCLUDED_ */ diff --git a/ngx_rtmp_send.c b/ngx_rtmp_send.c index 69dfed955..7087a631e 100644 --- a/ngx_rtmp_send.c +++ b/ngx_rtmp_send.c @@ -8,6 +8,7 @@ #include "ngx_rtmp.h" #include "ngx_rtmp_amf.h" #include "ngx_rtmp_streams.h" +#include "ngx_rtmp_transitions.h" #define NGX_RTMP_USER_START(s, tp) \ @@ -985,3 +986,141 @@ ngx_rtmp_send_sample_access(ngx_rtmp_session_t *s) return ngx_rtmp_send_shared_packet(s, ngx_rtmp_create_sample_access(s)); } + +/* -------------------------------------- For bandwidth detection ---------------------------------- */ + +ngx_chain_t * +ngx_rtmp_create_bwcheck(ngx_rtmp_session_t *s, u_char *payload) +{ + ngx_rtmp_header_t h; + + static double trans; + + static ngx_rtmp_amf_elt_t out_inf[] = { + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + NULL, 0 }, + + }; + + static ngx_rtmp_amf_elt_t out_elts[] = { + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + "onBWCheck", 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &trans, 0 }, + + { NGX_RTMP_AMF_NULL, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_OBJECT, + ngx_null_string, + out_inf, + sizeof(out_inf) }, + }; + + out_inf[0].data = payload; + trans = NGX_RTMP_BANDWIDTH_DETECTION_BWCHECK_TRANS; + + memset(&h, 0, sizeof(h)); + + h.type = NGX_RTMP_MSG_AMF_CMD; + h.csid = NGX_RTMP_CSID_AMF; + h.msid = NGX_RTMP_MSID; + + return ngx_rtmp_create_amf(s, &h, out_elts, + sizeof(out_elts) / sizeof(out_elts[0])); +} + +ngx_int_t +ngx_rtmp_send_bwcheck(ngx_rtmp_session_t *s, u_char *payload) +{ + return ngx_rtmp_send_shared_packet(s, + ngx_rtmp_create_bwcheck(s, payload)); +} + + +ngx_chain_t * +ngx_rtmp_create_bwdone(ngx_rtmp_session_t *s, + double kbitDown, ngx_uint_t deltaDown, double deltaTime, ngx_msec_t latency) +{ + ngx_rtmp_header_t h; + + static double trans; + static struct { + double kbitDown; + ngx_uint_t deltaDown; + double deltaTime; + ngx_msec_t latency; + } v; + + static ngx_rtmp_amf_elt_t out_inf[] = { + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &v.kbitDown, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &v.deltaDown, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &v.deltaTime, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &v.latency, 0 }, + + }; + + static ngx_rtmp_amf_elt_t out_elts[] = { + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + "onBWDone", 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &trans, 0 }, + + { NGX_RTMP_AMF_NULL, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_OBJECT, + ngx_null_string, + out_inf, + sizeof(out_inf) }, + }; + + ngx_memzero(&v, sizeof(v)); + v.kbitDown = kbitDown; + v.deltaDown = deltaDown; + v.deltaTime = deltaTime; + v.latency = latency; + trans = NGX_RTMP_BANDWIDTH_DETECTION_BWDONE_TRANS; + + memset(&h, 0, sizeof(h)); + + h.type = NGX_RTMP_MSG_AMF_CMD; + h.csid = NGX_RTMP_CSID_AMF; + h.msid = NGX_RTMP_MSID; + + return ngx_rtmp_create_amf(s, &h, out_elts, + sizeof(out_elts) / sizeof(out_elts[0])); +} + + +ngx_int_t +ngx_rtmp_send_bwdone(ngx_rtmp_session_t *s, + double kbitDown, ngx_uint_t deltaDown, double deltaTime, ngx_msec_t latency) +{ + return ngx_rtmp_send_shared_packet(s, + ngx_rtmp_create_bwdone(s, kbitDown, deltaDown, deltaTime, latency)); +} diff --git a/ngx_rtmp_transitions.h b/ngx_rtmp_transitions.h new file mode 100644 index 000000000..be1cca5f0 --- /dev/null +++ b/ngx_rtmp_transitions.h @@ -0,0 +1,15 @@ + +/* + * Copyright (C) Sergey Dryabzhinsky, 2016 + * + * Based on http://permalink.gmane.org/gmane.comp.web.flash.red5/5869 + * And live & stat modules + */ + +#ifndef _NGX_RTMP_TRANSITIONS_H_INCLUDED_ +#define _NGX_RTMP_TRANSITIONS_H_INCLUDED_ + +#define NGX_RTMP_BANDWIDTH_DETECTION_BWCHECK_TRANS 3 +#define NGX_RTMP_BANDWIDTH_DETECTION_BWDONE_TRANS 4 + +#endif // _NGX_RTMP_TRANSITIONS_H_INCLUDED_ From 1c57ac07c9b43beb0aecad1bd3909534ff16aca3 Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Sun, 28 Feb 2016 13:58:20 +0300 Subject: [PATCH 02/19] Fix _result log values --- ngx_rtmp_bandwidth_detection_module.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ngx_rtmp_bandwidth_detection_module.c b/ngx_rtmp_bandwidth_detection_module.c index c8480e1a2..7bacdf03b 100644 --- a/ngx_rtmp_bandwidth_detection_module.c +++ b/ngx_rtmp_bandwidth_detection_module.c @@ -203,9 +203,9 @@ ngx_rtmp_bandwidth_detection_on_result(ngx_rtmp_session_t *s, ngx_rtmp_header_t return NGX_ERROR; } - ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "relay: _result: level='%s' code='%s' description='%s'", - v.level, v.code, v.desc); + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "bandwidth_detection: _result: trans='%f' count='%ui'", + v.trans, v.count); switch ((ngx_int_t)v.trans) { case NGX_RTMP_BANDWIDTH_DETECTION_BWCHECK_TRANS: From 6a5398058d97dbbfadf1a4fbe6fec2b33fdb2c43 Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Sun, 28 Feb 2016 14:34:13 +0300 Subject: [PATCH 03/19] Fix sending messages --- ngx_rtmp_bandwidth_detection_module.c | 6 +++++- ngx_rtmp_send.c | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ngx_rtmp_bandwidth_detection_module.c b/ngx_rtmp_bandwidth_detection_module.c index 7bacdf03b..75009d27d 100644 --- a/ngx_rtmp_bandwidth_detection_module.c +++ b/ngx_rtmp_bandwidth_detection_module.c @@ -234,11 +234,15 @@ ngx_rtmp_bandwidth_detection_start(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_rtmp_bandwidth_detection_ctx_t *bw_ctx; ngx_rtmp_live_ctx_t *lv_ctx; + static struct { + double trans; + } v; + static ngx_rtmp_amf_elt_t in_elts[] = { { NGX_RTMP_AMF_NUMBER, ngx_null_string, - "checkBandwidth", 0 }, + &v.trans, 0 }, }; diff --git a/ngx_rtmp_send.c b/ngx_rtmp_send.c index 7087a631e..64390d5ba 100644 --- a/ngx_rtmp_send.c +++ b/ngx_rtmp_send.c @@ -1024,7 +1024,10 @@ ngx_rtmp_create_bwcheck(ngx_rtmp_session_t *s, u_char *payload) sizeof(out_inf) }, }; - out_inf[0].data = payload; + if (payload != NULL) { + out_inf[0].data = payload; + out_inf[0].len = ngx_strlen(payload); + } trans = NGX_RTMP_BANDWIDTH_DETECTION_BWCHECK_TRANS; memset(&h, 0, sizeof(h)); From 20c82967b43078713174cb0a4faa537f1f7658d8 Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Sun, 28 Feb 2016 14:57:42 +0300 Subject: [PATCH 04/19] My fork link in stat --- stat.xsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stat.xsl b/stat.xsl index 7411c5e26..f8bdd0710 100644 --- a/stat.xsl +++ b/stat.xsl @@ -17,7 +17,7 @@
- Generated by + Generated by nginx-rtmp-module , nginx , pid , From dbc5553841f42219ea690d9068001ce36704a1ce Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Sun, 28 Feb 2016 15:25:53 +0300 Subject: [PATCH 05/19] More debug, add _error handler --- ngx_rtmp_bandwidth_detection_module.c | 123 ++++++++++++++++---------- ngx_rtmp_bandwidth_detection_module.h | 2 - 2 files changed, 75 insertions(+), 50 deletions(-) diff --git a/ngx_rtmp_bandwidth_detection_module.c b/ngx_rtmp_bandwidth_detection_module.c index 75009d27d..64142f873 100644 --- a/ngx_rtmp_bandwidth_detection_module.c +++ b/ngx_rtmp_bandwidth_detection_module.c @@ -28,6 +28,9 @@ static ngx_int_t ngx_rtmp_bandwidth_detection_start(ngx_rtmp_session_t *s, ngx_r static ngx_int_t ngx_rtmp_bandwidth_detection_check_result(ngx_rtmp_session_t *s); +static u_char *payload; // Payload data for all + + static ngx_command_t ngx_rtmp_bandwidth_detection_commands[] = { { ngx_string("latency_min"), @@ -107,9 +110,9 @@ ngx_rtmp_bandwidth_detection_create_app_conf(ngx_conf_t *cf) acf->test_time = NGX_CONF_UNSET_MSEC; /* Init payload only once with some random garbage */ - acf->payload = ngx_pcalloc(cf->pool, NGX_RTMP_BANDWIDTH_DETECTION_PAYLOAD_LENGTH + 1); + payload = ngx_pcalloc(cf->pool, NGX_RTMP_BANDWIDTH_DETECTION_PAYLOAD_LENGTH + 1); for (i=0; ipayload[i] = ngx_random(); + payload[i] = ngx_random(); } return acf; @@ -127,9 +130,6 @@ ngx_rtmp_bandwidth_detection_merge_app_conf(ngx_conf_t *cf, void *parent, void * ngx_conf_merge_msec_value(conf->latency_undef, prev->latency_undef, 100); ngx_conf_merge_msec_value(conf->test_time, prev->test_time, 2000); - // One payload for all - conf->payload = prev->payload; - return NGX_CONF_OK; } @@ -167,14 +167,6 @@ ngx_rtmp_bandwidth_detection_on_result(ngx_rtmp_session_t *s, ngx_rtmp_header_t ngx_uint_t count; } v; - static ngx_rtmp_amf_elt_t in_inf[] = { - - { NGX_RTMP_AMF_NUMBER, - ngx_null_string, - &v.count, 0 }, - - }; - static ngx_rtmp_amf_elt_t in_elts[] = { { NGX_RTMP_AMF_NUMBER, @@ -185,14 +177,19 @@ ngx_rtmp_bandwidth_detection_on_result(ngx_rtmp_session_t *s, ngx_rtmp_header_t ngx_null_string, NULL, 0 }, - { NGX_RTMP_AMF_OBJECT, + { NGX_RTMP_AMF_NUMBER, ngx_null_string, - in_inf, sizeof(in_inf) }, + &v.count, 0 }, + }; + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "bandwidth_detection: _result"); ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_bandwidth_detection_module); if (ctx == NULL || s->relay) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "bandwidth_detection: _result - no context or relay!"); return NGX_OK; } @@ -200,6 +197,8 @@ ngx_rtmp_bandwidth_detection_on_result(ngx_rtmp_session_t *s, ngx_rtmp_header_t if (ngx_rtmp_receive_amf(s, in, in_elts, sizeof(in_elts) / sizeof(in_elts[0]))) { + ngx_log_error(NGX_LOG_WARN, s->connection->log, 0, + "bandwidth_detection: _result - no packet readed!"); return NGX_ERROR; } @@ -210,7 +209,6 @@ ngx_rtmp_bandwidth_detection_on_result(ngx_rtmp_session_t *s, ngx_rtmp_header_t switch ((ngx_int_t)v.trans) { case NGX_RTMP_BANDWIDTH_DETECTION_BWCHECK_TRANS: return ngx_rtmp_bandwidth_detection_check_result(s); - break; case NGX_RTMP_BANDWIDTH_DETECTION_BWDONE_TRANS: /* Need to test it. Maybe need to set this before send bwDone. */ @@ -223,16 +221,11 @@ ngx_rtmp_bandwidth_detection_on_result(ngx_rtmp_session_t *s, ngx_rtmp_header_t } -/** - * Start bandwidth detection here - */ static ngx_int_t -ngx_rtmp_bandwidth_detection_start(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) +ngx_rtmp_bandwidth_detection_on_error(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) { - - ngx_rtmp_bandwidth_detection_app_conf_t *acf; - ngx_rtmp_bandwidth_detection_ctx_t *bw_ctx; - ngx_rtmp_live_ctx_t *lv_ctx; + ngx_rtmp_bandwidth_detection_ctx_t *ctx; static struct { double trans; @@ -246,8 +239,42 @@ ngx_rtmp_bandwidth_detection_start(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, }; + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "bandwidth_detection: _error"); + + ngx_memzero(&v, sizeof(v)); + if (ngx_rtmp_receive_amf(s, in, in_elts, + sizeof(in_elts) / sizeof(in_elts[0]))) + { + ngx_log_error(NGX_LOG_WARN, s->connection->log, 0, + "bandwidth_detection: _error - no packet readed!"); + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "bandwidth_detection: _error: trans='%f''", + v.trans); + + return NGX_OK; +} + + +/** + * Start bandwidth detection here + */ +static ngx_int_t +ngx_rtmp_bandwidth_detection_start(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) +{ + + ngx_rtmp_bandwidth_detection_app_conf_t *acf; + ngx_rtmp_bandwidth_detection_ctx_t *bw_ctx; + ngx_rtmp_live_ctx_t *lv_ctx; + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "bandwidth_detection: start"); + if (s->relay) { - ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0, + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "bandwidth_detection: start - no relay please!"); return NGX_ERROR; } @@ -260,37 +287,30 @@ ngx_rtmp_bandwidth_detection_start(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, } if (!acf->test_time || in == NULL || in->buf == NULL) { - ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0, + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "bandwidth_detection: start - no test time or no buffer!"); return NGX_OK; } bw_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_bandwidth_detection_module); if (bw_ctx == NULL) { - ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0, + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "bandwidth_detection: start - no bw context!"); return NGX_OK; } if (bw_ctx->active) { - ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0, + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "bandwidth_detection: start - already active!"); return NGX_OK; } lv_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); if (lv_ctx == NULL) { - ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0, + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "bandwidth_detection: start - no live context!"); return NGX_OK; } - if (ngx_rtmp_receive_amf(s, in, in_elts, - sizeof(in_elts) / sizeof(in_elts[0])) != NGX_OK) { - ngx_log_error(NGX_LOG_WARN, s->connection->log, 0, - "bandwidth_detection: start - not received command packet!"); - return NGX_ERROR; - } - bw_ctx->active = 1; bw_ctx->bw_begin_time = ngx_cached_time->msec; bw_ctx->pkt_sent = 1; @@ -322,6 +342,9 @@ ngx_rtmp_bandwidth_detection_check_result(ngx_rtmp_session_t *s) double kbitDown; uint64_t bytesOut; + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "bandwidth_detection: check"); + acf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_bandwidth_detection_module); if (acf == NULL) { ngx_log_error(NGX_LOG_WARN, s->connection->log, 0, @@ -337,24 +360,24 @@ ngx_rtmp_bandwidth_detection_check_result(ngx_rtmp_session_t *s) bw_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_bandwidth_detection_module); if (bw_ctx == NULL) { - ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0, + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "bandwidth_detection: check - no bw context!"); return NGX_OK; } if (!bw_ctx->active) { - ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0, + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "bandwidth_detection: check - not active!"); return NGX_OK; } lv_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); if (lv_ctx == NULL) { - ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0, + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "bandwidth_detection: check - no live context!"); return NGX_OK; } if (lv_ctx->stream == NULL) { - ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0, + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "bandwidth_detection: check - no live stream!"); return NGX_OK; } @@ -378,7 +401,7 @@ ngx_rtmp_bandwidth_detection_check_result(ngx_rtmp_session_t *s) bw_ctx->pkt_sent ++; bw_ctx->cum_latency ++; - return ngx_rtmp_send_bwcheck(s, acf->payload); + return ngx_rtmp_send_bwcheck(s, payload); } else if (bw_ctx->pkt_received == bw_ctx->pkt_sent) { @@ -400,9 +423,9 @@ ngx_rtmp_bandwidth_detection_check_result(ngx_rtmp_session_t *s) kbitDown = deltaDown/deltaTime; - ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0, + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "bandwidth_detection: check - done!"); - ngx_log_debug5(NGX_LOG_DEBUG, s->connection->log, 0, + ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "bandwidth_detection: check - kbitDown=%ui, deltaDown=%.3f, deltaTime=%.3f, latency=%.3f, KBytes=%ui", kbitDown, deltaDown, deltaTime, bw_ctx->latency, (bytesOut - bw_ctx->bytes_out)/1024); @@ -411,7 +434,7 @@ ngx_rtmp_bandwidth_detection_check_result(ngx_rtmp_session_t *s) if (bw_ctx->pkt_sent == 1 && bw_ctx->pkt_received == 1) { // First call - return ngx_rtmp_send_bwcheck(s, acf->payload); + return ngx_rtmp_send_bwcheck(s, payload); } return NGX_OK; @@ -426,13 +449,17 @@ ngx_rtmp_bandwidth_detection_postconfiguration(ngx_conf_t *cf) cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module); - ch = ngx_array_push(&cmcf->amf); - ngx_str_set(&ch->name, "checkBandwidth"); - ch->handler = ngx_rtmp_bandwidth_detection_start; - ch = ngx_array_push(&cmcf->amf); ngx_str_set(&ch->name, "_result"); ch->handler = ngx_rtmp_bandwidth_detection_on_result; + ch = ngx_array_push(&cmcf->amf); + ngx_str_set(&ch->name, "_error"); + ch->handler = ngx_rtmp_bandwidth_detection_on_error; + + ch = ngx_array_push(&cmcf->amf); + ngx_str_set(&ch->name, "checkBandwidth"); + ch->handler = ngx_rtmp_bandwidth_detection_start; + return NGX_OK; } diff --git a/ngx_rtmp_bandwidth_detection_module.h b/ngx_rtmp_bandwidth_detection_module.h index 0f2d67084..2cb2fa149 100644 --- a/ngx_rtmp_bandwidth_detection_module.h +++ b/ngx_rtmp_bandwidth_detection_module.h @@ -39,8 +39,6 @@ typedef struct { ngx_msec_t latency_undef; // Default latency for modem, msec // or satellite connections or undetectable one ngx_msec_t test_time; // How long test bandwidth, msec - - u_char *payload; // Payload data for all } ngx_rtmp_bandwidth_detection_app_conf_t; From 5a32fd4082133e357fdd4899848c8da39ecebed2 Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Sun, 28 Feb 2016 15:30:26 +0300 Subject: [PATCH 06/19] Remove unused var --- ngx_rtmp_bandwidth_detection_module.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/ngx_rtmp_bandwidth_detection_module.c b/ngx_rtmp_bandwidth_detection_module.c index 64142f873..09e3225ef 100644 --- a/ngx_rtmp_bandwidth_detection_module.c +++ b/ngx_rtmp_bandwidth_detection_module.c @@ -225,8 +225,6 @@ static ngx_int_t ngx_rtmp_bandwidth_detection_on_error(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) { - ngx_rtmp_bandwidth_detection_ctx_t *ctx; - static struct { double trans; } v; From 272f719d675053d616bb43f38ed0e0ae31307360 Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Sun, 28 Feb 2016 16:21:03 +0300 Subject: [PATCH 07/19] Create bw context if none, send errors in some cases --- ngx_rtmp_bandwidth_detection_module.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ngx_rtmp_bandwidth_detection_module.c b/ngx_rtmp_bandwidth_detection_module.c index 09e3225ef..7a3c60da1 100644 --- a/ngx_rtmp_bandwidth_detection_module.c +++ b/ngx_rtmp_bandwidth_detection_module.c @@ -104,7 +104,7 @@ ngx_rtmp_bandwidth_detection_create_app_conf(ngx_conf_t *cf) return NULL; } - acf->latency_max = NGX_CONF_UNSET; + acf->latency_max = NGX_CONF_UNSET_MSEC; acf->latency_min = NGX_CONF_UNSET_MSEC; acf->latency_undef = NGX_CONF_UNSET_MSEC; acf->test_time = NGX_CONF_UNSET_MSEC; @@ -287,15 +287,19 @@ ngx_rtmp_bandwidth_detection_start(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, if (!acf->test_time || in == NULL || in->buf == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "bandwidth_detection: start - no test time or no buffer!"); - return NGX_OK; + return NGX_ERROR; } bw_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_bandwidth_detection_module); if (bw_ctx == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "bandwidth_detection: start - no bw context!"); - return NGX_OK; + "bandwidth_detection: start - no context! create new and set for module and session!"); + bw_ctx = ngx_palloc(s->connection->pool, sizeof(ngx_rtmp_bandwidth_detection_ctx_t)); + ngx_rtmp_set_ctx(s, bw_ctx, ngx_rtmp_bandwidth_detection_module); } + + ngx_memzero(bw_ctx, sizeof(*bw_ctx)); + if (bw_ctx->active) { ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "bandwidth_detection: start - already active!"); @@ -306,7 +310,7 @@ ngx_rtmp_bandwidth_detection_start(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, if (lv_ctx == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "bandwidth_detection: start - no live context!"); - return NGX_OK; + return NGX_ERROR; } bw_ctx->active = 1; From 58c4ddd40e081d9d1559697a4ccf2e010f950308 Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Sun, 28 Feb 2016 17:14:10 +0300 Subject: [PATCH 08/19] Remove live context use, reorder files and module --- config | 6 ++-- ngx_rtmp_bandwidth_detection_module.c | 40 ++++++++++----------------- 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/config b/config index 0b54a2f17..66cc91726 100644 --- a/config +++ b/config @@ -6,8 +6,8 @@ RTMP_CORE_MODULES=" \ ngx_rtmp_codec_module \ ngx_rtmp_access_module \ ngx_rtmp_record_module \ - ngx_rtmp_live_module \ ngx_rtmp_bandwidth_detection_module \ + ngx_rtmp_live_module \ ngx_rtmp_play_module \ ngx_rtmp_flv_module \ ngx_rtmp_mp4_module \ @@ -33,8 +33,8 @@ RTMP_DEPS=" \ $ngx_addon_dir/ngx_rtmp_eval.h \ $ngx_addon_dir/ngx_rtmp.h \ $ngx_addon_dir/ngx_rtmp_version.h \ - $ngx_addon_dir/ngx_rtmp_live_module.h \ $ngx_addon_dir/ngx_rtmp_bandwidth_detection_module.h \ + $ngx_addon_dir/ngx_rtmp_live_module.h \ $ngx_addon_dir/ngx_rtmp_netcall_module.h \ $ngx_addon_dir/ngx_rtmp_play_module.h \ $ngx_addon_dir/ngx_rtmp_record_module.h \ @@ -60,8 +60,8 @@ RTMP_CORE_SRCS=" \ $ngx_addon_dir/ngx_rtmp_codec_module.c \ $ngx_addon_dir/ngx_rtmp_access_module.c \ $ngx_addon_dir/ngx_rtmp_record_module.c \ - $ngx_addon_dir/ngx_rtmp_live_module.c \ $ngx_addon_dir/ngx_rtmp_bandwidth_detection_module.c \ + $ngx_addon_dir/ngx_rtmp_live_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 \ diff --git a/ngx_rtmp_bandwidth_detection_module.c b/ngx_rtmp_bandwidth_detection_module.c index 7a3c60da1..94c023e88 100644 --- a/ngx_rtmp_bandwidth_detection_module.c +++ b/ngx_rtmp_bandwidth_detection_module.c @@ -266,7 +266,6 @@ ngx_rtmp_bandwidth_detection_start(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_rtmp_bandwidth_detection_app_conf_t *acf; ngx_rtmp_bandwidth_detection_ctx_t *bw_ctx; - ngx_rtmp_live_ctx_t *lv_ctx; ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "bandwidth_detection: start"); @@ -294,11 +293,18 @@ ngx_rtmp_bandwidth_detection_start(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, if (bw_ctx == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "bandwidth_detection: start - no context! create new and set for module and session!"); + bw_ctx = ngx_palloc(s->connection->pool, sizeof(ngx_rtmp_bandwidth_detection_ctx_t)); + if (bw_ctx == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "bandwidth_detection: start - no context created!"); + return NGX_ERROR; + } + ngx_rtmp_set_ctx(s, bw_ctx, ngx_rtmp_bandwidth_detection_module); - } + ngx_memzero(bw_ctx, sizeof(*bw_ctx)); - ngx_memzero(bw_ctx, sizeof(*bw_ctx)); + } if (bw_ctx->active) { ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, @@ -306,13 +312,6 @@ ngx_rtmp_bandwidth_detection_start(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, return NGX_OK; } - lv_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); - if (lv_ctx == NULL) { - ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "bandwidth_detection: start - no live context!"); - return NGX_ERROR; - } - bw_ctx->active = 1; bw_ctx->bw_begin_time = ngx_cached_time->msec; bw_ctx->pkt_sent = 1; @@ -321,7 +320,7 @@ ngx_rtmp_bandwidth_detection_start(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, bw_ctx->pkt_recv_time2 = 0; bw_ctx->cum_latency = 0; bw_ctx->latency = acf->latency_min; - bw_ctx->bytes_out = lv_ctx->stream->bw_out.bytes; + bw_ctx->bytes_out = s->out_bytes; // Send first packet with empty payload - for latency calculation return ngx_rtmp_send_bwcheck(s, NULL); @@ -337,7 +336,6 @@ ngx_rtmp_bandwidth_detection_check_result(ngx_rtmp_session_t *s) ngx_rtmp_bandwidth_detection_app_conf_t *acf; ngx_rtmp_bandwidth_detection_ctx_t *bw_ctx; - ngx_rtmp_live_ctx_t *lv_ctx; ngx_uint_t timePassed; ngx_uint_t deltaDown; double deltaTime; @@ -372,18 +370,6 @@ ngx_rtmp_bandwidth_detection_check_result(ngx_rtmp_session_t *s) return NGX_OK; } - lv_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); - if (lv_ctx == NULL) { - ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "bandwidth_detection: check - no live context!"); - return NGX_OK; - } - if (lv_ctx->stream == NULL) { - ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "bandwidth_detection: check - no live stream!"); - return NGX_OK; - } - timePassed = ngx_cached_time->msec - bw_ctx->bw_begin_time; bw_ctx->pkt_received ++; @@ -417,7 +403,7 @@ ngx_rtmp_bandwidth_detection_check_result(ngx_rtmp_session_t *s) } - bytesOut = lv_ctx->stream->bw_out.bytes; + bytesOut = s->out_bytes; deltaDown = (bytesOut - bw_ctx->bytes_out) *8/1000.; deltaTime = ( (ngx_cached_time->msec - bw_ctx->bw_begin_time) - (bw_ctx->latency*bw_ctx->cum_latency))/1000.; @@ -463,5 +449,9 @@ ngx_rtmp_bandwidth_detection_postconfiguration(ngx_conf_t *cf) ngx_str_set(&ch->name, "checkBandwidth"); ch->handler = ngx_rtmp_bandwidth_detection_start; + ch = ngx_array_push(&cmcf->amf); + ngx_str_set(&ch->name, "onClientBWCheck"); + ch->handler = ngx_rtmp_bandwidth_detection_start; + return NGX_OK; } From 7f64585b759629ebf8a930f6ad2ef82d24bf6636 Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Sun, 28 Feb 2016 18:07:29 +0300 Subject: [PATCH 09/19] Set payload length --- ngx_rtmp_bandwidth_detection_module.c | 6 +++--- ngx_rtmp_send.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ngx_rtmp_bandwidth_detection_module.c b/ngx_rtmp_bandwidth_detection_module.c index 94c023e88..91abacbbd 100644 --- a/ngx_rtmp_bandwidth_detection_module.c +++ b/ngx_rtmp_bandwidth_detection_module.c @@ -323,7 +323,7 @@ ngx_rtmp_bandwidth_detection_start(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, bw_ctx->bytes_out = s->out_bytes; // Send first packet with empty payload - for latency calculation - return ngx_rtmp_send_bwcheck(s, NULL); + return ngx_rtmp_send_bwcheck(s, NULL, 0); } @@ -389,7 +389,7 @@ ngx_rtmp_bandwidth_detection_check_result(ngx_rtmp_session_t *s) bw_ctx->pkt_sent ++; bw_ctx->cum_latency ++; - return ngx_rtmp_send_bwcheck(s, payload); + return ngx_rtmp_send_bwcheck(s, payload, NGX_RTMP_BANDWIDTH_DETECTION_PAYLOAD_LENGTH); } else if (bw_ctx->pkt_received == bw_ctx->pkt_sent) { @@ -422,7 +422,7 @@ ngx_rtmp_bandwidth_detection_check_result(ngx_rtmp_session_t *s) if (bw_ctx->pkt_sent == 1 && bw_ctx->pkt_received == 1) { // First call - return ngx_rtmp_send_bwcheck(s, payload); + return ngx_rtmp_send_bwcheck(s, payload, NGX_RTMP_BANDWIDTH_DETECTION_PAYLOAD_LENGTH); } return NGX_OK; diff --git a/ngx_rtmp_send.c b/ngx_rtmp_send.c index 64390d5ba..069b773b4 100644 --- a/ngx_rtmp_send.c +++ b/ngx_rtmp_send.c @@ -990,7 +990,7 @@ ngx_rtmp_send_sample_access(ngx_rtmp_session_t *s) /* -------------------------------------- For bandwidth detection ---------------------------------- */ ngx_chain_t * -ngx_rtmp_create_bwcheck(ngx_rtmp_session_t *s, u_char *payload) +ngx_rtmp_create_bwcheck(ngx_rtmp_session_t *s, u_char *payload, size_t plength) { ngx_rtmp_header_t h; @@ -1041,10 +1041,10 @@ ngx_rtmp_create_bwcheck(ngx_rtmp_session_t *s, u_char *payload) } ngx_int_t -ngx_rtmp_send_bwcheck(ngx_rtmp_session_t *s, u_char *payload) +ngx_rtmp_send_bwcheck(ngx_rtmp_session_t *s, u_char *payload, size_t plength) { return ngx_rtmp_send_shared_packet(s, - ngx_rtmp_create_bwcheck(s, payload)); + ngx_rtmp_create_bwcheck(s, payload, plength)); } From 2d9b53fb951ef0fb4853adea13dd94f162904b97 Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Sun, 28 Feb 2016 18:37:01 +0300 Subject: [PATCH 10/19] Add client side bandwidth detection --- ngx_rtmp.h | 2 + ngx_rtmp_bandwidth_detection_module.c | 84 ++++++++++++++++++++++++++- ngx_rtmp_send.c | 66 +++++++++++++++++++++ 3 files changed, 151 insertions(+), 1 deletion(-) diff --git a/ngx_rtmp.h b/ngx_rtmp.h index 463b9f3ff..4179bb12c 100644 --- a/ngx_rtmp.h +++ b/ngx_rtmp.h @@ -592,6 +592,8 @@ ngx_int_t ngx_rtmp_send_fi(ngx_rtmp_session_t *s); ngx_int_t ngx_rtmp_send_bwcheck(ngx_rtmp_session_t *s, u_char *payload); ngx_int_t ngx_rtmp_send_bwdone(ngx_rtmp_session_t *s, double kbitDown, ngx_uint_t deltaDown, double deltaTime, ngx_msec_t latency); +ngx_int_t ngx_rtmp_send_onclientbwcheck(ngx_rtmp_session_t *s, double inTrans, + double cOutBytes, double cInBytes, ngx_uint_t inTime); /* Frame types */ diff --git a/ngx_rtmp_bandwidth_detection_module.c b/ngx_rtmp_bandwidth_detection_module.c index 91abacbbd..99fef2629 100644 --- a/ngx_rtmp_bandwidth_detection_module.c +++ b/ngx_rtmp_bandwidth_detection_module.c @@ -327,6 +327,88 @@ ngx_rtmp_bandwidth_detection_start(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, } +/** + * Bandwidth detection from client side + */ +static ngx_int_t +ngx_rtmp_bandwidth_detection_clientcheck(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) +{ + + ngx_rtmp_bandwidth_detection_app_conf_t *acf; + ngx_rtmp_bandwidth_detection_ctx_t *bw_ctx; + + static struct { + double trans; + ngx_msec_t time; + } v; + + static ngx_rtmp_amf_elt_t in_elts[] = { + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &v.trans, 0 }, + + { NGX_RTMP_AMF_NULL, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &v.time, 0 }, + + }; + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "bandwidth_detection: bwcheck"); + + if (s->relay) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "bandwidth_detection: bwcheck - no relay please!"); + return NGX_ERROR; + } + + acf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_bandwidth_detection_module); + if (acf == NULL) { + ngx_log_error(NGX_LOG_WARN, s->connection->log, 0, + "bandwidth_detection: bwcheck - no app config!"); + return NGX_ERROR; + } + + bw_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_bandwidth_detection_module); + if (bw_ctx == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "bandwidth_detection: bwcheck - no context! create new and set for module and session!"); + + bw_ctx = ngx_palloc(s->connection->pool, sizeof(ngx_rtmp_bandwidth_detection_ctx_t)); + if (bw_ctx == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "bandwidth_detection: bwcheck - no context created!"); + return NGX_ERROR; + } + + ngx_rtmp_set_ctx(s, bw_ctx, ngx_rtmp_bandwidth_detection_module); + ngx_memzero(bw_ctx, sizeof(*bw_ctx)); + + } + + ngx_memzero(&v, sizeof(v)); + if (ngx_rtmp_receive_amf(s, in, in_elts, + sizeof(in_elts) / sizeof(in_elts[0]))) + { + ngx_log_error(NGX_LOG_WARN, s->connection->log, 0, + "bandwidth_detection: bwcheck - no packet readed!"); + return NGX_ERROR; + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "bandwidth_detection: bwcheck: trans='%f' time='%ui'", + v.trans, v.time); + + // Send first packet with empty payload - for latency calculation + return ngx_rtmp_send_onclientbwcheck(s, v.trans, s->out_bytes, s->in_bytes, v.time); +} + + /** * End bandwidth detection here */ @@ -451,7 +533,7 @@ ngx_rtmp_bandwidth_detection_postconfiguration(ngx_conf_t *cf) ch = ngx_array_push(&cmcf->amf); ngx_str_set(&ch->name, "onClientBWCheck"); - ch->handler = ngx_rtmp_bandwidth_detection_start; + ch->handler = ngx_rtmp_bandwidth_detection_clientcheck; return NGX_OK; } diff --git a/ngx_rtmp_send.c b/ngx_rtmp_send.c index 069b773b4..4552df7c0 100644 --- a/ngx_rtmp_send.c +++ b/ngx_rtmp_send.c @@ -1127,3 +1127,69 @@ ngx_rtmp_send_bwdone(ngx_rtmp_session_t *s, return ngx_rtmp_send_shared_packet(s, ngx_rtmp_create_bwdone(s, kbitDown, deltaDown, deltaTime, latency)); } + + +ngx_int_t +ngx_rtmp_send_onclientbwcheck(ngx_rtmp_session_t *s, double inTrans, + double cOutBytes, double cInBytes, ngx_uint_t inTime) +{ + ngx_rtmp_core_srv_conf_t *cscf; + ngx_rtmp_core_app_conf_t **cacfp; + ngx_uint_t n; + ngx_rtmp_header_t h; + u_char *p; + + static struct { + double cOutBytes; + double cInBytes; + ngx_msec_t time; + double trans; + } v; + + static ngx_rtmp_amf_elt_t out_inf[] = { + + { NGX_RTMP_AMF_NUMBER, + ngx_string("cOutBytes"), + &v.cOutBytes, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("cInBytes"), + &v.cInBytes, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("time"), + &v.time, 0 }, + + }; + + static ngx_rtmp_amf_elt_t out_elts[] = { + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + "_result", 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &v.trans, 0 }, + + { NGX_RTMP_AMF_OBJECT, + ngx_null_string, + out_obj, sizeof(out_inf) }, + + }; + + ngx_memzero(&v, sizeof(v)); + + v.cOutBytes = cOutBytes; + v.cInBytes = cInBytes; + v.time = inTime; + v.trans = inTrans; + + ngx_memzero(&h, sizeof(h)); + h.csid = NGX_RTMP_CSID_AMF_INI; + h.type = NGX_RTMP_MSG_AMF_CMD; + + return ngx_rtmp_send_amf(s, &h, out_elts, + sizeof(out_elts) / sizeof(out_elts[0])) == NGX_OK ? + NGX_DONE : NGX_ERROR; +} From 753442dad1efbcf88ef5dbc089eb95c4f3992710 Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Sun, 28 Feb 2016 18:40:37 +0300 Subject: [PATCH 11/19] Fix fucntion definition --- ngx_rtmp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ngx_rtmp.h b/ngx_rtmp.h index 4179bb12c..67f073c59 100644 --- a/ngx_rtmp.h +++ b/ngx_rtmp.h @@ -589,7 +589,7 @@ ngx_int_t ngx_rtmp_send_close_method(ngx_rtmp_session_t *s, char *methodName); ngx_int_t ngx_rtmp_send_fcpublish(ngx_rtmp_session_t *s, u_char *desc); ngx_int_t ngx_rtmp_send_fcunpublish(ngx_rtmp_session_t *s, u_char *desc); ngx_int_t ngx_rtmp_send_fi(ngx_rtmp_session_t *s); -ngx_int_t ngx_rtmp_send_bwcheck(ngx_rtmp_session_t *s, u_char *payload); +ngx_int_t ngx_rtmp_send_bwcheck(ngx_rtmp_session_t *s, u_char *payload, size_t plength); ngx_int_t ngx_rtmp_send_bwdone(ngx_rtmp_session_t *s, double kbitDown, ngx_uint_t deltaDown, double deltaTime, ngx_msec_t latency); ngx_int_t ngx_rtmp_send_onclientbwcheck(ngx_rtmp_session_t *s, double inTrans, From c4442230a7e36523ce861194cbe1339bdb6fcf79 Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Sun, 28 Feb 2016 18:43:40 +0300 Subject: [PATCH 12/19] Fix undefined var, remove unused --- ngx_rtmp_send.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ngx_rtmp_send.c b/ngx_rtmp_send.c index 4552df7c0..fbb87e746 100644 --- a/ngx_rtmp_send.c +++ b/ngx_rtmp_send.c @@ -1133,11 +1133,7 @@ ngx_int_t ngx_rtmp_send_onclientbwcheck(ngx_rtmp_session_t *s, double inTrans, double cOutBytes, double cInBytes, ngx_uint_t inTime) { - ngx_rtmp_core_srv_conf_t *cscf; - ngx_rtmp_core_app_conf_t **cacfp; - ngx_uint_t n; ngx_rtmp_header_t h; - u_char *p; static struct { double cOutBytes; @@ -1174,7 +1170,7 @@ ngx_rtmp_send_onclientbwcheck(ngx_rtmp_session_t *s, double inTrans, { NGX_RTMP_AMF_OBJECT, ngx_null_string, - out_obj, sizeof(out_inf) }, + out_inf, sizeof(out_inf) }, }; From 83210546387b75ef986ebc7fbd2f638034d104cb Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Sun, 28 Feb 2016 20:33:39 +0300 Subject: [PATCH 13/19] Add fast detection mode. Less accurate. --- ngx_rtmp_bandwidth_detection_module.c | 144 +++++++++++++++++++++++--- ngx_rtmp_bandwidth_detection_module.h | 4 + 2 files changed, 136 insertions(+), 12 deletions(-) diff --git a/ngx_rtmp_bandwidth_detection_module.c b/ngx_rtmp_bandwidth_detection_module.c index 99fef2629..92a724cdf 100644 --- a/ngx_rtmp_bandwidth_detection_module.c +++ b/ngx_rtmp_bandwidth_detection_module.c @@ -33,6 +33,13 @@ static u_char *payload; // Payload da static ngx_command_t ngx_rtmp_bandwidth_detection_commands[] = { + { ngx_string("auto_sense_bw"), + 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_bandwidth_detection_app_conf_t, auto_sense_bw), + NULL }, + { ngx_string("latency_min"), NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, ngx_rtmp_bandwidth_detection_set_msec_slot, @@ -104,6 +111,7 @@ ngx_rtmp_bandwidth_detection_create_app_conf(ngx_conf_t *cf) return NULL; } + acf->auto_sense_bw = NGX_CONF_UNSET; acf->latency_max = NGX_CONF_UNSET_MSEC; acf->latency_min = NGX_CONF_UNSET_MSEC; acf->latency_undef = NGX_CONF_UNSET_MSEC; @@ -125,6 +133,7 @@ ngx_rtmp_bandwidth_detection_merge_app_conf(ngx_conf_t *cf, void *parent, void * ngx_rtmp_bandwidth_detection_app_conf_t *prev = parent; ngx_rtmp_bandwidth_detection_app_conf_t *conf = child; + ngx_conf_merge_value(conf->auto_sense_bw, prev->auto_sense_bw, 0); ngx_conf_merge_msec_value(conf->latency_max, prev->latency_max, 800); ngx_conf_merge_msec_value(conf->latency_min, prev->latency_min, 10); ngx_conf_merge_msec_value(conf->latency_undef, prev->latency_undef, 100); @@ -256,7 +265,6 @@ ngx_rtmp_bandwidth_detection_on_error(ngx_rtmp_session_t *s, ngx_rtmp_header_t * return NGX_OK; } - /** * Start bandwidth detection here */ @@ -310,23 +318,134 @@ ngx_rtmp_bandwidth_detection_start(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "bandwidth_detection: start - already active!"); return NGX_OK; + } else { + + bw_ctx->active = 1; + bw_ctx->bw_begin_time = ngx_cached_time->msec; + bw_ctx->pkt_sent = 1; + bw_ctx->pkt_received = 0; + bw_ctx->pkt_recv_time1 = 0; + bw_ctx->pkt_recv_time2 = 0; + bw_ctx->cum_latency = 0; + bw_ctx->latency = acf->latency_min; + bw_ctx->bytes_out = s->out_bytes; } - bw_ctx->active = 1; - bw_ctx->bw_begin_time = ngx_cached_time->msec; - bw_ctx->pkt_sent = 1; - bw_ctx->pkt_received = 0; - bw_ctx->pkt_recv_time1 = 0; - bw_ctx->pkt_recv_time2 = 0; - bw_ctx->cum_latency = 0; - bw_ctx->latency = acf->latency_min; - bw_ctx->bytes_out = s->out_bytes; - // Send first packet with empty payload - for latency calculation return ngx_rtmp_send_bwcheck(s, NULL, 0); } +/** + * FAST multicall bandwidth detection here + */ +static ngx_int_t +ngx_rtmp_bandwidth_detection_fast(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) +{ + + ngx_rtmp_bandwidth_detection_app_conf_t *acf; + ngx_rtmp_bandwidth_detection_ctx_t *bw_ctx; + ngx_uint_t timePassed; + ngx_uint_t deltaDown; + double deltaTime; + double kbitDown; + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "bandwidth_detection: fast"); + + if (s->relay) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "bandwidth_detection: fast - no relay please!"); + return NGX_ERROR; + } + + acf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_bandwidth_detection_module); + if (acf == NULL) { + ngx_log_error(NGX_LOG_WARN, s->connection->log, 0, + "bandwidth_detection: fast - no app config!"); + return NGX_ERROR; + } + + if (!acf->test_time || in == NULL || in->buf == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "bandwidth_detection: fast - no test time or no buffer!"); + return NGX_ERROR; + } + + bw_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_bandwidth_detection_module); + if (bw_ctx == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "bandwidth_detection: fast - no context! create new and set for module and session!"); + + bw_ctx = ngx_palloc(s->connection->pool, sizeof(ngx_rtmp_bandwidth_detection_ctx_t)); + if (bw_ctx == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "bandwidth_detection: fast - no context created!"); + return NGX_ERROR; + } + + ngx_rtmp_set_ctx(s, bw_ctx, ngx_rtmp_bandwidth_detection_module); + ngx_memzero(bw_ctx, sizeof(*bw_ctx)); + + bw_ctx->bw_begin_time2 = h->timestamp * 1000; + bw_ctx->latency = acf->latency_min; + } + + /* Emulate accumulation between calls */ + bw_ctx->bw_begin_time = bw_ctx->bw_begin_time2; + bw_ctx->bw_begin_time2 = ngx_cached_time->msec; + bw_ctx->bytes_out = bw_ctx->bytes_out2; + bw_ctx->bytes_out2 = s->out_bytes; + + deltaDown = (bw_ctx->bytes_out2 - bw_ctx->bytes_out) *8/1000.; + deltaTime = ( (bw_ctx->bw_begin_time2 - bw_ctx->bw_begin_time) - (bw_ctx->latency))/1000.; + + if (deltaTime <= 0) deltaTime = (bw_ctx->bw_begin_time2 - bw_ctx->bw_begin_time)/1000.; + if (deltaTime <= 0) deltaTime = 1.; + + kbitDown = deltaDown/deltaTime; + + // Do some load for next call + ngx_rtmp_send_bwcheck(s, payload, NGX_RTMP_BANDWIDTH_DETECTION_PAYLOAD_LENGTH); + + timePassed = bw_ctx->bw_begin_time2 - bw_ctx->bw_begin_time; + + bw_ctx->latency = ngx_min(timePassed, acf->latency_max); + bw_ctx->latency = ngx_max(bw_ctx->latency, acf->latency_min); + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "bandwidth_detection: fast - check done!"); + ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "bandwidth_detection: fast - kbitDown=%ui, deltaDown=%.3f, deltaTime=%.3f, latency=%.3f, KBytes=%ui", + kbitDown, deltaDown, deltaTime, bw_ctx->latency, (bw_ctx->bytes_out2 - bw_ctx->bytes_out)/1024); + + return ngx_rtmp_send_bwdone(s, kbitDown, deltaDown, deltaTime, bw_ctx->latency); +} + + +/** + * Bandwidth detection wrapper + */ +static ngx_int_t +ngx_rtmp_bandwidth_detection_wrapper(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) +{ + ngx_rtmp_bandwidth_detection_app_conf_t *acf; + + acf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_bandwidth_detection_module); + if (acf == NULL) { + ngx_log_error(NGX_LOG_WARN, s->connection->log, 0, + "bandwidth_detection: wrapper - no app config!"); + return NGX_ERROR; + } + + if (acf->auto_sense_bw) { + return ngx_rtmp_bandwidth_detection_start(s, h, in); + } else { + return ngx_rtmp_bandwidth_detection_fast(s, h, in); + } +} + + /** * Bandwidth detection from client side */ @@ -490,6 +609,7 @@ ngx_rtmp_bandwidth_detection_check_result(ngx_rtmp_session_t *s) deltaTime = ( (ngx_cached_time->msec - bw_ctx->bw_begin_time) - (bw_ctx->latency*bw_ctx->cum_latency))/1000.; if (deltaTime <= 0) deltaTime = (ngx_cached_time->msec - bw_ctx->bw_begin_time)/1000.; + if (deltaTime <= 0) deltaTime = 1.; kbitDown = deltaDown/deltaTime; @@ -529,7 +649,7 @@ ngx_rtmp_bandwidth_detection_postconfiguration(ngx_conf_t *cf) ch = ngx_array_push(&cmcf->amf); ngx_str_set(&ch->name, "checkBandwidth"); - ch->handler = ngx_rtmp_bandwidth_detection_start; + ch->handler = ngx_rtmp_bandwidth_detection_wrapper; ch = ngx_array_push(&cmcf->amf); ngx_str_set(&ch->name, "onClientBWCheck"); diff --git a/ngx_rtmp_bandwidth_detection_module.h b/ngx_rtmp_bandwidth_detection_module.h index 2cb2fa149..2a88e196e 100644 --- a/ngx_rtmp_bandwidth_detection_module.h +++ b/ngx_rtmp_bandwidth_detection_module.h @@ -23,7 +23,9 @@ typedef struct ngx_rtmp_bandwidth_detection_ctx_s ngx_rtmp_bandwidth_detection_c struct ngx_rtmp_bandwidth_detection_ctx_s { ngx_rtmp_session_t *session; uint64_t bytes_out; + uint64_t bytes_out2; ngx_msec_t bw_begin_time; + ngx_msec_t bw_begin_time2; ngx_uint_t pkt_sent; ngx_uint_t pkt_received; ngx_msec_t pkt_recv_time1; @@ -34,6 +36,8 @@ struct ngx_rtmp_bandwidth_detection_ctx_s { }; typedef struct { + ngx_flag_t auto_sense_bw; // Do multiple calls onBWCheck, and onBWDone + // Or just fast onBWDone ngx_msec_t latency_min; // Minimal detectable latency, msec ngx_msec_t latency_max; // Maximum latency assumed, msec ngx_msec_t latency_undef; // Default latency for modem, msec From 45998785b74c3bf8a9146b805c062188a9743c85 Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Sun, 28 Feb 2016 21:03:43 +0300 Subject: [PATCH 14/19] Try to fix payload length sent and bw fast calculation --- ngx_rtmp_bandwidth_detection_module.c | 3 ++- ngx_rtmp_send.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ngx_rtmp_bandwidth_detection_module.c b/ngx_rtmp_bandwidth_detection_module.c index 92a724cdf..648274feb 100644 --- a/ngx_rtmp_bandwidth_detection_module.c +++ b/ngx_rtmp_bandwidth_detection_module.c @@ -387,8 +387,9 @@ ngx_rtmp_bandwidth_detection_fast(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, n ngx_rtmp_set_ctx(s, bw_ctx, ngx_rtmp_bandwidth_detection_module); ngx_memzero(bw_ctx, sizeof(*bw_ctx)); - bw_ctx->bw_begin_time2 = h->timestamp * 1000; + bw_ctx->bw_begin_time2 = 0; bw_ctx->latency = acf->latency_min; + bw_ctx->bytes_out2 = 0; } /* Emulate accumulation between calls */ diff --git a/ngx_rtmp_send.c b/ngx_rtmp_send.c index fbb87e746..c00387ff9 100644 --- a/ngx_rtmp_send.c +++ b/ngx_rtmp_send.c @@ -1026,7 +1026,7 @@ ngx_rtmp_create_bwcheck(ngx_rtmp_session_t *s, u_char *payload, size_t plength) if (payload != NULL) { out_inf[0].data = payload; - out_inf[0].len = ngx_strlen(payload); + out_inf[0].len = plength; } trans = NGX_RTMP_BANDWIDTH_DETECTION_BWCHECK_TRANS; From 175cc47e3f18d363043f58b6adbeede11ddf5453 Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Sun, 28 Feb 2016 21:53:19 +0300 Subject: [PATCH 15/19] Try to fix sent messages --- ngx_rtmp_send.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/ngx_rtmp_send.c b/ngx_rtmp_send.c index c00387ff9..fcc2df298 100644 --- a/ngx_rtmp_send.c +++ b/ngx_rtmp_send.c @@ -999,7 +999,7 @@ ngx_rtmp_create_bwcheck(ngx_rtmp_session_t *s, u_char *payload, size_t plength) static ngx_rtmp_amf_elt_t out_inf[] = { { NGX_RTMP_AMF_STRING, - ngx_null_string, + ngx_string("payload"), NULL, 0 }, }; @@ -1014,10 +1014,6 @@ ngx_rtmp_create_bwcheck(ngx_rtmp_session_t *s, u_char *payload, size_t plength) ngx_null_string, &trans, 0 }, - { NGX_RTMP_AMF_NULL, - ngx_null_string, - NULL, 0 }, - { NGX_RTMP_AMF_OBJECT, ngx_null_string, out_inf, @@ -1033,7 +1029,7 @@ ngx_rtmp_create_bwcheck(ngx_rtmp_session_t *s, u_char *payload, size_t plength) memset(&h, 0, sizeof(h)); h.type = NGX_RTMP_MSG_AMF_CMD; - h.csid = NGX_RTMP_CSID_AMF; + h.csid = NGX_RTMP_CSID_AMF_INI; h.msid = NGX_RTMP_MSID; return ngx_rtmp_create_amf(s, &h, out_elts, @@ -1065,19 +1061,19 @@ ngx_rtmp_create_bwdone(ngx_rtmp_session_t *s, static ngx_rtmp_amf_elt_t out_inf[] = { { NGX_RTMP_AMF_NUMBER, - ngx_null_string, + ngx_string("kbitDown"), &v.kbitDown, 0 }, { NGX_RTMP_AMF_NUMBER, - ngx_null_string, + ngx_string("deltaDown"), &v.deltaDown, 0 }, { NGX_RTMP_AMF_NUMBER, - ngx_null_string, + ngx_string("deltaTime"), &v.deltaTime, 0 }, { NGX_RTMP_AMF_NUMBER, - ngx_null_string, + ngx_string("latency"), &v.latency, 0 }, }; @@ -1092,10 +1088,6 @@ ngx_rtmp_create_bwdone(ngx_rtmp_session_t *s, ngx_null_string, &trans, 0 }, - { NGX_RTMP_AMF_NULL, - ngx_null_string, - NULL, 0 }, - { NGX_RTMP_AMF_OBJECT, ngx_null_string, out_inf, @@ -1112,7 +1104,7 @@ ngx_rtmp_create_bwdone(ngx_rtmp_session_t *s, memset(&h, 0, sizeof(h)); h.type = NGX_RTMP_MSG_AMF_CMD; - h.csid = NGX_RTMP_CSID_AMF; + h.csid = NGX_RTMP_CSID_AMF_INI; h.msid = NGX_RTMP_MSID; return ngx_rtmp_create_amf(s, &h, out_elts, From 41d7b0e98819d583febf10c88b4b261f222a281a Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Sun, 28 Feb 2016 22:30:13 +0300 Subject: [PATCH 16/19] Try to send right amf data --- ngx_rtmp_bandwidth_detection_module.c | 30 ++++++++----- ngx_rtmp_send.c | 63 ++++++++++++--------------- 2 files changed, 47 insertions(+), 46 deletions(-) diff --git a/ngx_rtmp_bandwidth_detection_module.c b/ngx_rtmp_bandwidth_detection_module.c index 648274feb..27bcefc4e 100644 --- a/ngx_rtmp_bandwidth_detection_module.c +++ b/ngx_rtmp_bandwidth_detection_module.c @@ -169,6 +169,7 @@ static ngx_int_t ngx_rtmp_bandwidth_detection_on_result(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) { + ngx_rtmp_bandwidth_detection_app_conf_t *acf; ngx_rtmp_bandwidth_detection_ctx_t *ctx; static struct { @@ -195,6 +196,13 @@ ngx_rtmp_bandwidth_detection_on_result(ngx_rtmp_session_t *s, ngx_rtmp_header_t ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "bandwidth_detection: _result"); + acf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_bandwidth_detection_module); + if (acf == NULL) { + ngx_log_error(NGX_LOG_WARN, s->connection->log, 0, + "bandwidth_detection: _result - no app config!"); + return NGX_ERROR; + } + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_bandwidth_detection_module); if (ctx == NULL || s->relay) { ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, @@ -215,16 +223,18 @@ ngx_rtmp_bandwidth_detection_on_result(ngx_rtmp_session_t *s, ngx_rtmp_header_t "bandwidth_detection: _result: trans='%f' count='%ui'", v.trans, v.count); - switch ((ngx_int_t)v.trans) { - case NGX_RTMP_BANDWIDTH_DETECTION_BWCHECK_TRANS: - return ngx_rtmp_bandwidth_detection_check_result(s); - - case NGX_RTMP_BANDWIDTH_DETECTION_BWDONE_TRANS: - /* Need to test it. Maybe need to set this before send bwDone. */ - ctx->active = 0; - break; - default: - return NGX_OK; + if (acf->auto_sense_bw) { + switch ((ngx_int_t)v.trans) { + case NGX_RTMP_BANDWIDTH_DETECTION_BWCHECK_TRANS: + return ngx_rtmp_bandwidth_detection_check_result(s); + + case NGX_RTMP_BANDWIDTH_DETECTION_BWDONE_TRANS: + /* Need to test it. Maybe need to set this before send bwDone. */ + ctx->active = 0; + break; + default: + return NGX_OK; + } } return NGX_OK; } diff --git a/ngx_rtmp_send.c b/ngx_rtmp_send.c index fcc2df298..c5b5e3194 100644 --- a/ngx_rtmp_send.c +++ b/ngx_rtmp_send.c @@ -996,14 +996,6 @@ ngx_rtmp_create_bwcheck(ngx_rtmp_session_t *s, u_char *payload, size_t plength) static double trans; - static ngx_rtmp_amf_elt_t out_inf[] = { - - { NGX_RTMP_AMF_STRING, - ngx_string("payload"), - NULL, 0 }, - - }; - static ngx_rtmp_amf_elt_t out_elts[] = { { NGX_RTMP_AMF_STRING, @@ -1014,15 +1006,18 @@ ngx_rtmp_create_bwcheck(ngx_rtmp_session_t *s, u_char *payload, size_t plength) ngx_null_string, &trans, 0 }, - { NGX_RTMP_AMF_OBJECT, + { NGX_RTMP_AMF_NULL, ngx_null_string, - out_inf, - sizeof(out_inf) }, + NULL, 0 }, + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + NULL, 0 }, }; if (payload != NULL) { - out_inf[0].data = payload; - out_inf[0].len = plength; + out_elts[3].data = payload; + out_elts[3].len = plength; } trans = NGX_RTMP_BANDWIDTH_DETECTION_BWCHECK_TRANS; @@ -1053,45 +1048,41 @@ ngx_rtmp_create_bwdone(ngx_rtmp_session_t *s, static double trans; static struct { double kbitDown; - ngx_uint_t deltaDown; + double deltaDown; double deltaTime; - ngx_msec_t latency; + double latency; } v; - static ngx_rtmp_amf_elt_t out_inf[] = { + static ngx_rtmp_amf_elt_t out_elts[] = { - { NGX_RTMP_AMF_NUMBER, - ngx_string("kbitDown"), - &v.kbitDown, 0 }, + { NGX_RTMP_AMF_STRING, + ngx_null_string, + "onBWDone", 0 }, { NGX_RTMP_AMF_NUMBER, - ngx_string("deltaDown"), - &v.deltaDown, 0 }, + ngx_null_string, + &trans, 0 }, - { NGX_RTMP_AMF_NUMBER, - ngx_string("deltaTime"), - &v.deltaTime, 0 }, + { NGX_RTMP_AMF_NULL, + ngx_null_string, + NULL, 0 }, { NGX_RTMP_AMF_NUMBER, - ngx_string("latency"), - &v.latency, 0 }, - - }; - - static ngx_rtmp_amf_elt_t out_elts[] = { + ngx_null_string, + &v.kbitDown, 0 }, - { NGX_RTMP_AMF_STRING, + { NGX_RTMP_AMF_NUMBER, ngx_null_string, - "onBWDone", 0 }, + &v.deltaDown, 0 }, { NGX_RTMP_AMF_NUMBER, ngx_null_string, - &trans, 0 }, + &v.deltaTime, 0 }, - { NGX_RTMP_AMF_OBJECT, + { NGX_RTMP_AMF_NUMBER, ngx_null_string, - out_inf, - sizeof(out_inf) }, + &v.latency, 0 }, + }; ngx_memzero(&v, sizeof(v)); From d5ae9958c1375eeb1caf49f3b45298f1d9687432 Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Sun, 28 Feb 2016 23:04:44 +0300 Subject: [PATCH 17/19] Adjust var types --- ngx_rtmp_bandwidth_detection_module.c | 4 ++-- ngx_rtmp_send.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ngx_rtmp_bandwidth_detection_module.c b/ngx_rtmp_bandwidth_detection_module.c index 27bcefc4e..925a76291 100644 --- a/ngx_rtmp_bandwidth_detection_module.c +++ b/ngx_rtmp_bandwidth_detection_module.c @@ -356,7 +356,7 @@ ngx_rtmp_bandwidth_detection_fast(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, n ngx_rtmp_bandwidth_detection_app_conf_t *acf; ngx_rtmp_bandwidth_detection_ctx_t *bw_ctx; ngx_uint_t timePassed; - ngx_uint_t deltaDown; + double deltaDown; double deltaTime; double kbitDown; @@ -427,7 +427,7 @@ ngx_rtmp_bandwidth_detection_fast(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, n ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "bandwidth_detection: fast - check done!"); ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "bandwidth_detection: fast - kbitDown=%ui, deltaDown=%.3f, deltaTime=%.3f, latency=%.3f, KBytes=%ui", + "bandwidth_detection: fast - kbitDown=%.3f, deltaDown=%.3f, deltaTime=%.3f, latency=%.3f, KBytes=%ui", kbitDown, deltaDown, deltaTime, bw_ctx->latency, (bw_ctx->bytes_out2 - bw_ctx->bytes_out)/1024); return ngx_rtmp_send_bwdone(s, kbitDown, deltaDown, deltaTime, bw_ctx->latency); diff --git a/ngx_rtmp_send.c b/ngx_rtmp_send.c index c5b5e3194..082b1659f 100644 --- a/ngx_rtmp_send.c +++ b/ngx_rtmp_send.c @@ -1024,7 +1024,7 @@ ngx_rtmp_create_bwcheck(ngx_rtmp_session_t *s, u_char *payload, size_t plength) memset(&h, 0, sizeof(h)); h.type = NGX_RTMP_MSG_AMF_CMD; - h.csid = NGX_RTMP_CSID_AMF_INI; + h.csid = NGX_RTMP_CSID_AMF; h.msid = NGX_RTMP_MSID; return ngx_rtmp_create_amf(s, &h, out_elts, @@ -1095,7 +1095,7 @@ ngx_rtmp_create_bwdone(ngx_rtmp_session_t *s, memset(&h, 0, sizeof(h)); h.type = NGX_RTMP_MSG_AMF_CMD; - h.csid = NGX_RTMP_CSID_AMF_INI; + h.csid = NGX_RTMP_CSID_AMF; h.msid = NGX_RTMP_MSID; return ngx_rtmp_create_amf(s, &h, out_elts, From 6f0fdcae3a69b80d928c15b34a019a21da58e313 Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Sat, 16 Apr 2016 15:57:28 +0300 Subject: [PATCH 18/19] Update bandwidth detection module - add on connect startup and option - "readable" payload - use symbols in [32:64] - deactivate checks on error report - more load payload on fast check --- ngx_rtmp_bandwidth_detection_module.c | 105 ++++++++++++++++++++++---- ngx_rtmp_bandwidth_detection_module.h | 3 +- 2 files changed, 91 insertions(+), 17 deletions(-) diff --git a/ngx_rtmp_bandwidth_detection_module.c b/ngx_rtmp_bandwidth_detection_module.c index 925a76291..82f2558c7 100644 --- a/ngx_rtmp_bandwidth_detection_module.c +++ b/ngx_rtmp_bandwidth_detection_module.c @@ -18,6 +18,9 @@ #define NGX_RTMP_BANDWIDTH_DETECTION_PAYLOAD_LENGTH 16*1024 +static ngx_rtmp_connect_pt next_connect; + + static ngx_int_t ngx_rtmp_bandwidth_detection_postconfiguration(ngx_conf_t *cf); static void * ngx_rtmp_bandwidth_detection_create_app_conf(ngx_conf_t *cf); static char * ngx_rtmp_bandwidth_detection_merge_app_conf(ngx_conf_t *cf, @@ -30,9 +33,15 @@ static ngx_int_t ngx_rtmp_bandwidth_detection_check_result(ngx_rtmp_session_t *s static u_char *payload; // Payload data for all - static ngx_command_t ngx_rtmp_bandwidth_detection_commands[] = { + { ngx_string("auto_start_on_connect"), + 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_bandwidth_detection_app_conf_t, auto_start_on_connect), + NULL }, + { ngx_string("auto_sense_bw"), NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, ngx_conf_set_flag_slot, @@ -111,16 +120,18 @@ ngx_rtmp_bandwidth_detection_create_app_conf(ngx_conf_t *cf) return NULL; } - acf->auto_sense_bw = NGX_CONF_UNSET; - acf->latency_max = NGX_CONF_UNSET_MSEC; - acf->latency_min = NGX_CONF_UNSET_MSEC; - acf->latency_undef = NGX_CONF_UNSET_MSEC; - acf->test_time = NGX_CONF_UNSET_MSEC; + acf->auto_start_on_connect = NGX_CONF_UNSET; + acf->auto_sense_bw = NGX_CONF_UNSET; + acf->latency_max = NGX_CONF_UNSET_MSEC; + acf->latency_min = NGX_CONF_UNSET_MSEC; + acf->latency_undef = NGX_CONF_UNSET_MSEC; + acf->test_time = NGX_CONF_UNSET_MSEC; /* Init payload only once with some random garbage */ payload = ngx_pcalloc(cf->pool, NGX_RTMP_BANDWIDTH_DETECTION_PAYLOAD_LENGTH + 1); for (i=0; iauto_start_on_connect, prev->auto_start_on_connect, 0); ngx_conf_merge_value(conf->auto_sense_bw, prev->auto_sense_bw, 0); ngx_conf_merge_msec_value(conf->latency_max, prev->latency_max, 800); ngx_conf_merge_msec_value(conf->latency_min, prev->latency_min, 10); @@ -244,6 +256,8 @@ static ngx_int_t ngx_rtmp_bandwidth_detection_on_error(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) { + ngx_rtmp_bandwidth_detection_ctx_t *ctx; + static struct { double trans; } v; @@ -272,6 +286,26 @@ ngx_rtmp_bandwidth_detection_on_error(ngx_rtmp_session_t *s, ngx_rtmp_header_t * "bandwidth_detection: _error: trans='%f''", v.trans); + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_bandwidth_detection_module); + if (ctx == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "bandwidth_detection: _result - no context!"); + return NGX_OK; + } + + switch ((ngx_int_t)v.trans) { + case NGX_RTMP_BANDWIDTH_DETECTION_BWCHECK_TRANS: + ctx->active = 0; + break; + + case NGX_RTMP_BANDWIDTH_DETECTION_BWDONE_TRANS: + /* Need to test it. Maybe need to set this before send bwDone. */ + ctx->active = 0; + break; + default: + return NGX_OK; + } + return NGX_OK; } @@ -301,9 +335,9 @@ ngx_rtmp_bandwidth_detection_start(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, return NGX_ERROR; } - if (!acf->test_time || in == NULL || in->buf == NULL) { + if (!acf->test_time) { ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "bandwidth_detection: start - no test time or no buffer!"); + "bandwidth_detection: start - no test time!"); return NGX_ERROR; } @@ -355,7 +389,7 @@ ngx_rtmp_bandwidth_detection_fast(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, n ngx_rtmp_bandwidth_detection_app_conf_t *acf; ngx_rtmp_bandwidth_detection_ctx_t *bw_ctx; - ngx_uint_t timePassed; + ngx_uint_t timePassed, snd_cnt; double deltaDown; double deltaTime; double kbitDown; @@ -376,9 +410,9 @@ ngx_rtmp_bandwidth_detection_fast(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, n return NGX_ERROR; } - if (!acf->test_time || in == NULL || in->buf == NULL) { + if (!acf->test_time) { ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, - "bandwidth_detection: fast - no test time or no buffer!"); + "bandwidth_detection: fast - no test time!"); return NGX_ERROR; } @@ -397,9 +431,22 @@ ngx_rtmp_bandwidth_detection_fast(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, n ngx_rtmp_set_ctx(s, bw_ctx, ngx_rtmp_bandwidth_detection_module); ngx_memzero(bw_ctx, sizeof(*bw_ctx)); + bw_ctx->bw_begin_time = ngx_cached_time->msec; bw_ctx->bw_begin_time2 = 0; bw_ctx->latency = acf->latency_min; - bw_ctx->bytes_out2 = 0; + bw_ctx->bytes_out2 = s->out_bytes; + } + + // To prevent in _result call + bw_ctx->active = 0; + + // Do some load for next call + snd_cnt = 5; + while (snd_cnt) { + if (NGX_OK != ngx_rtmp_send_bwcheck(s, payload, NGX_RTMP_BANDWIDTH_DETECTION_PAYLOAD_LENGTH)) { + break; + } + snd_cnt--; } /* Emulate accumulation between calls */ @@ -416,9 +463,6 @@ ngx_rtmp_bandwidth_detection_fast(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, n kbitDown = deltaDown/deltaTime; - // Do some load for next call - ngx_rtmp_send_bwcheck(s, payload, NGX_RTMP_BANDWIDTH_DETECTION_PAYLOAD_LENGTH); - timePassed = bw_ctx->bw_begin_time2 - bw_ctx->bw_begin_time; bw_ctx->latency = ngx_min(timePassed, acf->latency_max); @@ -642,6 +686,32 @@ ngx_rtmp_bandwidth_detection_check_result(ngx_rtmp_session_t *s) } +static ngx_int_t +ngx_rtmp_bandwidth_detection_connect(ngx_rtmp_session_t *s, ngx_rtmp_connect_t *v) +{ + ngx_rtmp_bandwidth_detection_app_conf_t *acf; + ngx_int_t result; + + result = next_connect(s, v); + + if (result == NGX_OK) { + + acf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_bandwidth_detection_module); + if (acf == NULL) { + ngx_log_error(NGX_LOG_WARN, s->connection->log, 0, + "bandwidth_detection: check - no app config!"); + return NGX_ERROR; + } + + if (acf->auto_start_on_connect) { + result = ngx_rtmp_bandwidth_detection_wrapper(s, NULL, NULL); + } + } + + return result; +} + + static ngx_int_t ngx_rtmp_bandwidth_detection_postconfiguration(ngx_conf_t *cf) { @@ -650,6 +720,9 @@ ngx_rtmp_bandwidth_detection_postconfiguration(ngx_conf_t *cf) cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module); + next_connect = ngx_rtmp_connect; + ngx_rtmp_connect = ngx_rtmp_bandwidth_detection_connect; + ch = ngx_array_push(&cmcf->amf); ngx_str_set(&ch->name, "_result"); ch->handler = ngx_rtmp_bandwidth_detection_on_result; diff --git a/ngx_rtmp_bandwidth_detection_module.h b/ngx_rtmp_bandwidth_detection_module.h index 2a88e196e..8df4f9728 100644 --- a/ngx_rtmp_bandwidth_detection_module.h +++ b/ngx_rtmp_bandwidth_detection_module.h @@ -21,7 +21,6 @@ typedef struct ngx_rtmp_bandwidth_detection_ctx_s ngx_rtmp_bandwidth_detection_ctx_t; struct ngx_rtmp_bandwidth_detection_ctx_s { - ngx_rtmp_session_t *session; uint64_t bytes_out; uint64_t bytes_out2; ngx_msec_t bw_begin_time; @@ -36,6 +35,8 @@ struct ngx_rtmp_bandwidth_detection_ctx_s { }; typedef struct { + ngx_flag_t auto_start_on_connect; // Start bandwidth check on every connection + // without client call ngx_flag_t auto_sense_bw; // Do multiple calls onBWCheck, and onBWDone // Or just fast onBWDone ngx_msec_t latency_min; // Minimal detectable latency, msec From f365781623d7d689d13214b8cc0674cc7b7e0b1f Mon Sep 17 00:00:00 2001 From: Sergey Dryabzhinsky Date: Sat, 16 Apr 2016 19:18:10 +0300 Subject: [PATCH 19/19] Change option names, bw fast calculation --- ngx_rtmp_bandwidth_detection_module.c | 81 +++++++++++++++------------ ngx_rtmp_bandwidth_detection_module.h | 4 +- 2 files changed, 46 insertions(+), 39 deletions(-) diff --git a/ngx_rtmp_bandwidth_detection_module.c b/ngx_rtmp_bandwidth_detection_module.c index 82f2558c7..0cfa4f5ba 100644 --- a/ngx_rtmp_bandwidth_detection_module.c +++ b/ngx_rtmp_bandwidth_detection_module.c @@ -35,42 +35,42 @@ static u_char *payload; // Payload da static ngx_command_t ngx_rtmp_bandwidth_detection_commands[] = { - { ngx_string("auto_start_on_connect"), + { ngx_string("bw_auto_start"), 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_bandwidth_detection_app_conf_t, auto_start_on_connect), + offsetof(ngx_rtmp_bandwidth_detection_app_conf_t, auto_start), NULL }, - { ngx_string("auto_sense_bw"), + { ngx_string("bw_auto_sense"), 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_bandwidth_detection_app_conf_t, auto_sense_bw), + offsetof(ngx_rtmp_bandwidth_detection_app_conf_t, auto_sense), NULL }, - { ngx_string("latency_min"), + { ngx_string("bw_latency_min"), NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, ngx_rtmp_bandwidth_detection_set_msec_slot, NGX_RTMP_APP_CONF_OFFSET, offsetof(ngx_rtmp_bandwidth_detection_app_conf_t, latency_min), NULL }, - { ngx_string("latency_max"), + { ngx_string("bw_latency_max"), NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, ngx_rtmp_bandwidth_detection_set_msec_slot, NGX_RTMP_APP_CONF_OFFSET, offsetof(ngx_rtmp_bandwidth_detection_app_conf_t, latency_max), NULL }, - { ngx_string("latency_undef"), + { ngx_string("bw_latency_undef"), NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, ngx_rtmp_bandwidth_detection_set_msec_slot, NGX_RTMP_APP_CONF_OFFSET, offsetof(ngx_rtmp_bandwidth_detection_app_conf_t, latency_undef), NULL }, - { ngx_string("test_time"), + { ngx_string("bw_auto_sense_time"), NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, ngx_rtmp_bandwidth_detection_set_msec_slot, NGX_RTMP_APP_CONF_OFFSET, @@ -120,17 +120,17 @@ ngx_rtmp_bandwidth_detection_create_app_conf(ngx_conf_t *cf) return NULL; } - acf->auto_start_on_connect = NGX_CONF_UNSET; - acf->auto_sense_bw = NGX_CONF_UNSET; - acf->latency_max = NGX_CONF_UNSET_MSEC; - acf->latency_min = NGX_CONF_UNSET_MSEC; - acf->latency_undef = NGX_CONF_UNSET_MSEC; - acf->test_time = NGX_CONF_UNSET_MSEC; + acf->auto_start = NGX_CONF_UNSET; + acf->auto_sense = NGX_CONF_UNSET; + acf->latency_max = NGX_CONF_UNSET_MSEC; + acf->latency_min = NGX_CONF_UNSET_MSEC; + acf->latency_undef = NGX_CONF_UNSET_MSEC; + acf->test_time = NGX_CONF_UNSET_MSEC; /* Init payload only once with some random garbage */ payload = ngx_pcalloc(cf->pool, NGX_RTMP_BANDWIDTH_DETECTION_PAYLOAD_LENGTH + 1); for (i=0; iauto_start_on_connect, prev->auto_start_on_connect, 0); - ngx_conf_merge_value(conf->auto_sense_bw, prev->auto_sense_bw, 0); + ngx_conf_merge_value(conf->auto_start, prev->auto_start, 0); + ngx_conf_merge_value(conf->auto_sense, prev->auto_sense, 0); ngx_conf_merge_msec_value(conf->latency_max, prev->latency_max, 800); ngx_conf_merge_msec_value(conf->latency_min, prev->latency_min, 10); ngx_conf_merge_msec_value(conf->latency_undef, prev->latency_undef, 100); @@ -235,7 +235,7 @@ ngx_rtmp_bandwidth_detection_on_result(ngx_rtmp_session_t *s, ngx_rtmp_header_t "bandwidth_detection: _result: trans='%f' count='%ui'", v.trans, v.count); - if (acf->auto_sense_bw) { + if (acf->auto_sense) { switch ((ngx_int_t)v.trans) { case NGX_RTMP_BANDWIDTH_DETECTION_BWCHECK_TRANS: return ngx_rtmp_bandwidth_detection_check_result(s); @@ -293,13 +293,19 @@ ngx_rtmp_bandwidth_detection_on_error(ngx_rtmp_session_t *s, ngx_rtmp_header_t * return NGX_OK; } + /** + * If onBWCheck / onBWDone unsupported - drop activity + */ switch ((ngx_int_t)v.trans) { case NGX_RTMP_BANDWIDTH_DETECTION_BWCHECK_TRANS: + ngx_log_error(NGX_LOG_WARN, s->connection->log, 0, + "bandwidth_detection: _error - client not support onBWCheck?"); ctx->active = 0; break; case NGX_RTMP_BANDWIDTH_DETECTION_BWDONE_TRANS: - /* Need to test it. Maybe need to set this before send bwDone. */ + ngx_log_error(NGX_LOG_WARN, s->connection->log, 0, + "bandwidth_detection: _error - client not support onBWDone?"); ctx->active = 0; break; default: @@ -311,6 +317,7 @@ ngx_rtmp_bandwidth_detection_on_error(ngx_rtmp_session_t *s, ngx_rtmp_header_t * /** * Start bandwidth detection here + * Long version with multiple onBWCheck calls */ static ngx_int_t ngx_rtmp_bandwidth_detection_start(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) @@ -381,7 +388,7 @@ ngx_rtmp_bandwidth_detection_start(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, /** - * FAST multicall bandwidth detection here + * FAST bandwidth detection here */ static ngx_int_t ngx_rtmp_bandwidth_detection_fast(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, ngx_chain_t *in) @@ -430,23 +437,24 @@ ngx_rtmp_bandwidth_detection_fast(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, n ngx_rtmp_set_ctx(s, bw_ctx, ngx_rtmp_bandwidth_detection_module); ngx_memzero(bw_ctx, sizeof(*bw_ctx)); - - bw_ctx->bw_begin_time = ngx_cached_time->msec; - bw_ctx->bw_begin_time2 = 0; - bw_ctx->latency = acf->latency_min; - bw_ctx->bytes_out2 = s->out_bytes; } // To prevent in _result call bw_ctx->active = 0; + bw_ctx->bw_begin_time = ngx_cached_time->msec; + bw_ctx->bw_begin_time2 = 0; + bw_ctx->latency = acf->latency_min; + bw_ctx->bytes_out2 = s->out_bytes; + + ngx_rtmp_send_bwcheck(s, NULL, 0); // Do some load for next call - snd_cnt = 5; - while (snd_cnt) { + snd_cnt = 0; + while (snd_cnt<5) { if (NGX_OK != ngx_rtmp_send_bwcheck(s, payload, NGX_RTMP_BANDWIDTH_DETECTION_PAYLOAD_LENGTH)) { break; } - snd_cnt--; + snd_cnt++; } /* Emulate accumulation between calls */ @@ -455,19 +463,19 @@ ngx_rtmp_bandwidth_detection_fast(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, n bw_ctx->bytes_out = bw_ctx->bytes_out2; bw_ctx->bytes_out2 = s->out_bytes; + timePassed = (bw_ctx->bw_begin_time2 - bw_ctx->bw_begin_time) / snd_cnt; + + bw_ctx->latency = ngx_min(timePassed, acf->latency_max); + bw_ctx->latency = ngx_max(bw_ctx->latency, acf->latency_min); + deltaDown = (bw_ctx->bytes_out2 - bw_ctx->bytes_out) *8/1000.; - deltaTime = ( (bw_ctx->bw_begin_time2 - bw_ctx->bw_begin_time) - (bw_ctx->latency))/1000.; + deltaTime = ( (bw_ctx->bw_begin_time2 - bw_ctx->bw_begin_time) - (bw_ctx->latency*snd_cnt))/1000.; if (deltaTime <= 0) deltaTime = (bw_ctx->bw_begin_time2 - bw_ctx->bw_begin_time)/1000.; if (deltaTime <= 0) deltaTime = 1.; kbitDown = deltaDown/deltaTime; - timePassed = bw_ctx->bw_begin_time2 - bw_ctx->bw_begin_time; - - bw_ctx->latency = ngx_min(timePassed, acf->latency_max); - bw_ctx->latency = ngx_max(bw_ctx->latency, acf->latency_min); - ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "bandwidth_detection: fast - check done!"); ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, @@ -493,7 +501,7 @@ ngx_rtmp_bandwidth_detection_wrapper(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h return NGX_ERROR; } - if (acf->auto_sense_bw) { + if (acf->auto_sense) { return ngx_rtmp_bandwidth_detection_start(s, h, in); } else { return ngx_rtmp_bandwidth_detection_fast(s, h, in); @@ -578,7 +586,6 @@ ngx_rtmp_bandwidth_detection_clientcheck(ngx_rtmp_session_t *s, ngx_rtmp_header_ "bandwidth_detection: bwcheck: trans='%f' time='%ui'", v.trans, v.time); - // Send first packet with empty payload - for latency calculation return ngx_rtmp_send_onclientbwcheck(s, v.trans, s->out_bytes, s->in_bytes, v.time); } @@ -703,7 +710,7 @@ ngx_rtmp_bandwidth_detection_connect(ngx_rtmp_session_t *s, ngx_rtmp_connect_t * return NGX_ERROR; } - if (acf->auto_start_on_connect) { + if (acf->auto_start) { result = ngx_rtmp_bandwidth_detection_wrapper(s, NULL, NULL); } } diff --git a/ngx_rtmp_bandwidth_detection_module.h b/ngx_rtmp_bandwidth_detection_module.h index 8df4f9728..396a2ca71 100644 --- a/ngx_rtmp_bandwidth_detection_module.h +++ b/ngx_rtmp_bandwidth_detection_module.h @@ -35,9 +35,9 @@ struct ngx_rtmp_bandwidth_detection_ctx_s { }; typedef struct { - ngx_flag_t auto_start_on_connect; // Start bandwidth check on every connection + ngx_flag_t auto_start; // Start bandwidth check on every connection // without client call - ngx_flag_t auto_sense_bw; // Do multiple calls onBWCheck, and onBWDone + ngx_flag_t auto_sense; // Do multiple calls onBWCheck, and onBWDone // Or just fast onBWDone ngx_msec_t latency_min; // Minimal detectable latency, msec ngx_msec_t latency_max; // Maximum latency assumed, msec