static ngx_int_t ngx_rtmp_cmd_connect(ngx_rtmp_session_t *s, ngx_rtmp_connect_t *v) { ngx_rtmp_core_srv_conf_t *cscf; ngx_rtmp_core_app_conf_t **cacfp; ngx_uint_t n; size_t len; ngx_rtmp_header_t h; static double trans; static double capabilities = NGX_RTMP_CAPABILITIES; static double object_encoding = 0; static ngx_rtmp_amf_elt_t out_obj[] = { { NGX_RTMP_AMF_STRING, ngx_string("fmsVer"), NGX_RTMP_FMS_VERSION, 0 }, { NGX_RTMP_AMF_NUMBER, ngx_string("capabilities"), &capabilities, 0 }, }; static ngx_rtmp_amf_elt_t out_inf[] = { { NGX_RTMP_AMF_STRING, ngx_string("level"), "status", 0 }, { NGX_RTMP_AMF_STRING, ngx_string("code"), "NetConnection.Connect.Success", 0 }, { NGX_RTMP_AMF_STRING, ngx_string("description"), "Connection succeeded.", 0 }, { NGX_RTMP_AMF_NUMBER, ngx_string("objectEncoding"), &object_encoding, 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, &trans, 0 }, { NGX_RTMP_AMF_OBJECT, ngx_null_string, out_obj, sizeof(out_obj) }, { NGX_RTMP_AMF_OBJECT, ngx_null_string, out_inf, sizeof(out_inf) }, }; if (s->connected) { ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, "connect: duplicate connection"); return NGX_ERROR; } cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); ngx_log_debug8(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "connect: app='%s' flashver='%s' swf_url='%s' " "tc_url='%s' page_url='%s' acodecs=%uD vcodecs=%uD " "object_encoding=%ui", v->app, v->flashver, v->swf_url, v->tc_url, v->page_url, (uint32_t)v->acodecs, (uint32_t)v->vcodecs, (ngx_int_t)v->object_encoding); trans = v->trans; /* fill session parameters */ s->connected = 1; ngx_memzero(&h, sizeof(h)); h.csid = NGX_RTMP_CMD_CSID_AMF_INI; h.type = NGX_RTMP_MSG_AMF_CMD; #define NGX_RTMP_SET_STRPAR(name) \ s->name.len = ngx_strlen(v->name); \ s->name.data = ngx_palloc(s->connection->pool, s->name.len); \ ngx_memcpy(s->name.data, v->name, s->name.len) NGX_RTMP_SET_STRPAR(app); NGX_RTMP_SET_STRPAR(flashver); NGX_RTMP_SET_STRPAR(swf_url); NGX_RTMP_SET_STRPAR(tc_url); NGX_RTMP_SET_STRPAR(page_url); #undef NGX_RTMP_SET_STRPAR s->acodecs = v->acodecs; s->vcodecs = v->vcodecs; /* find application & set app_conf */ len = ngx_strlen(v->app); cacfp = cscf->applications.elts; for(n = 0; n < cscf->applications.nelts; ++n, ++cacfp) { if ((*cacfp)->name.len == len && !ngx_strncmp((*cacfp)->name.data, v->app, len)) { /* found app! */ s->app_conf = (*cacfp)->app_conf; break; } } if (s->app_conf == NULL) { ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, "connect: application not found: '%s'", v->app); return NGX_ERROR; } object_encoding = v->object_encoding; /* send all replies */ return ngx_rtmp_send_ack_size(s, cscf->ack_window) != NGX_OK || ngx_rtmp_send_bandwidth(s, cscf->ack_window, NGX_RTMP_LIMIT_DYNAMIC) != NGX_OK || ngx_rtmp_send_chunk_size(s, cscf->chunk_size) != NGX_OK || ngx_rtmp_send_amf(s, &h, out_elts, sizeof(out_elts) / sizeof(out_elts[0])) != NGX_OK ? NGX_ERROR : NGX_OK; }
static ngx_int_t ngx_rtmp_relay_send_connect(ngx_rtmp_session_t *s) { static double trans = NGX_RTMP_RELAY_CONNECT_TRANS; static double acodecs = 3575; static double vcodecs = 252; static ngx_rtmp_amf_elt_t out_cmd[] = { { NGX_RTMP_AMF_STRING, ngx_string("app"), NULL, 0 }, /* <-- fill */ { NGX_RTMP_AMF_STRING, ngx_string("tcUrl"), NULL, 0 }, /* <-- fill */ { NGX_RTMP_AMF_STRING, ngx_string("pageUrl"), NULL, 0 }, /* <-- fill */ { NGX_RTMP_AMF_STRING, ngx_string("swfUrl"), NULL, 0 }, /* <-- fill */ { NGX_RTMP_AMF_STRING, ngx_string("flashVer"), NULL, 0 }, /* <-- fill */ { NGX_RTMP_AMF_NUMBER, ngx_string("audioCodecs"), &acodecs, 0 }, { NGX_RTMP_AMF_NUMBER, ngx_string("videoCodecs"), &vcodecs, 0 } }; static ngx_rtmp_amf_elt_t out_elts[] = { { NGX_RTMP_AMF_STRING, ngx_null_string, "connect", 0 }, { NGX_RTMP_AMF_NUMBER, ngx_null_string, &trans, 0 }, { NGX_RTMP_AMF_OBJECT, ngx_null_string, out_cmd, sizeof(out_cmd) } }; ngx_rtmp_core_app_conf_t *cacf; ngx_rtmp_core_srv_conf_t *cscf; ngx_rtmp_relay_ctx_t *ctx; ngx_rtmp_header_t h; size_t len; u_char *p; cacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_core_module); cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module); if (cacf == NULL || ctx == NULL) { return NGX_ERROR; } /* app */ if (ctx->app.len) { out_cmd[0].data = ctx->app.data; out_cmd[0].len = ctx->app.len; } else { out_cmd[0].data = cacf->name.data; out_cmd[0].len = cacf->name.len; } /* tcUrl */ if (ctx->tc_url.len) { out_cmd[1].data = ctx->tc_url.data; out_cmd[1].len = ctx->tc_url.len; } else { len = sizeof("rtmp://") - 1 + ctx->url.len + sizeof("/") - 1 + ctx->app.len; p = ngx_palloc(s->connection->pool, len); if (p == NULL) { return NGX_ERROR; } out_cmd[1].data = p; p = ngx_cpymem(p, "rtmp://", sizeof("rtmp://") - 1); p = ngx_cpymem(p, ctx->url.data, ctx->url.len); *p++ = '/'; p = ngx_cpymem(p, ctx->app.data, ctx->app.len); out_cmd[1].len = p - (u_char *)out_cmd[1].data; } /* pageUrl */ out_cmd[2].data = ctx->page_url.data; out_cmd[2].len = ctx->page_url.len; /* swfUrl */ out_cmd[3].data = ctx->swf_url.data; out_cmd[3].len = ctx->swf_url.len; /* flashVer */ if (ctx->flash_ver.len) { out_cmd[4].data = ctx->flash_ver.data; out_cmd[4].len = ctx->flash_ver.len; } else { out_cmd[4].data = NGX_RTMP_RELAY_FLASHVER; out_cmd[4].len = sizeof(NGX_RTMP_RELAY_FLASHVER) - 1; } ngx_memzero(&h, sizeof(h)); h.csid = NGX_RTMP_RELAY_CSID_AMF_INI; h.type = NGX_RTMP_MSG_AMF_CMD; return ngx_rtmp_send_chunk_size(s, cscf->chunk_size) != NGX_OK || ngx_rtmp_send_ack_size(s, cscf->ack_window) != NGX_OK || ngx_rtmp_send_amf(s, &h, out_elts, sizeof(out_elts) / sizeof(out_elts[0])) != NGX_OK ? NGX_ERROR : NGX_OK; }