WebRTC improvements:
- Return ICE headers for WHIP/WHEP/WISH OPTIONS requests already to help clients that cannot change ICE servers post-SDP-request-generation - Fixes to WebRTC WHIP/WHEP GET param parsing - Added "constant" GET param for forcing constant-rate playback - Use correct syntax for WebRTC Link headers
This commit is contained in:
parent
5f70d387a5
commit
9fd34c95fa
4 changed files with 79 additions and 71 deletions
|
@ -150,7 +150,7 @@ std::string &HTTP::Parser::BuildRequest(){
|
||||||
/// \todo Include POST variable handling for vars?
|
/// \todo Include POST variable handling for vars?
|
||||||
std::map<std::string, std::string>::iterator it;
|
std::map<std::string, std::string>::iterator it;
|
||||||
if (protocol.size() < 5 || protocol[4] != '/'){protocol = "HTTP/1.0";}
|
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";
|
builder = method + " " + Encodings::URL::encode(url, "/:=@[]") + allVars() + " " + protocol + "\r\n";
|
||||||
}else{
|
}else{
|
||||||
builder = method + " " + Encodings::URL::encode(url, "/:=@[]") + " " + protocol + "\r\n";
|
builder = method + " " + Encodings::URL::encode(url, "/:=@[]") + " " + protocol + "\r\n";
|
||||||
|
|
|
@ -833,9 +833,8 @@ namespace Mist{
|
||||||
respondHTTP(reqH, headersOnly);
|
respondHTTP(reqH, headersOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Default implementation of preHTTP simply calls initialize and selectDefaultTracks.
|
/// Default implementation of preHTTP simply calls selectDefaultTracks.
|
||||||
void HTTPOutput::preHTTP(){
|
void HTTPOutput::preHTTP(){
|
||||||
initialize();
|
|
||||||
selectDefaultTracks();
|
selectDefaultTracks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -429,14 +429,83 @@ namespace Mist{
|
||||||
HTTPOutput::requestHandler();
|
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<std::string> 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<std::string>::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){
|
void OutWebRTC::respondHTTP(const HTTP::Parser & req, bool headersOnly){
|
||||||
// Generic header/parameter handling
|
// Generic header/parameter handling
|
||||||
HTTPOutput::respondHTTP(req, headersOnly);
|
HTTPOutput::respondHTTP(req, headersOnly);
|
||||||
INFO_MSG("HTTP: %s", req.method.c_str());
|
// Always send the ICE headers, because why not?
|
||||||
// Check for WHIP payload
|
setIceHeaders(H);
|
||||||
|
|
||||||
|
// Check for WHIP/WHEP payload
|
||||||
if (headersOnly){
|
if (headersOnly){
|
||||||
H.setCORSHeaders();
|
// Options can be used to get the ICE config, so we should include it in the response
|
||||||
H.StartResponse("200", "All good", req, myConn);
|
H.StartResponse("200", "All good, have some ICE config", req, myConn);
|
||||||
H.Chunkify(0, 0, myConn);
|
H.Chunkify(0, 0, myConn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -470,71 +539,10 @@ namespace Mist{
|
||||||
noSignalling = true;
|
noSignalling = true;
|
||||||
H.SetHeader("Content-Type", "application/sdp");
|
H.SetHeader("Content-Type", "application/sdp");
|
||||||
H.SetHeader("Location", streamName + "/" + JSON::Value(getpid()).asString());
|
H.SetHeader("Location", streamName + "/" + JSON::Value(getpid()).asString());
|
||||||
if (config->getString("iceservers").size()){
|
if (req.GetVar("constant").size()){
|
||||||
std::deque<std::string> links;
|
INFO_MSG("Disabling automatic playback rate control");
|
||||||
JSON::Value iceConf = JSON::fromString(config->getString("iceservers"));
|
maxSkipAhead = 1;//disable automatic rate control
|
||||||
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<std::string>::iterator it = links.begin();
|
|
||||||
std::string linkHeader = *it;
|
|
||||||
++it;
|
|
||||||
while (it != links.end()){
|
|
||||||
linkHeader += "\r\nLink: " + *it;
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
H.SetHeader("Link", linkHeader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
H.setCORSHeaders();
|
|
||||||
H.StartResponse("201", "Created", req, myConn);
|
H.StartResponse("201", "Created", req, myConn);
|
||||||
H.Chunkify(sdpAnswer.toString(), myConn);
|
H.Chunkify(sdpAnswer.toString(), myConn);
|
||||||
H.Chunkify(0, 0, myConn);
|
H.Chunkify(0, 0, myConn);
|
||||||
|
|
|
@ -90,6 +90,7 @@ namespace Mist{
|
||||||
static void init(Util::Config *cfg);
|
static void init(Util::Config *cfg);
|
||||||
virtual void sendNext();
|
virtual void sendNext();
|
||||||
virtual void onWebsocketFrame();
|
virtual void onWebsocketFrame();
|
||||||
|
void setIceHeaders(HTTP::Parser & H);
|
||||||
virtual void respondHTTP(const HTTP::Parser & req, bool headersOnly);
|
virtual void respondHTTP(const HTTP::Parser & req, bool headersOnly);
|
||||||
virtual void preHTTP(){}
|
virtual void preHTTP(){}
|
||||||
virtual void preWebsocketConnect();
|
virtual void preWebsocketConnect();
|
||||||
|
|
Loading…
Add table
Reference in a new issue