Implemented browser detection and handling of output-specific browser exceptions.
This commit is contained in:
		
							parent
							
								
									4b2e2aa889
								
							
						
					
					
						commit
						266ab3a654
					
				
					 5 changed files with 77 additions and 11 deletions
				
			
		|  | @ -68,6 +68,21 @@ namespace Mist{ | |||
|     capa["methods"][0u]["handler"] = "http"; | ||||
|     capa["methods"][0u]["type"] = "html5/video/webm"; | ||||
|     capa["methods"][0u]["priority"] = 8ll; | ||||
|     //EBML will only work with VP8/VP9/Opus except on Chrome
 | ||||
|     JSON::Value blacklistNonChrome = JSON::fromString("[[\"blacklist\"], [\"whitelist\",[\"Chrome\",\"Chromium\"]], [\"blacklist\",[\"Edge\",\"OPR/\"]]]"); | ||||
|     capa["exceptions"]["codec:H264"] = blacklistNonChrome; | ||||
|     capa["exceptions"]["codec:HEVC"] = blacklistNonChrome; | ||||
|     capa["exceptions"]["codec:theora"] = blacklistNonChrome; | ||||
|     capa["exceptions"]["codec:MPEG2"] = blacklistNonChrome; | ||||
|     capa["exceptions"]["codec:AAC"] = blacklistNonChrome; | ||||
|     capa["exceptions"]["codec:vorbis"] = blacklistNonChrome; | ||||
|     capa["exceptions"]["codec:PCM"] = blacklistNonChrome; | ||||
|     capa["exceptions"]["codec:ALAW"] = blacklistNonChrome; | ||||
|     capa["exceptions"]["codec:ULAW"] = blacklistNonChrome; | ||||
|     capa["exceptions"]["codec:MP2"] = blacklistNonChrome; | ||||
|     capa["exceptions"]["codec:MP3"] = blacklistNonChrome; | ||||
|     capa["exceptions"]["codec:FLOAT"] = blacklistNonChrome; | ||||
|     capa["exceptions"]["codec:AC3"] = blacklistNonChrome; | ||||
|     capa["push_urls"].append("/*.mkv"); | ||||
|     capa["push_urls"].append("/*.webm"); | ||||
| 
 | ||||
|  |  | |||
|  | @ -306,6 +306,8 @@ namespace Mist { | |||
|     capa["methods"][0u]["handler"] = "http"; | ||||
|     capa["methods"][0u]["type"] = "html5/application/vnd.apple.mpegurl"; | ||||
|     capa["methods"][0u]["priority"] = 9ll; | ||||
|     //MP3 only works on Edge/Apple
 | ||||
|     capa["exceptions"]["codec:MP3"] = JSON::fromString("[[\"blacklist\"],[\"whitelist\",[\"iPad\",\"iPhone\",\"iPod\",\"MacIntel\",\"Edge\"]]]"); | ||||
|     /*LTS-START*/ | ||||
|     cfg->addOption("listlimit", JSON::fromString("{\"arg\":\"integer\",\"default\":0,\"short\":\"y\",\"long\":\"list-limit\",\"help\":\"Maximum number of parts in live playlists (0 = infinite).\"}")); | ||||
|     capa["optional"]["listlimit"]["name"] = "Live playlist limit"; | ||||
|  |  | |||
|  | @ -170,9 +170,40 @@ namespace Mist { | |||
|     } | ||||
|     sources.insert(tmp); | ||||
|   } | ||||
|    | ||||
|   | ||||
|   /// Checks if a given user agent is allowed according to the given exception.
 | ||||
|   bool checkException(const JSON::Value & ex, const std::string & useragent){ | ||||
|     //No user agent? Always allow everything.
 | ||||
|     if (!useragent.size()){return true;} | ||||
|     if (!ex.isArray() || !ex.size()){return true;} | ||||
|     bool ret = true; | ||||
|     jsonForEachConst(ex, e){ | ||||
|       if (!e->isArray() || !e->size()){continue;} | ||||
|       bool setTo = ((*e)[0u].asStringRef() == "whitelist"); | ||||
|       if (e->size() == 1){ | ||||
|         ret = setTo; | ||||
|         continue; | ||||
|       } | ||||
|       if (!(*e)[1].isArray()){continue;} | ||||
|       jsonForEachConst((*e)[1u], i){ | ||||
|         if (useragent.find(i->asStringRef()) != std::string::npos){ | ||||
|           ret = setTo; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return ret; | ||||
|   } | ||||
| 
 | ||||
|   void addSources(std::string & streamname, std::set<JSON::Value, sourceCompare> & sources, HTTP::URL url, JSON::Value & conncapa, JSON::Value & strmMeta){ | ||||
|   void addSources(std::string & streamname, std::set<JSON::Value, sourceCompare> & sources, HTTP::URL url, JSON::Value & conncapa, JSON::Value & strmMeta, const std::string & useragent){ | ||||
|     if (strmMeta.isMember("live") && conncapa.isMember("exceptions") && conncapa["exceptions"].isObject() && conncapa["exceptions"].size()){ | ||||
|       jsonForEach(conncapa["exceptions"], ex){ | ||||
|         if (ex.key() == "live"){ | ||||
|           if (!checkException(*ex, useragent)){ | ||||
|             return; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     const std::string & rel = conncapa["url_rel"].asStringRef(); | ||||
|     unsigned int most_simul = 0; | ||||
|     unsigned int total_matches = 0; | ||||
|  | @ -188,6 +219,17 @@ namespace Mist { | |||
|                   if ((*trit)["codec"].asStringRef() == (*itc).asStringRef()){ | ||||
|                     matches++; | ||||
|                     total_matches++; | ||||
|                     if (conncapa.isMember("exceptions") && conncapa["exceptions"].isObject() && conncapa["exceptions"].size()){ | ||||
|                       jsonForEach(conncapa["exceptions"], ex){ | ||||
|                         if (ex.key() == "codec:"+(*trit)["codec"].asStringRef()){ | ||||
|                           if (!checkException(*ex, useragent)){ | ||||
|                             matches--; | ||||
|                             total_matches--; | ||||
|                           } | ||||
|                           break; | ||||
|                         } | ||||
|                       } | ||||
|                     } | ||||
|                   } | ||||
|                 } | ||||
|               } | ||||
|  | @ -262,7 +304,7 @@ namespace Mist { | |||
|     H.SendResponse("200", "OK", myConn); | ||||
|   } | ||||
|    | ||||
|   JSON::Value OutHTTP::getStatusJSON(std::string & reqHost){ | ||||
|   JSON::Value OutHTTP::getStatusJSON(std::string & reqHost, const std::string & useragent){ | ||||
|     JSON::Value json_resp; | ||||
|     if (config->getString("nostreamtext") != ""){ | ||||
|       json_resp["on_error"] = config->getString("nostreamtext"); | ||||
|  | @ -383,7 +425,7 @@ namespace Mist { | |||
|         //and a URL - then list the URL
 | ||||
|         JSON::Value capa_json = capa.asJSON(); | ||||
|         if (capa.getMember("url_rel") || capa.getMember("methods")){ | ||||
|           addSources(streamName, sources, outURL, capa_json, json_resp["meta"]); | ||||
|           addSources(streamName, sources, outURL, capa_json, json_resp["meta"], useragent); | ||||
|         } | ||||
|         //Make note if this connector can be depended upon by other connectors
 | ||||
|         if (capa.getMember("provides")){ | ||||
|  | @ -396,7 +438,7 @@ namespace Mist { | |||
|             //if it depends on this connector and has a URL, list it
 | ||||
|             if (conns.count(capa_lst.getIndiceName(j)) && capa_lst.getIndice(j).getMember("deps").asString() == cProv && capa_lst.getIndice(j).getMember("methods")){ | ||||
|               JSON::Value subcapa_json = capa_lst.getIndice(j).asJSON(); | ||||
|               addSources(streamName, sources, outURL, subcapa_json, json_resp["meta"]); | ||||
|               addSources(streamName, sources, outURL, subcapa_json, json_resp["meta"], useragent); | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|  | @ -536,6 +578,10 @@ namespace Mist { | |||
|     if ((H.url.length() > 9 && H.url.substr(0, 6) == "/info_" && H.url.substr(H.url.length() - 3, 3) == ".js") || (H.url.length() > 10 && H.url.substr(0, 7) == "/embed_" && H.url.substr(H.url.length() - 3, 3) == ".js") || (H.url.length() > 9 && H.url.substr(0, 6) == "/json_" && H.url.substr(H.url.length() - 3, 3) == ".js")){ | ||||
|       if (websocketHandler()){return;} | ||||
|       std::string reqHost = HTTP::URL(H.GetHeader("Host")).host; | ||||
|       std::string useragent = H.GetVar("ua"); | ||||
|       if (!useragent.size()){ | ||||
|         useragent = H.GetHeader("User-Agent"); | ||||
|       } | ||||
|       std::string response; | ||||
|       std::string rURL = H.url; | ||||
|       H.Clean(); | ||||
|  | @ -553,7 +599,7 @@ namespace Mist { | |||
|       } | ||||
|       initialize(); | ||||
|       response = "// Generating info code for stream " + streamName + "\n\nif (!mistvideo){var mistvideo = {};}\n"; | ||||
|       JSON::Value json_resp = getStatusJSON(reqHost); | ||||
|       JSON::Value json_resp = getStatusJSON(reqHost, useragent); | ||||
|       if (rURL.substr(0, 6) != "/json_"){ | ||||
|         response += "mistvideo['" + streamName + "'] = " + json_resp.toString() + ";\n"; | ||||
|       }else{ | ||||
|  | @ -764,6 +810,10 @@ namespace Mist { | |||
|   bool OutHTTP::websocketHandler(){ | ||||
|     stayConnected = true; | ||||
|     std::string reqHost = HTTP::URL(H.GetHeader("Host")).host; | ||||
|     std::string useragent = H.GetVar("ua"); | ||||
|     if (!useragent.size()){ | ||||
|       useragent = H.GetHeader("User-Agent"); | ||||
|     } | ||||
|     if (H.GetHeader("Upgrade") != "websocket"){return false;} | ||||
|     HTTP::Websocket ws(myConn, H); | ||||
|     if (!ws){return false;} | ||||
|  | @ -788,7 +838,7 @@ namespace Mist { | |||
|         }else{ | ||||
|           disconnect(); | ||||
|         } | ||||
|         JSON::Value resp = getStatusJSON(reqHost); | ||||
|         JSON::Value resp = getStatusJSON(reqHost, useragent); | ||||
|         ws.sendFrame(resp.toString()); | ||||
|         prevState = newState; | ||||
|       }else{ | ||||
|  |  | |||
|  | @ -15,7 +15,7 @@ namespace Mist { | |||
|       void onHTTP(); | ||||
|       void sendIcon(); | ||||
|       bool websocketHandler(); | ||||
|       JSON::Value getStatusJSON(std::string & reqHost); | ||||
|       JSON::Value getStatusJSON(std::string & reqHost, const std::string & useragent = ""); | ||||
|       bool stayConnected; | ||||
|       virtual bool onFinish(){ | ||||
|         return stayConnected; | ||||
|  |  | |||
|  | @ -26,9 +26,8 @@ namespace Mist{ | |||
|     capa["methods"][0u]["handler"] = "http"; | ||||
|     capa["methods"][0u]["type"] = "html5/video/mp4"; | ||||
|     capa["methods"][0u]["priority"] = 8ll; | ||||
|     ///\todo uncomment when we actually start implementing mp4 recording
 | ||||
|     //capa["canRecord"].append("mp4");
 | ||||
|     //capa["canRecord"].append("m3u");
 | ||||
|     //MP4 live is broken on Apple
 | ||||
|     capa["exceptions"]["live"] = JSON::fromString("[[\"blacklist\",[\"iPad\",\"iPhone\",\"iPod\",\"Safari\"]], [\"whitelist\",[\"Chrome\",\"Chromium\"]]]"); | ||||
|   } | ||||
| 
 | ||||
|   uint64_t OutProgressiveMP4::estimateFileSize(){ | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Thulinma
						Thulinma