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?
|
||||
std::map<std::string, std::string>::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";
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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<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){
|
||||
// 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<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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Reference in a new issue