diff --git a/lib/http_parser.cpp b/lib/http_parser.cpp index 44f5ed20..b0847a3c 100644 --- a/lib/http_parser.cpp +++ b/lib/http_parser.cpp @@ -150,7 +150,7 @@ std::string &HTTP::Parser::BuildRequest(){ /// \todo Include POST variable handling for vars? std::map::iterator it; if (protocol.size() < 5 || protocol[4] != '/'){protocol = "HTTP/1.0";} - if (method != "POST" && vars.size() && url.find('?') == std::string::npos){ + if (!(method == "POST" && GetHeader("Content-Type") == "application/x-www-form-urlencoded") && vars.size() && url.find('?') == std::string::npos){ builder = method + " " + Encodings::URL::encode(url, "/:=@[]") + allVars() + " " + protocol + "\r\n"; }else{ builder = method + " " + Encodings::URL::encode(url, "/:=@[]") + " " + protocol + "\r\n"; diff --git a/src/output/output_http.cpp b/src/output/output_http.cpp index 8ab1ab7f..5a0d051a 100644 --- a/src/output/output_http.cpp +++ b/src/output/output_http.cpp @@ -833,9 +833,8 @@ namespace Mist{ respondHTTP(reqH, headersOnly); } - /// Default implementation of preHTTP simply calls initialize and selectDefaultTracks. + /// Default implementation of preHTTP simply calls selectDefaultTracks. void HTTPOutput::preHTTP(){ - initialize(); selectDefaultTracks(); } diff --git a/src/output/output_webrtc.cpp b/src/output/output_webrtc.cpp index c907b0e4..e5aa7a5c 100644 --- a/src/output/output_webrtc.cpp +++ b/src/output/output_webrtc.cpp @@ -429,14 +429,83 @@ namespace Mist{ HTTPOutput::requestHandler(); } + // If ICE headers are configured, sets them on the given HTTP::Parser instance. + void OutWebRTC::setIceHeaders(HTTP::Parser & H){ + if (!config->getString("iceservers").size()){return;} + std::deque links; + JSON::Value iceConf = JSON::fromString(config->getString("iceservers")); + jsonForEach(iceConf, i){ + if (i->isMember("url") && (*i)["url"].isString()){ + JSON::Value &u = (*i)["url"]; + std::string str = "<"+u.asString()+">; rel=\"ice-server\";"; + if (i->isMember("username")){ + str += " username=" + (*i)["username"].toString() + ";"; + } + if (i->isMember("credential")){ + str += " credential=" + (*i)["credential"].toString() + ";"; + } + if (i->isMember("credentialType")){ + str += " credential-type=" + (*i)["credentialType"].toString() + ";"; + } + links.push_back(str); + } + if (i->isMember("urls") && (*i)["urls"].isString()){ + JSON::Value &u = (*i)["urls"]; + std::string str = "<"+u.asString()+">; rel=\"ice-server\";"; + if (i->isMember("username")){ + str += " username=" + (*i)["username"].toString() + ";"; + } + if (i->isMember("credential")){ + str += " credential=" + (*i)["credential"].toString() + ";"; + } + if (i->isMember("credentialType")){ + str += " credential-type=" + (*i)["credentialType"].toString() + ";"; + } + links.push_back(str); + } + if (i->isMember("urls") && (*i)["urls"].isArray()){ + jsonForEach((*i)["urls"], j){ + JSON::Value &u = *j; + std::string str = "<"+u.asString()+">; rel=\"ice-server\";"; + if (i->isMember("username")){ + str += " username=" + (*i)["username"].toString() + ";"; + } + if (i->isMember("credential")){ + str += " credential=" + (*i)["credential"].toString() + ";"; + } + if (i->isMember("credentialType")){ + str += " credential-type=" + (*i)["credentialType"].toString() + ";"; + } + links.push_back(str); + } + } + } + if (links.size()){ + if (links.size() == 1){ + H.SetHeader("Link", *links.begin()); + }else{ + std::deque::iterator it = links.begin(); + std::string linkHeader = *it; + ++it; + while (it != links.end()){ + linkHeader += "\r\nLink: " + *it; + ++it; + } + H.SetHeader("Link", linkHeader); + } + } + } + void OutWebRTC::respondHTTP(const HTTP::Parser & req, bool headersOnly){ // Generic header/parameter handling HTTPOutput::respondHTTP(req, headersOnly); - INFO_MSG("HTTP: %s", req.method.c_str()); - // Check for WHIP payload + // Always send the ICE headers, because why not? + setIceHeaders(H); + + // Check for WHIP/WHEP payload if (headersOnly){ - H.setCORSHeaders(); - H.StartResponse("200", "All good", req, myConn); + // Options can be used to get the ICE config, so we should include it in the response + H.StartResponse("200", "All good, have some ICE config", req, myConn); H.Chunkify(0, 0, myConn); return; } @@ -470,71 +539,10 @@ namespace Mist{ noSignalling = true; H.SetHeader("Content-Type", "application/sdp"); H.SetHeader("Location", streamName + "/" + JSON::Value(getpid()).asString()); - if (config->getString("iceservers").size()){ - std::deque links; - JSON::Value iceConf = JSON::fromString(config->getString("iceservers")); - jsonForEach(iceConf, i){ - if (i->isMember("url") && (*i)["url"].isString()){ - JSON::Value &u = (*i)["url"]; - std::string str = u.asString()+"; rel=\"ice-server\";"; - if (i->isMember("username")){ - str += " username=" + (*i)["username"].toString() + ";"; - } - if (i->isMember("credential")){ - str += " credential=" + (*i)["credential"].toString() + ";"; - } - if (i->isMember("credentialType")){ - str += " credential-type=" + (*i)["credentialType"].toString() + ";"; - } - links.push_back(str); - } - if (i->isMember("urls") && (*i)["urls"].isString()){ - JSON::Value &u = (*i)["urls"]; - std::string str = u.asString()+"; rel=\"ice-server\";"; - if (i->isMember("username")){ - str += " username=" + (*i)["username"].toString() + ";"; - } - if (i->isMember("credential")){ - str += " credential=" + (*i)["credential"].toString() + ";"; - } - if (i->isMember("credentialType")){ - str += " credential-type=" + (*i)["credentialType"].toString() + ";"; - } - links.push_back(str); - } - if (i->isMember("urls") && (*i)["urls"].isArray()){ - jsonForEach((*i)["urls"], j){ - JSON::Value &u = *j; - std::string str = u.asString()+"; rel=\"ice-server\";"; - if (i->isMember("username")){ - str += " username=" + (*i)["username"].toString() + ";"; - } - if (i->isMember("credential")){ - str += " credential=" + (*i)["credential"].toString() + ";"; - } - if (i->isMember("credentialType")){ - str += " credential-type=" + (*i)["credentialType"].toString() + ";"; - } - links.push_back(str); - } - } - } - if (links.size()){ - if (links.size() == 1){ - H.SetHeader("Link", *links.begin()); - }else{ - std::deque::iterator it = links.begin(); - std::string linkHeader = *it; - ++it; - while (it != links.end()){ - linkHeader += "\r\nLink: " + *it; - ++it; - } - H.SetHeader("Link", linkHeader); - } - } + if (req.GetVar("constant").size()){ + INFO_MSG("Disabling automatic playback rate control"); + maxSkipAhead = 1;//disable automatic rate control } - H.setCORSHeaders(); H.StartResponse("201", "Created", req, myConn); H.Chunkify(sdpAnswer.toString(), myConn); H.Chunkify(0, 0, myConn); diff --git a/src/output/output_webrtc.h b/src/output/output_webrtc.h index 03eea959..7481ed4f 100644 --- a/src/output/output_webrtc.h +++ b/src/output/output_webrtc.h @@ -90,6 +90,7 @@ namespace Mist{ static void init(Util::Config *cfg); virtual void sendNext(); virtual void onWebsocketFrame(); + void setIceHeaders(HTTP::Parser & H); virtual void respondHTTP(const HTTP::Parser & req, bool headersOnly); virtual void preHTTP(){} virtual void preWebsocketConnect();