Removed lots of left-over debug messages, added chunked transfer support to all segmented HTTP streaming methods, fixed several major slowdown problems, fixed HTTP progressive seconds-seeking.
This commit is contained in:
		
							parent
							
								
									2d9859bbad
								
							
						
					
					
						commit
						2bc9858b66
					
				
					 7 changed files with 460 additions and 481 deletions
				
			
		| 
						 | 
					@ -403,18 +403,14 @@ namespace Connector_HTTP {
 | 
				
			||||||
    }else{
 | 
					    }else{
 | 
				
			||||||
      long long int ret = Util::getMS();
 | 
					      long long int ret = Util::getMS();
 | 
				
			||||||
      //success, check type of response
 | 
					      //success, check type of response
 | 
				
			||||||
      std::cout << "Response headers for " << orig_url << " received...";
 | 
					 | 
				
			||||||
      if (H.GetHeader("Content-Length") != "" || H.GetHeader("Transfer-Encoding") == "chunked"){
 | 
					      if (H.GetHeader("Content-Length") != "" || H.GetHeader("Transfer-Encoding") == "chunked"){
 | 
				
			||||||
        //known length - simply re-send the request with added headers and continue
 | 
					        //known length - simply re-send the request with added headers and continue
 | 
				
			||||||
        H.SetHeader("X-UID", uid);
 | 
					        H.SetHeader("X-UID", uid);
 | 
				
			||||||
        H.SetHeader("Server", "mistserver/" PACKAGE_VERSION "/" + Util::Config::libver);
 | 
					        H.SetHeader("Server", "mistserver/" PACKAGE_VERSION "/" + Util::Config::libver);
 | 
				
			||||||
        H.body = "";
 | 
					        H.body = "";
 | 
				
			||||||
        std::cout << "proxying..." << std::endl;
 | 
					 | 
				
			||||||
        H.Proxy(*(myCConn->conn), *conn);
 | 
					        H.Proxy(*(myCConn->conn), *conn);
 | 
				
			||||||
        std::cout << "Proxying " << orig_url << " completed!" << std::endl;
 | 
					 | 
				
			||||||
        myCConn->inUse.unlock();
 | 
					        myCConn->inUse.unlock();
 | 
				
			||||||
      }else{
 | 
					      }else{
 | 
				
			||||||
        std::cout << "progressin'..." << std::endl;
 | 
					 | 
				
			||||||
        //unknown length
 | 
					        //unknown length
 | 
				
			||||||
        H.SetHeader("X-UID", uid);
 | 
					        H.SetHeader("X-UID", uid);
 | 
				
			||||||
        H.SetHeader("Server", "mistserver/" PACKAGE_VERSION "/" + Util::Config::libver);
 | 
					        H.SetHeader("Server", "mistserver/" PACKAGE_VERSION "/" + Util::Config::libver);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -150,7 +150,7 @@ namespace Connector_HTTP {
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    Socket::Connection ss( -1);
 | 
					    Socket::Connection ss( -1);
 | 
				
			||||||
    std::string streamname;
 | 
					    std::string streamname;
 | 
				
			||||||
    std::string recBuffer = "";
 | 
					    bool handlingRequest = false;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    int Quality = 0;
 | 
					    int Quality = 0;
 | 
				
			||||||
    int Segment = -1;
 | 
					    int Segment = -1;
 | 
				
			||||||
| 
						 | 
					@ -161,124 +161,125 @@ namespace Connector_HTTP {
 | 
				
			||||||
    conn.setBlocking(false); //do not block on conn.spool() when no data is available
 | 
					    conn.setBlocking(false); //do not block on conn.spool() when no data is available
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    while (conn.connected()){
 | 
					    while (conn.connected()){
 | 
				
			||||||
      if (conn.spool() || conn.Received().size()){
 | 
					      if ( !handlingRequest){
 | 
				
			||||||
        if (HTTP_R.Read(conn)){
 | 
					        if (conn.spool() || conn.Received().size()){
 | 
				
			||||||
          #if DEBUG >= 5
 | 
					          if (HTTP_R.Read(conn)){
 | 
				
			||||||
          std::cout << "Received request: " << HTTP_R.getUrl() << std::endl;
 | 
					 | 
				
			||||||
          #endif
 | 
					 | 
				
			||||||
          conn.setHost(HTTP_R.GetHeader("X-Origin"));
 | 
					 | 
				
			||||||
          streamname = HTTP_R.GetHeader("X-Stream");
 | 
					 | 
				
			||||||
          if ( !ss){
 | 
					 | 
				
			||||||
            ss = Util::Stream::getStream(streamname);
 | 
					 | 
				
			||||||
            if ( !ss.connected()){
 | 
					 | 
				
			||||||
              HTTP_S.Clean();
 | 
					 | 
				
			||||||
              HTTP_S.SetBody("No such stream is available on the system. Please try again.\n");
 | 
					 | 
				
			||||||
              conn.SendNow(HTTP_S.BuildResponse("404", "Not found"));
 | 
					 | 
				
			||||||
              continue;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            ss.setBlocking(false);
 | 
					 | 
				
			||||||
            //make sure metadata is received
 | 
					 | 
				
			||||||
            while ( !Strm.metadata && ss.connected()){
 | 
					 | 
				
			||||||
              if (ss.spool()){
 | 
					 | 
				
			||||||
                while (Strm.parsePacket(ss.Received())){
 | 
					 | 
				
			||||||
                  //do nothing
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          if (HTTP_R.url.find(".abst") != std::string::npos){
 | 
					 | 
				
			||||||
            std::string streamID = HTTP_R.url.substr(HTTP_R.url.find(streamname) + streamname.size() + 1);
 | 
					 | 
				
			||||||
            streamID = streamID.substr(0, streamID.find(".abst"));
 | 
					 | 
				
			||||||
            std::cerr << "Requesting bootstrap for stream " << streamID << std::endl;
 | 
					 | 
				
			||||||
            HTTP_S.Clean();
 | 
					 | 
				
			||||||
            HTTP_S.SetBody(dynamicBootstrap(streamname, Strm.getTrackById(atoll(streamID.c_str())),Strm.metadata.isMember("live")));
 | 
					 | 
				
			||||||
            HTTP_S.SetHeader("Content-Type", "binary/octet");
 | 
					 | 
				
			||||||
            HTTP_S.SetHeader("Cache-Control", "no-cache");
 | 
					 | 
				
			||||||
            conn.SendNow(HTTP_S.BuildResponse("200", "OK"));
 | 
					 | 
				
			||||||
            HTTP_R.Clean(); //clean for any possible next requests
 | 
					 | 
				
			||||||
            continue;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          if (HTTP_R.url.find("f4m") == std::string::npos){
 | 
					 | 
				
			||||||
            std::string tmp_qual = HTTP_R.url.substr(HTTP_R.url.find("/", 10) + 1);
 | 
					 | 
				
			||||||
            Quality = atoi(tmp_qual.substr(0, tmp_qual.find("Seg") - 1).c_str());
 | 
					 | 
				
			||||||
            int temp;
 | 
					 | 
				
			||||||
            temp = HTTP_R.url.find("Seg") + 3;
 | 
					 | 
				
			||||||
            Segment = atoi(HTTP_R.url.substr(temp, HTTP_R.url.find("-", temp) - temp).c_str());
 | 
					 | 
				
			||||||
            temp = HTTP_R.url.find("Frag") + 4;
 | 
					 | 
				
			||||||
            ReqFragment = atoi(HTTP_R.url.substr(temp).c_str());
 | 
					 | 
				
			||||||
            #if DEBUG >= 5
 | 
					            #if DEBUG >= 5
 | 
				
			||||||
            printf("Video track %d, segment %d, fragment %d\n", Quality, Segment, ReqFragment);
 | 
					            std::cout << "Received request: " << HTTP_R.getUrl() << std::endl;
 | 
				
			||||||
            #endif
 | 
					            #endif
 | 
				
			||||||
            if (!audioTrack){getTracks(Strm.metadata);}
 | 
					            conn.setHost(HTTP_R.GetHeader("X-Origin"));
 | 
				
			||||||
            JSON::Value & vidTrack = Strm.getTrackById(Quality);
 | 
					            streamname = HTTP_R.GetHeader("X-Stream");
 | 
				
			||||||
            mstime = 0;
 | 
					            if ( !ss){
 | 
				
			||||||
            mslen = 0;
 | 
					              ss = Util::Stream::getStream(streamname);
 | 
				
			||||||
            if (vidTrack.isMember("keys")){
 | 
					              if ( !ss.connected()){
 | 
				
			||||||
              for (JSON::ArrIter it = vidTrack["keys"].ArrBegin(); it != vidTrack["keys"].ArrEnd(); it++){
 | 
					 | 
				
			||||||
                if ((*it)["num"].asInt() >= ReqFragment){
 | 
					 | 
				
			||||||
                  mstime = (*it)["time"].asInt();
 | 
					 | 
				
			||||||
                  mslen = (*it)["len"].asInt();
 | 
					 | 
				
			||||||
                  if (Strm.metadata.isMember("live")){
 | 
					 | 
				
			||||||
                    if (it == vidTrack["keys"].ArrEnd() - 2){
 | 
					 | 
				
			||||||
                      HTTP_S.Clean();
 | 
					 | 
				
			||||||
                      HTTP_S.SetBody("Proxy, re-request this in a second or two.\n");
 | 
					 | 
				
			||||||
                      conn.SendNow(HTTP_S.BuildResponse("208", "Ask again later"));
 | 
					 | 
				
			||||||
                      HTTP_R.Clean(); //clean for any possible next requests
 | 
					 | 
				
			||||||
                      std::cout << "Fragment after fragment " << ReqFragment << " not available yet" << std::endl;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                  }
 | 
					 | 
				
			||||||
                  break;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (HTTP_R.url == "/"){continue;}//Don't continue, but continue instead.
 | 
					 | 
				
			||||||
            if (Strm.metadata.isMember("live")){
 | 
					 | 
				
			||||||
              if (mstime == 0 && ReqFragment > 1){
 | 
					 | 
				
			||||||
                HTTP_S.Clean();
 | 
					                HTTP_S.Clean();
 | 
				
			||||||
                HTTP_S.SetBody("The requested fragment is no longer kept in memory on the server and cannot be served.\n");
 | 
					                HTTP_S.SetBody("No such stream is available on the system. Please try again.\n");
 | 
				
			||||||
                conn.SendNow(HTTP_S.BuildResponse("412", "Fragment out of range"));
 | 
					                HTTP_S.SendResponse("404", "Not found", conn);
 | 
				
			||||||
                HTTP_R.Clean(); //clean for any possible next requests
 | 
					 | 
				
			||||||
                std::cout << "Fragment " << ReqFragment << " too old" << std::endl;
 | 
					 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
 | 
					              ss.setBlocking(false);
 | 
				
			||||||
 | 
					              //make sure metadata is received
 | 
				
			||||||
 | 
					              while ( !Strm.metadata && ss.connected()){
 | 
				
			||||||
 | 
					                if (ss.spool()){
 | 
				
			||||||
 | 
					                  while (Strm.parsePacket(ss.Received())){
 | 
				
			||||||
 | 
					                    //do nothing
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            std::stringstream sstream;
 | 
					            if (HTTP_R.url.find(".abst") != std::string::npos){
 | 
				
			||||||
            sstream << "t " << Quality << " " << audioTrack << "\ns " << mstime << "\np " << (mstime + mslen) << "\n";
 | 
					              std::string streamID = HTTP_R.url.substr(HTTP_R.url.find(streamname) + streamname.size() + 1);
 | 
				
			||||||
            ss.SendNow(sstream.str().c_str());
 | 
					              streamID = streamID.substr(0, streamID.find(".abst"));
 | 
				
			||||||
            std::cout << sstream.str() << std::endl;
 | 
					              std::cerr << "Requesting bootstrap for stream " << streamID << std::endl;
 | 
				
			||||||
            
 | 
					              HTTP_S.Clean();
 | 
				
			||||||
            HTTP_S.Clean();
 | 
					              HTTP_S.SetBody(dynamicBootstrap(streamname, Strm.getTrackById(atoll(streamID.c_str())),Strm.metadata.isMember("live")));
 | 
				
			||||||
            HTTP_S.protocol = "HTTP/1.1";
 | 
					              HTTP_S.SetHeader("Content-Type", "binary/octet");
 | 
				
			||||||
            HTTP_S.SetHeader("Content-Type", "video/mp4");
 | 
					              HTTP_S.SetHeader("Cache-Control", "no-cache");
 | 
				
			||||||
            HTTP_S.SetBody("");
 | 
					              HTTP_S.SendResponse("200", "OK", conn);
 | 
				
			||||||
            std::string new_strap = dynamicBootstrap(streamname, Strm.getTrackById(Quality), Strm.metadata.isMember("live"), ReqFragment);
 | 
					              HTTP_R.Clean(); //clean for any possible next requests
 | 
				
			||||||
            HTTP_S.SetHeader("Transfer-Encoding", "chunked");
 | 
					              continue;
 | 
				
			||||||
            HTTP_S.SendResponse("200", "OK", conn);
 | 
					 | 
				
			||||||
            HTTP_S.Chunkify(new_strap, conn);
 | 
					 | 
				
			||||||
            HTTP_S.Chunkify("\000\000\000\000mdat", 8, conn);
 | 
					 | 
				
			||||||
            //fill buffer with init data, if needed.
 | 
					 | 
				
			||||||
            if (audioTrack > 0 && Strm.getTrackById(audioTrack).isMember("init")){
 | 
					 | 
				
			||||||
              tmp.DTSCAudioInit(Strm.getTrackById(audioTrack));
 | 
					 | 
				
			||||||
              tmp.tagTime(mstime);
 | 
					 | 
				
			||||||
              HTTP_S.Chunkify(tmp.data, tmp.len, conn);
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (Quality > 0 && Strm.getTrackById(Quality).isMember("init")){
 | 
					            if (HTTP_R.url.find("f4m") == std::string::npos){
 | 
				
			||||||
              tmp.DTSCVideoInit(Strm.getTrackById(Quality));
 | 
					              std::string tmp_qual = HTTP_R.url.substr(HTTP_R.url.find("/", 10) + 1);
 | 
				
			||||||
              tmp.tagTime(mstime);
 | 
					              Quality = atoi(tmp_qual.substr(0, tmp_qual.find("Seg") - 1).c_str());
 | 
				
			||||||
              HTTP_S.Chunkify(tmp.data, tmp.len, conn);
 | 
					              int temp;
 | 
				
			||||||
 | 
					              temp = HTTP_R.url.find("Seg") + 3;
 | 
				
			||||||
 | 
					              Segment = atoi(HTTP_R.url.substr(temp, HTTP_R.url.find("-", temp) - temp).c_str());
 | 
				
			||||||
 | 
					              temp = HTTP_R.url.find("Frag") + 4;
 | 
				
			||||||
 | 
					              ReqFragment = atoi(HTTP_R.url.substr(temp).c_str());
 | 
				
			||||||
 | 
					              #if DEBUG >= 5
 | 
				
			||||||
 | 
					              printf("Video track %d, segment %d, fragment %d\n", Quality, Segment, ReqFragment);
 | 
				
			||||||
 | 
					              #endif
 | 
				
			||||||
 | 
					              if (!audioTrack){getTracks(Strm.metadata);}
 | 
				
			||||||
 | 
					              JSON::Value & vidTrack = Strm.getTrackById(Quality);
 | 
				
			||||||
 | 
					              mstime = 0;
 | 
				
			||||||
 | 
					              mslen = 0;
 | 
				
			||||||
 | 
					              if (vidTrack.isMember("keys")){
 | 
				
			||||||
 | 
					                for (JSON::ArrIter it = vidTrack["keys"].ArrBegin(); it != vidTrack["keys"].ArrEnd(); it++){
 | 
				
			||||||
 | 
					                  if ((*it)["num"].asInt() >= ReqFragment){
 | 
				
			||||||
 | 
					                    mstime = (*it)["time"].asInt();
 | 
				
			||||||
 | 
					                    mslen = (*it)["len"].asInt();
 | 
				
			||||||
 | 
					                    if (Strm.metadata.isMember("live")){
 | 
				
			||||||
 | 
					                      if (it == vidTrack["keys"].ArrEnd() - 2){
 | 
				
			||||||
 | 
					                        HTTP_S.Clean();
 | 
				
			||||||
 | 
					                        HTTP_S.SetBody("Proxy, re-request this in a second or two.\n");
 | 
				
			||||||
 | 
					                        HTTP_S.SendResponse("208", "Ask again later", conn);
 | 
				
			||||||
 | 
					                        HTTP_R.Clean(); //clean for any possible next requests
 | 
				
			||||||
 | 
					                        std::cout << "Fragment after fragment " << ReqFragment << " not available yet" << std::endl;
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              if (HTTP_R.url == "/"){continue;}//Don't continue, but continue instead.
 | 
				
			||||||
 | 
					              if (Strm.metadata.isMember("live")){
 | 
				
			||||||
 | 
					                if (mstime == 0 && ReqFragment > 1){
 | 
				
			||||||
 | 
					                  HTTP_S.Clean();
 | 
				
			||||||
 | 
					                  HTTP_S.SetBody("The requested fragment is no longer kept in memory on the server and cannot be served.\n");
 | 
				
			||||||
 | 
					                  HTTP_S.SendResponse("412", "Fragment out of range", conn);
 | 
				
			||||||
 | 
					                  HTTP_R.Clean(); //clean for any possible next requests
 | 
				
			||||||
 | 
					                  std::cout << "Fragment " << ReqFragment << " too old" << std::endl;
 | 
				
			||||||
 | 
					                  continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              std::stringstream sstream;
 | 
				
			||||||
 | 
					              sstream << "t " << Quality << " " << audioTrack << "\ns " << mstime << "\np " << (mstime + mslen) << "\n";
 | 
				
			||||||
 | 
					              ss.SendNow(sstream.str().c_str());
 | 
				
			||||||
 | 
					              
 | 
				
			||||||
 | 
					              HTTP_S.Clean();
 | 
				
			||||||
 | 
					              HTTP_S.SetHeader("Content-Type", "video/mp4");
 | 
				
			||||||
 | 
					              HTTP_S.StartResponse(HTTP_R, conn);
 | 
				
			||||||
 | 
					              //send the bootstrap
 | 
				
			||||||
 | 
					              std::string bootstrap = dynamicBootstrap(streamname, Strm.getTrackById(Quality), Strm.metadata.isMember("live"), ReqFragment);
 | 
				
			||||||
 | 
					              HTTP_S.Chunkify(bootstrap, conn);
 | 
				
			||||||
 | 
					              //send a zero-size mdat, meaning it stretches until end of file.
 | 
				
			||||||
 | 
					              HTTP_S.Chunkify("\000\000\000\000mdat", 8, conn);
 | 
				
			||||||
 | 
					              //send init data, if needed.
 | 
				
			||||||
 | 
					              if (audioTrack > 0 && Strm.getTrackById(audioTrack).isMember("init")){
 | 
				
			||||||
 | 
					                tmp.DTSCAudioInit(Strm.getTrackById(audioTrack));
 | 
				
			||||||
 | 
					                tmp.tagTime(mstime);
 | 
				
			||||||
 | 
					                HTTP_S.Chunkify(tmp.data, tmp.len, conn);
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              if (Quality > 0 && Strm.getTrackById(Quality).isMember("init")){
 | 
				
			||||||
 | 
					                tmp.DTSCVideoInit(Strm.getTrackById(Quality));
 | 
				
			||||||
 | 
					                tmp.tagTime(mstime);
 | 
				
			||||||
 | 
					                HTTP_S.Chunkify(tmp.data, tmp.len, conn);
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              handlingRequest = true;
 | 
				
			||||||
 | 
					            }else{
 | 
				
			||||||
 | 
					              HTTP_S.Clean();
 | 
				
			||||||
 | 
					              HTTP_S.SetHeader("Content-Type", "text/xml");
 | 
				
			||||||
 | 
					              HTTP_S.SetHeader("Cache-Control", "no-cache");
 | 
				
			||||||
 | 
					              HTTP_S.SetBody(dynamicIndex(streamname, Strm.metadata));
 | 
				
			||||||
 | 
					              HTTP_S.SendResponse("200", "OK", conn);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }else{
 | 
					            HTTP_R.Clean(); //clean for any possible next requests
 | 
				
			||||||
            HTTP_S.Clean();
 | 
					 | 
				
			||||||
            HTTP_S.SetHeader("Content-Type", "text/xml");
 | 
					 | 
				
			||||||
            HTTP_S.SetHeader("Cache-Control", "no-cache");
 | 
					 | 
				
			||||||
            std::string manifest = dynamicIndex(streamname, Strm.metadata);
 | 
					 | 
				
			||||||
            HTTP_S.SetBody(manifest);
 | 
					 | 
				
			||||||
            conn.SendNow(HTTP_S.BuildResponse("200", "OK"));
 | 
					 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          HTTP_R.Clean(); //clean for any possible next requests
 | 
					        }else{
 | 
				
			||||||
 | 
					          //sleep for 250ms before next attempt
 | 
				
			||||||
 | 
					          Util::sleep(250);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }else{
 | 
					 | 
				
			||||||
        Util::sleep(1);
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (ss.connected()){
 | 
					      if (ss.connected()){
 | 
				
			||||||
        unsigned int now = Util::epoch();
 | 
					        unsigned int now = Util::epoch();
 | 
				
			||||||
| 
						 | 
					@ -286,13 +287,12 @@ namespace Connector_HTTP {
 | 
				
			||||||
          lastStats = now;
 | 
					          lastStats = now;
 | 
				
			||||||
          ss.SendNow(conn.getStats("HTTP_Dynamic").c_str());
 | 
					          ss.SendNow(conn.getStats("HTTP_Dynamic").c_str());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (ss.spool()){
 | 
					        if (handlingRequest && ss.spool()){
 | 
				
			||||||
          while (Strm.parsePacket(ss.Received())){
 | 
					          while (Strm.parsePacket(ss.Received())){
 | 
				
			||||||
            if (Strm.lastType() == DTSC::PAUSEMARK){
 | 
					            if (Strm.lastType() == DTSC::PAUSEMARK){
 | 
				
			||||||
              //send an empty chunk to signify request is done
 | 
					              //send an empty chunk to signify request is done
 | 
				
			||||||
              std::string empty = "";
 | 
					              HTTP_S.Chunkify("", 0, conn);
 | 
				
			||||||
              HTTP_S.Chunkify(empty, conn);
 | 
					              handlingRequest = false;
 | 
				
			||||||
              std::cout << "Finito!" << std::endl;
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (Strm.lastType() == DTSC::VIDEO || Strm.lastType() == DTSC::AUDIO){
 | 
					            if (Strm.lastType() == DTSC::VIDEO || Strm.lastType() == DTSC::AUDIO){
 | 
				
			||||||
              //send a chunk with the new data
 | 
					              //send a chunk with the new data
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -94,9 +94,6 @@ namespace Connector_HTTP {
 | 
				
			||||||
  ///\param conn A socket describing the connection the client.
 | 
					  ///\param conn A socket describing the connection the client.
 | 
				
			||||||
  ///\return The exit code of the connector.
 | 
					  ///\return The exit code of the connector.
 | 
				
			||||||
  int liveConnector(Socket::Connection conn){
 | 
					  int liveConnector(Socket::Connection conn){
 | 
				
			||||||
    std::stringstream TSBuf;
 | 
					 | 
				
			||||||
    long long int TSBufTime = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    DTSC::Stream Strm; //Incoming stream buffer.
 | 
					    DTSC::Stream Strm; //Incoming stream buffer.
 | 
				
			||||||
    HTTP::Parser HTTP_R, HTTP_S; //HTTP Receiver en HTTP Sender.
 | 
					    HTTP::Parser HTTP_R, HTTP_S; //HTTP Receiver en HTTP Sender.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -104,6 +101,7 @@ namespace Connector_HTTP {
 | 
				
			||||||
    bool AppleCompat = false; //Set to true when Apple device detected.
 | 
					    bool AppleCompat = false; //Set to true when Apple device detected.
 | 
				
			||||||
    Socket::Connection ss( -1);
 | 
					    Socket::Connection ss( -1);
 | 
				
			||||||
    std::string streamname;
 | 
					    std::string streamname;
 | 
				
			||||||
 | 
					    bool handlingRequest = false;
 | 
				
			||||||
    std::string recBuffer = "";
 | 
					    std::string recBuffer = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    TS::Packet PackData;
 | 
					    TS::Packet PackData;
 | 
				
			||||||
| 
						 | 
					@ -129,100 +127,107 @@ namespace Connector_HTTP {
 | 
				
			||||||
    conn.setBlocking(false); //do not block on conn.spool() when no data is available
 | 
					    conn.setBlocking(false); //do not block on conn.spool() when no data is available
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (conn.connected()){
 | 
					    while (conn.connected()){
 | 
				
			||||||
      if (conn.spool() || conn.Received().size()){
 | 
					      if ( !handlingRequest){
 | 
				
			||||||
        if (HTTP_R.Read(conn)){
 | 
					        if (conn.spool() || conn.Received().size()){
 | 
				
			||||||
#if DEBUG >= 5
 | 
					          if (HTTP_R.Read(conn)){
 | 
				
			||||||
          std::cout << "Received request: " << HTTP_R.getUrl() << std::endl;
 | 
					  #if DEBUG >= 5
 | 
				
			||||||
#endif
 | 
					            std::cout << "Received request: " << HTTP_R.getUrl() << std::endl;
 | 
				
			||||||
          conn.setHost(HTTP_R.GetHeader("X-Origin"));
 | 
					  #endif
 | 
				
			||||||
          AppleCompat = (HTTP_R.GetHeader("User-Agent").find("Apple") != std::string::npos);
 | 
					            conn.setHost(HTTP_R.GetHeader("X-Origin"));
 | 
				
			||||||
          streamname = HTTP_R.GetHeader("X-Stream");
 | 
					            AppleCompat = (HTTP_R.GetHeader("User-Agent").find("Apple") != std::string::npos);
 | 
				
			||||||
          if ( !ss){
 | 
					            streamname = HTTP_R.GetHeader("X-Stream");
 | 
				
			||||||
            ss = Util::Stream::getStream(streamname);
 | 
					            if ( !ss){
 | 
				
			||||||
            if ( !ss.connected()){
 | 
					              ss = Util::Stream::getStream(streamname);
 | 
				
			||||||
              #if DEBUG >= 1
 | 
					              if ( !ss.connected()){
 | 
				
			||||||
              fprintf(stderr, "Could not connect to server!\n");
 | 
					                #if DEBUG >= 1
 | 
				
			||||||
              #endif
 | 
					                fprintf(stderr, "Could not connect to server!\n");
 | 
				
			||||||
              HTTP_S.Clean();
 | 
					                #endif
 | 
				
			||||||
              HTTP_S.SetBody("No such stream is available on the system. Please try again.\n");
 | 
					                HTTP_S.Clean();
 | 
				
			||||||
              conn.SendNow(HTTP_S.BuildResponse("404", "Not found"));
 | 
					                HTTP_S.SetBody("No such stream is available on the system. Please try again.\n");
 | 
				
			||||||
              ready4data = false;
 | 
					                conn.SendNow(HTTP_S.BuildResponse("404", "Not found"));
 | 
				
			||||||
              continue;
 | 
					                ready4data = false;
 | 
				
			||||||
            }
 | 
					                continue;
 | 
				
			||||||
            ss.setBlocking(false);
 | 
					              }
 | 
				
			||||||
            //make sure metadata is received
 | 
					              ss.setBlocking(false);
 | 
				
			||||||
            while ( !Strm.metadata && ss.connected()){
 | 
					              //make sure metadata is received
 | 
				
			||||||
              if (ss.spool()){
 | 
					              while ( !Strm.metadata && ss.connected()){
 | 
				
			||||||
                while (Strm.parsePacket(ss.Received())){
 | 
					                if (ss.spool()){
 | 
				
			||||||
                  //do nothing
 | 
					                  while (Strm.parsePacket(ss.Received())){
 | 
				
			||||||
 | 
					                    //do nothing
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					            if (HTTP_R.url.find(".m3u") == std::string::npos){
 | 
				
			||||||
          if (HTTP_R.url.find(".m3u") == std::string::npos){
 | 
					              temp = HTTP_R.url.find("/", 5) + 1;
 | 
				
			||||||
            temp = HTTP_R.url.find("/", 5) + 1;
 | 
					              std::string allTracks = HTTP_R.url.substr(temp, HTTP_R.url.find("/", temp) - temp);
 | 
				
			||||||
            std::string allTracks = HTTP_R.url.substr(temp, HTTP_R.url.find("/", temp) - temp);
 | 
					              trackID = atoi(allTracks.c_str());
 | 
				
			||||||
            trackID = atoi(allTracks.c_str());
 | 
					              audioTrackID = atoi(allTracks.substr(allTracks.find("_")+1).c_str());
 | 
				
			||||||
            audioTrackID = atoi(allTracks.substr(allTracks.find("_")+1).c_str());
 | 
					              temp = HTTP_R.url.find("/", temp) + 1;
 | 
				
			||||||
            temp = HTTP_R.url.find("/", temp) + 1;
 | 
					              Segment = atoi(HTTP_R.url.substr(temp, HTTP_R.url.find("_", temp) - temp).c_str());
 | 
				
			||||||
            Segment = atoi(HTTP_R.url.substr(temp, HTTP_R.url.find("_", temp) - temp).c_str());
 | 
					              lastVid = Segment * 90;
 | 
				
			||||||
            lastVid = Segment * 90;
 | 
					              temp = HTTP_R.url.find("_", temp) + 1;
 | 
				
			||||||
            temp = HTTP_R.url.find("_", temp) + 1;
 | 
					              int frameCount = atoi(HTTP_R.url.substr(temp, HTTP_R.url.find(".ts", temp) - temp).c_str());
 | 
				
			||||||
            int frameCount = atoi(HTTP_R.url.substr(temp, HTTP_R.url.find(".ts", temp) - temp).c_str());
 | 
					              if (Strm.metadata.isMember("live")){
 | 
				
			||||||
            if (Strm.metadata.isMember("live")){
 | 
					                int seekable = Strm.canSeekms(Segment);
 | 
				
			||||||
              int seekable = Strm.canSeekms(Segment);
 | 
					                if (seekable < 0){
 | 
				
			||||||
              if (seekable < 0){
 | 
					                  HTTP_S.Clean();
 | 
				
			||||||
                HTTP_S.Clean();
 | 
					                  HTTP_S.SetBody("The requested fragment is no longer kept in memory on the server and cannot be served.\n");
 | 
				
			||||||
                HTTP_S.SetBody("The requested fragment is no longer kept in memory on the server and cannot be served.\n");
 | 
					                  conn.SendNow(HTTP_S.BuildResponse("412", "Fragment out of range"));
 | 
				
			||||||
                conn.SendNow(HTTP_S.BuildResponse("412", "Fragment out of range"));
 | 
					                  HTTP_R.Clean(); //clean for any possible next requests
 | 
				
			||||||
                HTTP_R.Clean(); //clean for any possible next requests
 | 
					                  std::cout << "Fragment @ " << Segment << " too old" << std::endl;
 | 
				
			||||||
                std::cout << "Fragment @ " << Segment << " too old" << std::endl;
 | 
					                  continue;
 | 
				
			||||||
                continue;
 | 
					                }
 | 
				
			||||||
 | 
					                if (seekable > 0){
 | 
				
			||||||
 | 
					                  HTTP_S.Clean();
 | 
				
			||||||
 | 
					                  HTTP_S.SetBody("Proxy, re-request this in a second or two.\n");
 | 
				
			||||||
 | 
					                  conn.SendNow(HTTP_S.BuildResponse("208", "Ask again later"));
 | 
				
			||||||
 | 
					                  HTTP_R.Clean(); //clean for any possible next requests
 | 
				
			||||||
 | 
					                  std::cout << "Fragment @ " << Segment << " not available yet" << std::endl;
 | 
				
			||||||
 | 
					                  continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
              if (seekable > 0){
 | 
					              for (int i = 0; i < allTracks.size(); i++){
 | 
				
			||||||
                HTTP_S.Clean();
 | 
					                if (allTracks[i] == '_'){
 | 
				
			||||||
                HTTP_S.SetBody("Proxy, re-request this in a second or two.\n");
 | 
					                  allTracks[i] = ' ';
 | 
				
			||||||
                conn.SendNow(HTTP_S.BuildResponse("208", "Ask again later"));
 | 
					                }
 | 
				
			||||||
                HTTP_R.Clean(); //clean for any possible next requests
 | 
					 | 
				
			||||||
                std::cout << "Fragment @ " << Segment << " not available yet" << std::endl;
 | 
					 | 
				
			||||||
                continue;
 | 
					 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            }
 | 
					              std::stringstream sstream;
 | 
				
			||||||
            for (int i = 0; i < allTracks.size(); i++){
 | 
					              sstream << "t " << allTracks << "\n";
 | 
				
			||||||
              if (allTracks[i] == '_'){
 | 
					              sstream << "s " << Segment << "\n";
 | 
				
			||||||
                allTracks[i] = ' ';
 | 
					              sstream << "p " << frameCount << "\n";
 | 
				
			||||||
              }
 | 
					              ss.SendNow(sstream.str().c_str());
 | 
				
			||||||
            }
 | 
					              
 | 
				
			||||||
            std::stringstream sstream;
 | 
					              HTTP_S.Clean();
 | 
				
			||||||
            sstream << "t " << allTracks << "\n";
 | 
					              HTTP_S.SetHeader("Content-Type", "video/mp2t");
 | 
				
			||||||
            sstream << "s " << Segment << "\n";
 | 
					              HTTP_S.StartResponse(HTTP_R, conn);
 | 
				
			||||||
            sstream << "p " << frameCount << "\n";
 | 
					              handlingRequest = true;
 | 
				
			||||||
            ss.SendNow(sstream.str().c_str());
 | 
					 | 
				
			||||||
          }else{
 | 
					 | 
				
			||||||
            std::string request = HTTP_R.url.substr(HTTP_R.url.find("/", 5) + 1);
 | 
					 | 
				
			||||||
            if (HTTP_R.url.find(".m3u8") != std::string::npos){
 | 
					 | 
				
			||||||
              manifestType = "audio/x-mpegurl";
 | 
					 | 
				
			||||||
            }else{
 | 
					            }else{
 | 
				
			||||||
              manifestType = "audio/mpegurl";
 | 
					              std::string request = HTTP_R.url.substr(HTTP_R.url.find("/", 5) + 1);
 | 
				
			||||||
 | 
					              if (HTTP_R.url.find(".m3u8") != std::string::npos){
 | 
				
			||||||
 | 
					                manifestType = "audio/x-mpegurl";
 | 
				
			||||||
 | 
					              }else{
 | 
				
			||||||
 | 
					                manifestType = "audio/mpegurl";
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              HTTP_S.Clean();
 | 
				
			||||||
 | 
					              HTTP_S.SetHeader("Content-Type", manifestType);
 | 
				
			||||||
 | 
					              HTTP_S.SetHeader("Cache-Control", "no-cache");
 | 
				
			||||||
 | 
					              std::string manifest;
 | 
				
			||||||
 | 
					              if (request.find("/") == std::string::npos){
 | 
				
			||||||
 | 
					                manifest = liveIndex(Strm.metadata, Strm.metadata.isMember("live"));
 | 
				
			||||||
 | 
					              }else{
 | 
				
			||||||
 | 
					                int selectId = atoi(request.substr(0,request.find("/")).c_str());
 | 
				
			||||||
 | 
					                manifest = liveIndex(Strm.getTrackById(selectId), Strm.metadata.isMember("live"));
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              HTTP_S.SetBody(manifest);
 | 
				
			||||||
 | 
					              conn.SendNow(HTTP_S.BuildResponse("200", "OK"));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            HTTP_S.Clean();
 | 
					            ready4data = true;
 | 
				
			||||||
            HTTP_S.SetHeader("Content-Type", manifestType);
 | 
					            HTTP_R.Clean(); //clean for any possible next requests
 | 
				
			||||||
            HTTP_S.SetHeader("Cache-Control", "no-cache");
 | 
					 | 
				
			||||||
            std::string manifest;
 | 
					 | 
				
			||||||
            if (request.find("/") == std::string::npos){
 | 
					 | 
				
			||||||
              manifest = liveIndex(Strm.metadata, Strm.metadata.isMember("live"));
 | 
					 | 
				
			||||||
            }else{
 | 
					 | 
				
			||||||
              int selectId = atoi(request.substr(0,request.find("/")).c_str());
 | 
					 | 
				
			||||||
              manifest = liveIndex(Strm.getTrackById(selectId), Strm.metadata.isMember("live"));
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            HTTP_S.SetBody(manifest);
 | 
					 | 
				
			||||||
            conn.SendNow(HTTP_S.BuildResponse("200", "OK"));
 | 
					 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          ready4data = true;
 | 
					        }else{
 | 
				
			||||||
          HTTP_R.Clean(); //clean for any possible next requests
 | 
					          Util::sleep(250);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }else{
 | 
					 | 
				
			||||||
        Util::sleep(1);
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (ready4data){
 | 
					      if (ready4data){
 | 
				
			||||||
        unsigned int now = Util::epoch();
 | 
					        unsigned int now = Util::epoch();
 | 
				
			||||||
| 
						 | 
					@ -230,23 +235,11 @@ namespace Connector_HTTP {
 | 
				
			||||||
          lastStats = now;
 | 
					          lastStats = now;
 | 
				
			||||||
          ss.SendNow(conn.getStats("HTTP_Live").c_str());
 | 
					          ss.SendNow(conn.getStats("HTTP_Live").c_str());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (ss.spool()){
 | 
					        if (handlingRequest && ss.spool()){
 | 
				
			||||||
          while (Strm.parsePacket(ss.Received())){
 | 
					          while (Strm.parsePacket(ss.Received())){
 | 
				
			||||||
            if (Strm.lastType() == DTSC::PAUSEMARK){
 | 
					            if (Strm.lastType() == DTSC::PAUSEMARK){
 | 
				
			||||||
              TSBuf.flush();
 | 
					              HTTP_S.Chunkify("", 0, conn);
 | 
				
			||||||
              if (TSBuf.str().size()){
 | 
					              handlingRequest = false;
 | 
				
			||||||
                HTTP_S.Clean();
 | 
					 | 
				
			||||||
                HTTP_S.protocol = "HTTP/1.1";
 | 
					 | 
				
			||||||
                HTTP_S.SetHeader("Content-Type", "video/mp2t");
 | 
					 | 
				
			||||||
                HTTP_S.SetHeader("Connection", "keep-alive");
 | 
					 | 
				
			||||||
                HTTP_S.SetBody("");
 | 
					 | 
				
			||||||
                HTTP_S.SetHeader("Content-Length", TSBuf.str().size());
 | 
					 | 
				
			||||||
                conn.SendNow(HTTP_S.BuildResponse("200", "OK"));
 | 
					 | 
				
			||||||
                conn.SendNow(TSBuf.str().c_str(), TSBuf.str().size());
 | 
					 | 
				
			||||||
                TSBuf.str("");
 | 
					 | 
				
			||||||
                PacketNumber = 0;
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
              TSBuf.str("");
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if ( !haveAvcc){
 | 
					            if ( !haveAvcc){
 | 
				
			||||||
              avccbox.setPayload(Strm.getTrackById(trackID)["init"].asString());
 | 
					              avccbox.setPayload(Strm.getTrackById(trackID)["init"].asString());
 | 
				
			||||||
| 
						 | 
					@ -257,9 +250,9 @@ namespace Connector_HTTP {
 | 
				
			||||||
              //write PAT and PMT TS packets
 | 
					              //write PAT and PMT TS packets
 | 
				
			||||||
              if (PacketNumber % 42 == 0){
 | 
					              if (PacketNumber % 42 == 0){
 | 
				
			||||||
                PackData.DefaultPAT();
 | 
					                PackData.DefaultPAT();
 | 
				
			||||||
                TSBuf.write(PackData.ToString(), 188);
 | 
					                HTTP_S.Chunkify(PackData.ToString(), 188, conn);
 | 
				
			||||||
                PackData.DefaultPMT();
 | 
					                PackData.DefaultPMT();
 | 
				
			||||||
                TSBuf.write(PackData.ToString(), 188);
 | 
					                HTTP_S.Chunkify(PackData.ToString(), 188, conn);
 | 
				
			||||||
                PacketNumber += 2;
 | 
					                PacketNumber += 2;
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -310,7 +303,7 @@ namespace Connector_HTTP {
 | 
				
			||||||
              unsigned int toSend = PackData.AddStuffing(ToPack.bytes(184));
 | 
					              unsigned int toSend = PackData.AddStuffing(ToPack.bytes(184));
 | 
				
			||||||
              std::string gonnaSend = ToPack.remove(toSend);
 | 
					              std::string gonnaSend = ToPack.remove(toSend);
 | 
				
			||||||
              PackData.FillFree(gonnaSend);
 | 
					              PackData.FillFree(gonnaSend);
 | 
				
			||||||
              TSBuf.write(PackData.ToString(), 188);
 | 
					              HTTP_S.Chunkify(PackData.ToString(), 188, conn);
 | 
				
			||||||
              PacketNumber++;
 | 
					              PacketNumber++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              //rest of packets
 | 
					              //rest of packets
 | 
				
			||||||
| 
						 | 
					@ -321,7 +314,7 @@ namespace Connector_HTTP {
 | 
				
			||||||
                toSend = PackData.AddStuffing(ToPack.bytes(184));
 | 
					                toSend = PackData.AddStuffing(ToPack.bytes(184));
 | 
				
			||||||
                gonnaSend = ToPack.remove(toSend);
 | 
					                gonnaSend = ToPack.remove(toSend);
 | 
				
			||||||
                PackData.FillFree(gonnaSend);
 | 
					                PackData.FillFree(gonnaSend);
 | 
				
			||||||
                TSBuf.write(PackData.ToString(), 188);
 | 
					                HTTP_S.Chunkify(PackData.ToString(), 188, conn);
 | 
				
			||||||
                PacketNumber++;
 | 
					                PacketNumber++;
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -54,12 +54,7 @@ namespace Connector_HTTP {
 | 
				
			||||||
            std::cout << "Received request: " << HTTP_R.getUrl() << std::endl;
 | 
					            std::cout << "Received request: " << HTTP_R.getUrl() << std::endl;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
            conn.setHost(HTTP_R.GetHeader("X-Origin"));
 | 
					            conn.setHost(HTTP_R.GetHeader("X-Origin"));
 | 
				
			||||||
            //we assume the URL is the stream name with a 3 letter extension
 | 
					            streamname = HTTP_R.GetHeader("X-Stream");
 | 
				
			||||||
            streamname = HTTP_R.getUrl().substr(1);
 | 
					 | 
				
			||||||
            size_t extDot = streamname.rfind('.');
 | 
					 | 
				
			||||||
            if (extDot != std::string::npos){
 | 
					 | 
				
			||||||
              streamname.resize(extDot);
 | 
					 | 
				
			||||||
            }; //strip the extension
 | 
					 | 
				
			||||||
            int start = 0;
 | 
					            int start = 0;
 | 
				
			||||||
            if ( !HTTP_R.GetVar("start").empty()){
 | 
					            if ( !HTTP_R.GetVar("start").empty()){
 | 
				
			||||||
              start = atoi(HTTP_R.GetVar("start").c_str());
 | 
					              start = atoi(HTTP_R.GetVar("start").c_str());
 | 
				
			||||||
| 
						 | 
					@ -126,7 +121,9 @@ namespace Connector_HTTP {
 | 
				
			||||||
            byterate += Strm.getTrackById(audioID)["bps"].asInt();
 | 
					            byterate += Strm.getTrackById(audioID)["bps"].asInt();
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          if ( !byterate){byterate = 1;}
 | 
					          if ( !byterate){byterate = 1;}
 | 
				
			||||||
          seek_sec = (seek_byte / byterate) * 1000;
 | 
					          if (seek_byte){
 | 
				
			||||||
 | 
					            seek_sec = (seek_byte / byterate) * 1000;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
          std::stringstream cmd;
 | 
					          std::stringstream cmd;
 | 
				
			||||||
          cmd << "t";
 | 
					          cmd << "t";
 | 
				
			||||||
          if (videoID != -1){
 | 
					          if (videoID != -1){
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -52,12 +52,7 @@ namespace Connector_HTTP {
 | 
				
			||||||
            std::cout << "Received request: " << HTTP_R.getUrl() << std::endl;
 | 
					            std::cout << "Received request: " << HTTP_R.getUrl() << std::endl;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
            conn.setHost(HTTP_R.GetHeader("X-Origin"));
 | 
					            conn.setHost(HTTP_R.GetHeader("X-Origin"));
 | 
				
			||||||
            //we assume the URL is the stream name with a 3 letter extension
 | 
					            streamname = HTTP_R.GetHeader("X-Stream");
 | 
				
			||||||
            streamname = HTTP_R.getUrl().substr(1);
 | 
					 | 
				
			||||||
            size_t extDot = streamname.rfind('.');
 | 
					 | 
				
			||||||
            if (extDot != std::string::npos){
 | 
					 | 
				
			||||||
              streamname.resize(extDot);
 | 
					 | 
				
			||||||
            }; //strip the extension
 | 
					 | 
				
			||||||
            int start = 0;
 | 
					            int start = 0;
 | 
				
			||||||
            if ( !HTTP_R.GetVar("start").empty()){
 | 
					            if ( !HTTP_R.GetVar("start").empty()){
 | 
				
			||||||
              start = atoi(HTTP_R.GetVar("start").c_str());
 | 
					              start = atoi(HTTP_R.GetVar("start").c_str());
 | 
				
			||||||
| 
						 | 
					@ -121,7 +116,9 @@ namespace Connector_HTTP {
 | 
				
			||||||
            byterate += Strm.getTrackById(audioID)["bps"].asInt();
 | 
					            byterate += Strm.getTrackById(audioID)["bps"].asInt();
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          if ( !byterate){byterate = 1;}
 | 
					          if ( !byterate){byterate = 1;}
 | 
				
			||||||
          seek_sec = (seek_byte / byterate) * 1000;
 | 
					          if (seek_byte){
 | 
				
			||||||
 | 
					            seek_sec = (seek_byte / byterate) * 1000;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
          std::stringstream cmd;
 | 
					          std::stringstream cmd;
 | 
				
			||||||
          cmd << "t";
 | 
					          cmd << "t";
 | 
				
			||||||
          if (videoID != -1){
 | 
					          if (videoID != -1){
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,12 +60,7 @@ namespace Connector_HTTP {
 | 
				
			||||||
            std::cout << "Received request: " << HTTP_R.getUrl() << std::endl;
 | 
					            std::cout << "Received request: " << HTTP_R.getUrl() << std::endl;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
            conn.setHost(HTTP_R.GetHeader("X-Origin"));
 | 
					            conn.setHost(HTTP_R.GetHeader("X-Origin"));
 | 
				
			||||||
            //we assume the URL is the stream name with a 3 letter extension
 | 
					            streamname = HTTP_R.GetHeader("X-Stream");
 | 
				
			||||||
            streamname = HTTP_R.getUrl().substr(1);
 | 
					 | 
				
			||||||
            size_t extDot = streamname.rfind('.');
 | 
					 | 
				
			||||||
            if (extDot != std::string::npos){
 | 
					 | 
				
			||||||
              streamname.resize(extDot);
 | 
					 | 
				
			||||||
            }; //strip the extension
 | 
					 | 
				
			||||||
            int start = 0;
 | 
					            int start = 0;
 | 
				
			||||||
            if ( !HTTP_R.GetVar("start").empty()){
 | 
					            if ( !HTTP_R.GetVar("start").empty()){
 | 
				
			||||||
              start = atoi(HTTP_R.GetVar("start").c_str());
 | 
					              start = atoi(HTTP_R.GetVar("start").c_str());
 | 
				
			||||||
| 
						 | 
					@ -132,7 +127,9 @@ namespace Connector_HTTP {
 | 
				
			||||||
            byterate += Strm.getTrackById(audioID)["bps"].asInt();
 | 
					            byterate += Strm.getTrackById(audioID)["bps"].asInt();
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          if ( !byterate){byterate = 1;}
 | 
					          if ( !byterate){byterate = 1;}
 | 
				
			||||||
          seek_sec = (seek_byte / byterate) * 1000;
 | 
					          if (seek_byte){
 | 
				
			||||||
 | 
					            seek_sec = (seek_byte / byterate) * 1000;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
          std::stringstream cmd;
 | 
					          std::stringstream cmd;
 | 
				
			||||||
          cmd << "t";
 | 
					          cmd << "t";
 | 
				
			||||||
          if (videoID != -1){
 | 
					          if (videoID != -1){
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,10 +60,10 @@ namespace Connector_HTTP {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (oIt->second["type"].asString() == "video"){
 | 
					      if (oIt->second["type"].asString() == "video"){
 | 
				
			||||||
        allVideo[oIt->first] = oIt->second;
 | 
					        allVideo[oIt->first] = oIt->second;
 | 
				
			||||||
        if (oIt->second["width"].asInt() > maxWidth){ maxWidth = oIt->second["width"].asInt(); }
 | 
					        if (oIt->second["width"].asInt() > maxWidth){maxWidth = oIt->second["width"].asInt();}
 | 
				
			||||||
        if (oIt->second["width"].asInt() < minWidth){ minWidth = oIt->second["width"].asInt(); }
 | 
					        if (oIt->second["width"].asInt() < minWidth){minWidth = oIt->second["width"].asInt();}
 | 
				
			||||||
        if (oIt->second["height"].asInt() > maxHeight){ maxHeight = oIt->second["height"].asInt(); }
 | 
					        if (oIt->second["height"].asInt() > maxHeight){maxHeight = oIt->second["height"].asInt();}
 | 
				
			||||||
        if (oIt->second["height"].asInt() < minHeight){ minHeight = oIt->second["height"].asInt(); }
 | 
					        if (oIt->second["height"].asInt() < minHeight){minHeight = oIt->second["height"].asInt();}
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -164,6 +164,7 @@ namespace Connector_HTTP {
 | 
				
			||||||
    bool ready4data = false;//Set to true when streaming is to begin.
 | 
					    bool ready4data = false;//Set to true when streaming is to begin.
 | 
				
			||||||
    Socket::Connection ss( -1);//The Stream Socket, used to connect to the desired stream.
 | 
					    Socket::Connection ss( -1);//The Stream Socket, used to connect to the desired stream.
 | 
				
			||||||
    std::string streamname;//Will contain the name of the stream.
 | 
					    std::string streamname;//Will contain the name of the stream.
 | 
				
			||||||
 | 
					    bool handlingRequest = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool wantsVideo = false;//Indicates whether this request is a video request.
 | 
					    bool wantsVideo = false;//Indicates whether this request is a video request.
 | 
				
			||||||
    bool wantsAudio = false;//Indicates whether this request is an audio request.
 | 
					    bool wantsAudio = false;//Indicates whether this request is an audio request.
 | 
				
			||||||
| 
						 | 
					@ -178,257 +179,253 @@ namespace Connector_HTTP {
 | 
				
			||||||
    JSON::Value allVideo;
 | 
					    JSON::Value allVideo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (conn.connected()){
 | 
					    while (conn.connected()){
 | 
				
			||||||
      if (conn.spool() || conn.Received().size()){
 | 
					      if ( !handlingRequest){
 | 
				
			||||||
        if (HTTP_R.Read(conn)){
 | 
					        if (conn.spool() || conn.Received().size()){
 | 
				
			||||||
#if DEBUG >= 5
 | 
					          if (HTTP_R.Read(conn)){
 | 
				
			||||||
          std::cout << "Received request: " << HTTP_R.getUrl() << std::endl;
 | 
					  #if DEBUG >= 5
 | 
				
			||||||
#endif
 | 
					            std::cout << "Received request: " << HTTP_R.getUrl() << std::endl;
 | 
				
			||||||
          //Get data set by the proxy.
 | 
					  #endif
 | 
				
			||||||
          conn.setHost(HTTP_R.GetHeader("X-Origin"));
 | 
					            //Get data set by the proxy.
 | 
				
			||||||
          streamname = HTTP_R.GetHeader("X-Stream");
 | 
					            conn.setHost(HTTP_R.GetHeader("X-Origin"));
 | 
				
			||||||
          if ( !ss){
 | 
					            streamname = HTTP_R.GetHeader("X-Stream");
 | 
				
			||||||
            //initiate Stream Socket
 | 
					            if ( !ss){
 | 
				
			||||||
            ss = Util::Stream::getStream(streamname);
 | 
					              //initiate Stream Socket
 | 
				
			||||||
            if ( !ss.connected()){
 | 
					              ss = Util::Stream::getStream(streamname);
 | 
				
			||||||
              #if DEBUG >= 1
 | 
					              if ( !ss.connected()){
 | 
				
			||||||
              fprintf(stderr, "Could not connect to server!\n");
 | 
					                #if DEBUG >= 1
 | 
				
			||||||
              #endif
 | 
					                fprintf(stderr, "Could not connect to server!\n");
 | 
				
			||||||
              HTTP_S.Clean();
 | 
					                #endif
 | 
				
			||||||
              HTTP_S.SetBody("No such stream is available on the system. Please try again.\n");
 | 
					                HTTP_S.Clean();
 | 
				
			||||||
              conn.SendNow(HTTP_S.BuildResponse("404", "Not found"));
 | 
					                HTTP_S.SetBody("No such stream is available on the system. Please try again.\n");
 | 
				
			||||||
              ready4data = false;
 | 
					                conn.SendNow(HTTP_S.BuildResponse("404", "Not found"));
 | 
				
			||||||
              continue;
 | 
					                ready4data = false;
 | 
				
			||||||
            }
 | 
					                continue;
 | 
				
			||||||
            ss.setBlocking(false);
 | 
					              }
 | 
				
			||||||
            //Do nothing until metadata has been received.
 | 
					              ss.setBlocking(false);
 | 
				
			||||||
            while ( !Strm.metadata && ss.connected()){
 | 
					              //Do nothing until metadata has been received.
 | 
				
			||||||
              if (ss.spool()){
 | 
					              while ( !Strm.metadata && ss.connected()){
 | 
				
			||||||
                while (Strm.parsePacket(ss.Received())){
 | 
					                if (ss.spool()){
 | 
				
			||||||
                  //do nothing
 | 
					                  while (Strm.parsePacket(ss.Received())){
 | 
				
			||||||
 | 
					                    //do nothing
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            }
 | 
					              for (JSON::ObjIter oIt = Strm.metadata["tracks"].ObjBegin(); oIt != Strm.metadata["tracks"].ObjEnd(); oIt++){
 | 
				
			||||||
            for (JSON::ObjIter oIt = Strm.metadata["tracks"].ObjBegin(); oIt != Strm.metadata["tracks"].ObjEnd(); oIt++){
 | 
					                if (oIt->second["type"].asString() == "audio"){
 | 
				
			||||||
              if (oIt->second["type"].asString() == "audio"){
 | 
					                  allAudio[oIt->first] = oIt->second;
 | 
				
			||||||
                allAudio[oIt->first] = oIt->second;
 | 
					                }
 | 
				
			||||||
 | 
					                if (oIt->second["type"].asString() == "video"){
 | 
				
			||||||
 | 
					                  allVideo[oIt->first] = oIt->second;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
              if (oIt->second["type"].asString() == "video"){
 | 
					            };
 | 
				
			||||||
                allVideo[oIt->first] = oIt->second;
 | 
					      
 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          };
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if (HTTP_R.url.find("Manifest") == std::string::npos){
 | 
					            if (HTTP_R.url.find("Manifest") == std::string::npos){
 | 
				
			||||||
            //We have a non-manifest request, parse it.
 | 
					              //We have a non-manifest request, parse it.
 | 
				
			||||||
            Quality = HTTP_R.url.substr(HTTP_R.url.find("/Q(", 8) + 3);
 | 
					              Quality = HTTP_R.url.substr(HTTP_R.url.find("/Q(", 8) + 3);
 | 
				
			||||||
            Quality = Quality.substr(0, Quality.find(")"));
 | 
					              Quality = Quality.substr(0, Quality.find(")"));
 | 
				
			||||||
            parseString = HTTP_R.url.substr(HTTP_R.url.find(")/") + 2);
 | 
					              parseString = HTTP_R.url.substr(HTTP_R.url.find(")/") + 2);
 | 
				
			||||||
            wantsAudio = false;
 | 
					              wantsAudio = false;
 | 
				
			||||||
            wantsVideo = false;
 | 
					              wantsVideo = false;
 | 
				
			||||||
            if (parseString[0] == 'A'){
 | 
					              if (parseString[0] == 'A'){
 | 
				
			||||||
              wantsAudio = true;
 | 
					                wantsAudio = true;
 | 
				
			||||||
            }
 | 
					              }
 | 
				
			||||||
            if (parseString[0] == 'V'){
 | 
					              if (parseString[0] == 'V'){
 | 
				
			||||||
              wantsVideo = true;
 | 
					                wantsVideo = true;
 | 
				
			||||||
            }
 | 
					              }
 | 
				
			||||||
            parseString = parseString.substr(parseString.find("(") + 1);
 | 
					              parseString = parseString.substr(parseString.find("(") + 1);
 | 
				
			||||||
            requestedTime = atoll(parseString.substr(0, parseString.find(")")).c_str());
 | 
					              requestedTime = atoll(parseString.substr(0, parseString.find(")")).c_str());
 | 
				
			||||||
            if (Strm.metadata.isMember("live")){
 | 
					              if (Strm.metadata.isMember("live")){
 | 
				
			||||||
              ///\todo Fix this for live stuff
 | 
					                ///\todo Fix this for live stuff
 | 
				
			||||||
              int seekable = Strm.canSeekms(requestedTime / 10000);
 | 
					                int seekable = Strm.canSeekms(requestedTime / 10000);
 | 
				
			||||||
              if (seekable == 0){
 | 
					                if (seekable == 0){
 | 
				
			||||||
                // iff the fragment in question is available, check if the next is available too
 | 
					                  // iff the fragment in question is available, check if the next is available too
 | 
				
			||||||
                for (int i = 0; i < Strm.metadata["keytime"].size(); i++){
 | 
					                  for (int i = 0; i < Strm.metadata["keytime"].size(); i++){
 | 
				
			||||||
                  if (Strm.metadata["keytime"][i].asInt() >= (requestedTime / 10000)){
 | 
					                    if (Strm.metadata["keytime"][i].asInt() >= (requestedTime / 10000)){
 | 
				
			||||||
                    if (i + 1 == Strm.metadata["keytime"].size()){
 | 
					                      if (i + 1 == Strm.metadata["keytime"].size()){
 | 
				
			||||||
                      seekable = 1;
 | 
					                        seekable = 1;
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					                      break;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (seekable < 0){
 | 
				
			||||||
 | 
					                  HTTP_S.Clean();
 | 
				
			||||||
 | 
					                  HTTP_S.SetBody("The requested fragment is no longer kept in memory on the server and cannot be served.\n");
 | 
				
			||||||
 | 
					                  conn.SendNow(HTTP_S.BuildResponse("412", "Fragment out of range"));
 | 
				
			||||||
 | 
					                  HTTP_R.Clean(); //clean for any possible next requests
 | 
				
			||||||
 | 
					                  std::cout << "Fragment @ " << requestedTime / 10000 << "ms too old (" << Strm.metadata["keytime"][0u].asInt() << " - " << Strm.metadata["keytime"][Strm.metadata["keytime"].size() - 1].asInt() << " ms)" << std::endl;
 | 
				
			||||||
 | 
					                  continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (seekable > 0){
 | 
				
			||||||
 | 
					                  HTTP_S.Clean();
 | 
				
			||||||
 | 
					                  HTTP_S.SetBody("Proxy, re-request this in a second or two.\n");
 | 
				
			||||||
 | 
					                  conn.SendNow(HTTP_S.BuildResponse("208", "Ask again later"));
 | 
				
			||||||
 | 
					                  HTTP_R.Clean(); //clean for any possible next requests
 | 
				
			||||||
 | 
					                  std::cout << "Fragment @ " << requestedTime / 10000 << "ms not available yet (" << Strm.metadata["keytime"][0u].asInt() << " - " << Strm.metadata["keytime"][Strm.metadata["keytime"].size() - 1].asInt() << " ms)" << std::endl;
 | 
				
			||||||
 | 
					                  continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              //Seek to the right place and send a play-once for a single fragment.
 | 
				
			||||||
 | 
					              std::stringstream sstream;
 | 
				
			||||||
 | 
					              JSON::Value myRef;
 | 
				
			||||||
 | 
					              long long int selectedQuality = atoll(Quality.c_str()) / 8;
 | 
				
			||||||
 | 
					              if (wantsVideo){
 | 
				
			||||||
 | 
					                //Select the correct track ID
 | 
				
			||||||
 | 
					                for (JSON::ObjIter vIt = allVideo.ObjBegin(); vIt != allVideo.ObjEnd(); vIt++){
 | 
				
			||||||
 | 
					                  if (vIt->second["bps"].asInt() == selectedQuality){
 | 
				
			||||||
 | 
					                    myRef = vIt->second;
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              if (wantsAudio){
 | 
				
			||||||
 | 
					                //Select the correct track ID
 | 
				
			||||||
 | 
					                for (JSON::ObjIter aIt = allAudio.ObjBegin(); aIt != allAudio.ObjEnd(); aIt++){
 | 
				
			||||||
 | 
					                  if (aIt->second["bps"].asInt() == selectedQuality){
 | 
				
			||||||
 | 
					                    myRef = aIt->second;
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              
 | 
				
			||||||
 | 
					              long long mstime = 0;
 | 
				
			||||||
 | 
					              long long mslen = 0;
 | 
				
			||||||
 | 
					              if (myRef.isMember("keys")){
 | 
				
			||||||
 | 
					                for (JSON::ArrIter it = myRef["keys"].ArrBegin(); it != myRef["keys"].ArrEnd(); it++){
 | 
				
			||||||
 | 
					                  if ((*it)["time"].asInt() >= (requestedTime / 10000)){
 | 
				
			||||||
 | 
					                    mstime = (*it)["time"].asInt();
 | 
				
			||||||
 | 
					                    mslen = (*it)["len"].asInt();
 | 
				
			||||||
 | 
					                    if (Strm.metadata.isMember("live")){
 | 
				
			||||||
 | 
					                      if (it == myRef["keys"].ArrEnd() - 2){
 | 
				
			||||||
 | 
					                        HTTP_S.Clean();
 | 
				
			||||||
 | 
					                        HTTP_S.SetBody("Proxy, re-request this in a second or two.\n");
 | 
				
			||||||
 | 
					                        conn.SendNow(HTTP_S.BuildResponse("208", "Ask again later"));
 | 
				
			||||||
 | 
					                        HTTP_R.Clean(); //clean for any possible next requests
 | 
				
			||||||
 | 
					                        std::cout << "Fragment after fragment @ " << (requestedTime / 10000) << " not available yet" << std::endl;
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                  }
 | 
					                  }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
              if (seekable < 0){
 | 
					              if (HTTP_R.url == "/"){continue;}//Don't continue, but continue instead.
 | 
				
			||||||
                HTTP_S.Clean();
 | 
					              if (Strm.metadata.isMember("live")){
 | 
				
			||||||
                HTTP_S.SetBody("The requested fragment is no longer kept in memory on the server and cannot be served.\n");
 | 
					                if (mstime == 0 && (requestedTime / 10000) > 1){
 | 
				
			||||||
                conn.SendNow(HTTP_S.BuildResponse("412", "Fragment out of range"));
 | 
					                  HTTP_S.Clean();
 | 
				
			||||||
                HTTP_R.Clean(); //clean for any possible next requests
 | 
					                  HTTP_S.SetBody("The requested fragment is no longer kept in memory on the server and cannot be served.\n");
 | 
				
			||||||
                std::cout << "Fragment @ " << requestedTime / 10000 << "ms too old (" << Strm.metadata["keytime"][0u].asInt() << " - " << Strm.metadata["keytime"][Strm.metadata["keytime"].size() - 1].asInt() << " ms)" << std::endl;
 | 
					                  conn.SendNow(HTTP_S.BuildResponse("412", "Fragment out of range"));
 | 
				
			||||||
                continue;
 | 
					                  HTTP_R.Clean(); //clean for any possible next requests
 | 
				
			||||||
              }
 | 
					                  std::cout << "Fragment @ " << (requestedTime / 10000) << " too old" << std::endl;
 | 
				
			||||||
              if (seekable > 0){
 | 
					                  continue;
 | 
				
			||||||
                HTTP_S.Clean();
 | 
					 | 
				
			||||||
                HTTP_S.SetBody("Proxy, re-request this in a second or two.\n");
 | 
					 | 
				
			||||||
                conn.SendNow(HTTP_S.BuildResponse("208", "Ask again later"));
 | 
					 | 
				
			||||||
                HTTP_R.Clean(); //clean for any possible next requests
 | 
					 | 
				
			||||||
                std::cout << "Fragment @ " << requestedTime / 10000 << "ms not available yet (" << Strm.metadata["keytime"][0u].asInt() << " - " << Strm.metadata["keytime"][Strm.metadata["keytime"].size() - 1].asInt() << " ms)" << std::endl;
 | 
					 | 
				
			||||||
                continue;
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            //Seek to the right place and send a play-once for a single fragment.
 | 
					 | 
				
			||||||
            std::stringstream sstream;
 | 
					 | 
				
			||||||
            JSON::Value myRef;
 | 
					 | 
				
			||||||
            long long int selectedQuality = atoll(Quality.c_str()) / 8;
 | 
					 | 
				
			||||||
            if (wantsVideo){
 | 
					 | 
				
			||||||
              //Select the correct track ID
 | 
					 | 
				
			||||||
              for (JSON::ObjIter vIt = allVideo.ObjBegin(); vIt != allVideo.ObjEnd(); vIt++){
 | 
					 | 
				
			||||||
                if (vIt->second["bps"].asInt() == selectedQuality){
 | 
					 | 
				
			||||||
                  myRef = vIt->second;
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            }
 | 
					              
 | 
				
			||||||
            if (wantsAudio){
 | 
					              
 | 
				
			||||||
              //Select the correct track ID
 | 
					              sstream << "t " << myRef["trackid"].asInt() << "\n";
 | 
				
			||||||
              for (JSON::ObjIter aIt = allAudio.ObjBegin(); aIt != allAudio.ObjEnd(); aIt++){
 | 
					              sstream << "s " << (requestedTime / 10000) << "\np " << (mstime + mslen) <<"\n";
 | 
				
			||||||
                if (aIt->second["bps"].asInt() == selectedQuality){
 | 
					              ss.SendNow(sstream.str().c_str());
 | 
				
			||||||
                  myRef = aIt->second;
 | 
					
 | 
				
			||||||
                }
 | 
					              unsigned int myDuration;
 | 
				
			||||||
 | 
					              
 | 
				
			||||||
 | 
					              //Wrap everything in mp4 boxes
 | 
				
			||||||
 | 
					              MP4::MFHD mfhd_box;
 | 
				
			||||||
 | 
					              JSON::Value trackRef;
 | 
				
			||||||
 | 
					              if (wantsVideo){
 | 
				
			||||||
 | 
					                trackRef = allVideo.ObjBegin()->second;
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            }
 | 
					              if (wantsAudio){
 | 
				
			||||||
            
 | 
					                trackRef = allAudio.ObjBegin()->second;
 | 
				
			||||||
            long long mstime = 0;
 | 
					              }
 | 
				
			||||||
            long long mslen = 0;
 | 
					              //Also obtain the associated keyframe;
 | 
				
			||||||
            if (myRef.isMember("keys")){
 | 
					              JSON::Value keyObj;
 | 
				
			||||||
              for (JSON::ArrIter it = myRef["keys"].ArrBegin(); it != myRef["keys"].ArrEnd(); it++){
 | 
					              for (JSON::ArrIter keyIt = trackRef["keys"].ArrBegin(); keyIt != trackRef["keys"].ArrEnd(); keyIt++){
 | 
				
			||||||
                if ((*it)["time"].asInt() >= (requestedTime / 10000)){
 | 
					                if ((*keyIt)["time"].asInt() >= (requestedTime / 10000)){
 | 
				
			||||||
                  mstime = (*it)["time"].asInt();
 | 
					                  keyObj = (*keyIt);
 | 
				
			||||||
                  mslen = (*it)["len"].asInt();
 | 
					                  mfhd_box.setSequenceNumber((*keyIt)["num"].asInt());
 | 
				
			||||||
                  if (Strm.metadata.isMember("live")){
 | 
					                  myDuration = (*keyIt)["len"].asInt() * 10000;
 | 
				
			||||||
                    if (it == myRef["keys"].ArrEnd() - 2){
 | 
					 | 
				
			||||||
                      HTTP_S.Clean();
 | 
					 | 
				
			||||||
                      HTTP_S.SetBody("Proxy, re-request this in a second or two.\n");
 | 
					 | 
				
			||||||
                      conn.SendNow(HTTP_S.BuildResponse("208", "Ask again later"));
 | 
					 | 
				
			||||||
                      HTTP_R.Clean(); //clean for any possible next requests
 | 
					 | 
				
			||||||
                      std::cout << "Fragment after fragment @ " << (requestedTime / 10000) << " not available yet" << std::endl;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                  }
 | 
					 | 
				
			||||||
                  break;
 | 
					                  break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            }
 | 
					              
 | 
				
			||||||
            if (HTTP_R.url == "/"){continue;}//Don't continue, but continue instead.
 | 
					              MP4::TFHD tfhd_box;
 | 
				
			||||||
            if (Strm.metadata.isMember("live")){
 | 
					              tfhd_box.setFlags(MP4::tfhdSampleFlag);
 | 
				
			||||||
              if (mstime == 0 && (requestedTime / 10000) > 1){
 | 
					              tfhd_box.setTrackID(1);
 | 
				
			||||||
                HTTP_S.Clean();
 | 
					              tfhd_box.setDefaultSampleFlags(0x000000C0 | MP4::noIPicture | MP4::noDisposable | MP4::noKeySample);
 | 
				
			||||||
                HTTP_S.SetBody("The requested fragment is no longer kept in memory on the server and cannot be served.\n");
 | 
					              
 | 
				
			||||||
                conn.SendNow(HTTP_S.BuildResponse("412", "Fragment out of range"));
 | 
					              MP4::TRUN trun_box;
 | 
				
			||||||
                HTTP_R.Clean(); //clean for any possible next requests
 | 
					              trun_box.setFlags(MP4::trundataOffset | MP4::trunfirstSampleFlags | MP4::trunsampleDuration | MP4::trunsampleSize);
 | 
				
			||||||
                std::cout << "Fragment @ " << (requestedTime / 10000) << " too old" << std::endl;
 | 
					              trun_box.setDataOffset(42);
 | 
				
			||||||
                continue;
 | 
					              trun_box.setFirstSampleFlags(0x00000040 | MP4::isIPicture | MP4::noDisposable | MP4::isKeySample);
 | 
				
			||||||
 | 
					              for (int i = 0; i < keyObj["parts"].size(); i++){
 | 
				
			||||||
 | 
					                MP4::trunSampleInformation trunSample;
 | 
				
			||||||
 | 
					                trunSample.sampleSize = keyObj["parts"][i].asInt();
 | 
				
			||||||
 | 
					                //Guesstimate sample duration.
 | 
				
			||||||
 | 
					                trunSample.sampleDuration = ((double)(keyObj["len"].asInt() * 10000) / keyObj["parts"].size());
 | 
				
			||||||
 | 
					                trun_box.setSampleInformation(trunSample, i);
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            }
 | 
					              
 | 
				
			||||||
            
 | 
					              MP4::SDTP sdtp_box;
 | 
				
			||||||
            
 | 
					              sdtp_box.setVersion(0);
 | 
				
			||||||
            sstream << "t " << myRef["trackid"].asInt() << "\n";
 | 
					              sdtp_box.setValue(0x24, 4);
 | 
				
			||||||
            sstream << "s " << (requestedTime / 10000) << "\np " << (mstime + mslen) <<"\n";
 | 
					              for (int i = 1; i < keyObj["parts"].size(); i++){
 | 
				
			||||||
            ss.SendNow(sstream.str().c_str());
 | 
					                sdtp_box.setValue(0x14, 4 + i);
 | 
				
			||||||
 | 
					 | 
				
			||||||
            HTTP_S.Clean();
 | 
					 | 
				
			||||||
            HTTP_S.SetHeader("Content-Type", "video/mp4");
 | 
					 | 
				
			||||||
            HTTP_S.SetBody("");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            unsigned int myDuration;
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            //Wrap everything in mp4 boxes
 | 
					 | 
				
			||||||
            MP4::MFHD mfhd_box;
 | 
					 | 
				
			||||||
            JSON::Value trackRef;
 | 
					 | 
				
			||||||
            if (wantsVideo){
 | 
					 | 
				
			||||||
              trackRef = allVideo.ObjBegin()->second;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (wantsAudio){
 | 
					 | 
				
			||||||
              trackRef = allAudio.ObjBegin()->second;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            //Also obtain the associated keyframe;
 | 
					 | 
				
			||||||
            JSON::Value keyObj;
 | 
					 | 
				
			||||||
            for (JSON::ArrIter keyIt = trackRef["keys"].ArrBegin(); keyIt != trackRef["keys"].ArrEnd(); keyIt++){
 | 
					 | 
				
			||||||
              if ((*keyIt)["time"].asInt() >= (requestedTime / 10000)){
 | 
					 | 
				
			||||||
                keyObj = (*keyIt);
 | 
					 | 
				
			||||||
                mfhd_box.setSequenceNumber((*keyIt)["num"].asInt());
 | 
					 | 
				
			||||||
                myDuration = (*keyIt)["len"].asInt() * 10000;
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            }
 | 
					              
 | 
				
			||||||
            
 | 
					              MP4::TRAF traf_box;
 | 
				
			||||||
            MP4::TFHD tfhd_box;
 | 
					              traf_box.setContent(tfhd_box, 0);
 | 
				
			||||||
            tfhd_box.setFlags(MP4::tfhdSampleFlag);
 | 
					              traf_box.setContent(trun_box, 1);
 | 
				
			||||||
            tfhd_box.setTrackID(1);
 | 
					              traf_box.setContent(sdtp_box, 2);
 | 
				
			||||||
            tfhd_box.setDefaultSampleFlags(0x000000C0 | MP4::noIPicture | MP4::noDisposable | MP4::noKeySample);
 | 
					              
 | 
				
			||||||
            
 | 
					              //If the stream is live, we want to have a fragref box if possible
 | 
				
			||||||
            MP4::TRUN trun_box;
 | 
					              if (Strm.metadata.isMember("live")){
 | 
				
			||||||
            trun_box.setFlags(MP4::trundataOffset | MP4::trunfirstSampleFlags | MP4::trunsampleDuration | MP4::trunsampleSize);
 | 
					                ///\todo Fix this for live
 | 
				
			||||||
            trun_box.setDataOffset(42);
 | 
					                MP4::UUID_TrackFragmentReference fragref_box;
 | 
				
			||||||
            trun_box.setFirstSampleFlags(0x00000040 | MP4::isIPicture | MP4::noDisposable | MP4::isKeySample);
 | 
					                fragref_box.setVersion(1);
 | 
				
			||||||
            for (int i = 0; i < keyObj["parts"].size(); i++){
 | 
					                fragref_box.setFragmentCount(0);
 | 
				
			||||||
              MP4::trunSampleInformation trunSample;
 | 
					                int fragCount = 0;
 | 
				
			||||||
              trunSample.sampleSize = keyObj["parts"][i].asInt();
 | 
					                for (int i = 0; i < Strm.metadata["keytime"].size(); i++){
 | 
				
			||||||
              //Guesstimate sample duration.
 | 
					                  if (Strm.metadata["keytime"][i].asInt() > (requestedTime / 10000)){
 | 
				
			||||||
              trunSample.sampleDuration = ((double)(keyObj["len"].asInt() * 10000) / keyObj["parts"].size());
 | 
					                    fragref_box.setTime(fragCount, Strm.metadata["keytime"][i].asInt() * 10000);
 | 
				
			||||||
              trun_box.setSampleInformation(trunSample, i);
 | 
					                    fragref_box.setDuration(fragCount, Strm.metadata["keylen"][i].asInt() * 10000);
 | 
				
			||||||
            }
 | 
					                    fragref_box.setFragmentCount(++fragCount);
 | 
				
			||||||
            
 | 
					                  }
 | 
				
			||||||
            MP4::SDTP sdtp_box;
 | 
					 | 
				
			||||||
            sdtp_box.setVersion(0);
 | 
					 | 
				
			||||||
            sdtp_box.setValue(0x24, 4);
 | 
					 | 
				
			||||||
            for (int i = 1; i < keyObj["parts"].size(); i++){
 | 
					 | 
				
			||||||
              sdtp_box.setValue(0x14, 4 + i);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            MP4::TRAF traf_box;
 | 
					 | 
				
			||||||
            traf_box.setContent(tfhd_box, 0);
 | 
					 | 
				
			||||||
            traf_box.setContent(trun_box, 1);
 | 
					 | 
				
			||||||
            traf_box.setContent(sdtp_box, 2);
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            //If the stream is live, we want to have a fragref box if possible
 | 
					 | 
				
			||||||
            if (Strm.metadata.isMember("live")){
 | 
					 | 
				
			||||||
              ///\todo Fix this for live
 | 
					 | 
				
			||||||
              MP4::UUID_TrackFragmentReference fragref_box;
 | 
					 | 
				
			||||||
              fragref_box.setVersion(1);
 | 
					 | 
				
			||||||
              fragref_box.setFragmentCount(0);
 | 
					 | 
				
			||||||
              int fragCount = 0;
 | 
					 | 
				
			||||||
              for (int i = 0; i < Strm.metadata["keytime"].size(); i++){
 | 
					 | 
				
			||||||
                if (Strm.metadata["keytime"][i].asInt() > (requestedTime / 10000)){
 | 
					 | 
				
			||||||
                  fragref_box.setTime(fragCount, Strm.metadata["keytime"][i].asInt() * 10000);
 | 
					 | 
				
			||||||
                  fragref_box.setDuration(fragCount, Strm.metadata["keylen"][i].asInt() * 10000);
 | 
					 | 
				
			||||||
                  fragref_box.setFragmentCount(++fragCount);
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					                traf_box.setContent(fragref_box, 3);
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
              traf_box.setContent(fragref_box, 3);
 | 
					
 | 
				
			||||||
 | 
					              MP4::MOOF moof_box;
 | 
				
			||||||
 | 
					              moof_box.setContent(mfhd_box, 0);
 | 
				
			||||||
 | 
					              moof_box.setContent(traf_box, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              //Setting the correct offsets.
 | 
				
			||||||
 | 
					              trun_box.setDataOffset(moof_box.boxedSize() + 8);
 | 
				
			||||||
 | 
					              traf_box.setContent(trun_box, 1);
 | 
				
			||||||
 | 
					              moof_box.setContent(traf_box, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              HTTP_S.Clean();
 | 
				
			||||||
 | 
					              HTTP_S.SetHeader("Content-Type", "video/mp4");
 | 
				
			||||||
 | 
					              HTTP_S.StartResponse(HTTP_R, conn);
 | 
				
			||||||
 | 
					              HTTP_S.Chunkify(moof_box.asBox(), moof_box.boxedSize(), conn);
 | 
				
			||||||
 | 
					              HTTP_S.Chunkify("\000\000\000\000mdat", 8, conn);
 | 
				
			||||||
 | 
					              handlingRequest = true;
 | 
				
			||||||
 | 
					            }else{
 | 
				
			||||||
 | 
					              //We have a request for a Manifest, generate and send it.
 | 
				
			||||||
 | 
					              HTTP_S.Clean();
 | 
				
			||||||
 | 
					              HTTP_S.SetHeader("Content-Type", "text/xml");
 | 
				
			||||||
 | 
					              HTTP_S.SetHeader("Cache-Control", "no-cache");
 | 
				
			||||||
 | 
					              std::string manifest = smoothIndex(Strm.metadata);
 | 
				
			||||||
 | 
					              HTTP_S.SetBody(manifest);
 | 
				
			||||||
 | 
					              conn.SendNow(HTTP_S.BuildResponse("200", "OK"));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            ready4data = true;
 | 
				
			||||||
            MP4::MOOF moof_box;
 | 
					            //Clean for any possible next requests
 | 
				
			||||||
            moof_box.setContent(mfhd_box, 0);
 | 
					            HTTP_R.Clean();
 | 
				
			||||||
            moof_box.setContent(traf_box, 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            //Setting the correct offsets.
 | 
					 | 
				
			||||||
            trun_box.setDataOffset(moof_box.boxedSize() + 8);
 | 
					 | 
				
			||||||
            traf_box.setContent(trun_box, 1);
 | 
					 | 
				
			||||||
            moof_box.setContent(traf_box, 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            //Send the complete message
 | 
					 | 
				
			||||||
            HTTP_S.SetHeader("Content-Length", keyObj["size"].asInt() + 8 + moof_box.boxedSize());
 | 
					 | 
				
			||||||
            conn.SendNow(HTTP_S.BuildResponse("200", "OK"));
 | 
					 | 
				
			||||||
            conn.SendNow(moof_box.asBox(), moof_box.boxedSize());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            unsigned long size = htonl(keyObj["size"].asInt() + 8);
 | 
					 | 
				
			||||||
            conn.SendNow((char*) &size, 4);
 | 
					 | 
				
			||||||
            conn.SendNow("mdat", 4);
 | 
					 | 
				
			||||||
          }else{
 | 
					 | 
				
			||||||
            //We have a request for a Manifest, generate and send it.
 | 
					 | 
				
			||||||
            HTTP_S.Clean();
 | 
					 | 
				
			||||||
            HTTP_S.SetHeader("Content-Type", "text/xml");
 | 
					 | 
				
			||||||
            HTTP_S.SetHeader("Cache-Control", "no-cache");
 | 
					 | 
				
			||||||
            std::string manifest = smoothIndex(Strm.metadata);
 | 
					 | 
				
			||||||
            HTTP_S.SetBody(manifest);
 | 
					 | 
				
			||||||
            conn.SendNow(HTTP_S.BuildResponse("200", "OK"));
 | 
					 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          ready4data = true;
 | 
					        }else{
 | 
				
			||||||
          //Clean for any possible next requests
 | 
					          //Wait 250ms before checking for new data.
 | 
				
			||||||
          HTTP_R.Clean();
 | 
					          Util::sleep(250);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }else{
 | 
					 | 
				
			||||||
        //Wait 1 second before checking for new data.
 | 
					 | 
				
			||||||
        Util::sleep(1);
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (ready4data){
 | 
					      if (ready4data){
 | 
				
			||||||
        unsigned int now = Util::epoch();
 | 
					        unsigned int now = Util::epoch();
 | 
				
			||||||
| 
						 | 
					@ -437,12 +434,14 @@ namespace Connector_HTTP {
 | 
				
			||||||
          lastStats = now;
 | 
					          lastStats = now;
 | 
				
			||||||
          ss.SendNow(conn.getStats("HTTP_Smooth").c_str());
 | 
					          ss.SendNow(conn.getStats("HTTP_Smooth").c_str());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (ss.spool()){
 | 
					        if (handlingRequest && ss.spool()){
 | 
				
			||||||
          while (Strm.parsePacket(ss.Received())){
 | 
					          while (Strm.parsePacket(ss.Received())){
 | 
				
			||||||
            if (Strm.lastType() == DTSC::AUDIO || Strm.lastType() == DTSC::VIDEO){
 | 
					            if (Strm.lastType() == DTSC::AUDIO || Strm.lastType() == DTSC::VIDEO){
 | 
				
			||||||
              //Select only the data that the client has requested.
 | 
					              HTTP_S.Chunkify(Strm.lastData(), conn);
 | 
				
			||||||
              int tmp = Util::getMS();
 | 
					            }
 | 
				
			||||||
              conn.SendNow(Strm.lastData());
 | 
					            if (Strm.lastType() == DTSC::PAUSEMARK){
 | 
				
			||||||
 | 
					              HTTP_S.Chunkify("", 0, conn);
 | 
				
			||||||
 | 
					              handlingRequest = false;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue