diff --git a/src/connectors/conn_http.cpp b/src/connectors/conn_http.cpp index 87ccdb77..e6d5ba25 100644 --- a/src/connectors/conn_http.cpp +++ b/src/connectors/conn_http.cpp @@ -403,18 +403,14 @@ namespace Connector_HTTP { }else{ long long int ret = Util::getMS(); //success, check type of response - std::cout << "Response headers for " << orig_url << " received..."; if (H.GetHeader("Content-Length") != "" || H.GetHeader("Transfer-Encoding") == "chunked"){ //known length - simply re-send the request with added headers and continue H.SetHeader("X-UID", uid); H.SetHeader("Server", "mistserver/" PACKAGE_VERSION "/" + Util::Config::libver); H.body = ""; - std::cout << "proxying..." << std::endl; H.Proxy(*(myCConn->conn), *conn); - std::cout << "Proxying " << orig_url << " completed!" << std::endl; myCConn->inUse.unlock(); }else{ - std::cout << "progressin'..." << std::endl; //unknown length H.SetHeader("X-UID", uid); H.SetHeader("Server", "mistserver/" PACKAGE_VERSION "/" + Util::Config::libver); diff --git a/src/connectors/conn_http_dynamic.cpp b/src/connectors/conn_http_dynamic.cpp index 87149ba2..9c930172 100644 --- a/src/connectors/conn_http_dynamic.cpp +++ b/src/connectors/conn_http_dynamic.cpp @@ -150,7 +150,7 @@ namespace Connector_HTTP { Socket::Connection ss( -1); std::string streamname; - std::string recBuffer = ""; + bool handlingRequest = false; int Quality = 0; int Segment = -1; @@ -161,124 +161,125 @@ namespace Connector_HTTP { conn.setBlocking(false); //do not block on conn.spool() when no data is available while (conn.connected()){ - if (conn.spool() || conn.Received().size()){ - if (HTTP_R.Read(conn)){ - #if DEBUG >= 5 - 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 ( !handlingRequest){ + if (conn.spool() || conn.Received().size()){ + if (HTTP_R.Read(conn)){ #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 - 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"); - 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){ + 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("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 " << ReqFragment << " too old" << std::endl; + HTTP_S.SetBody("No such stream is available on the system. Please try again.\n"); + HTTP_S.SendResponse("404", "Not found", conn); 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; - sstream << "t " << Quality << " " << audioTrack << "\ns " << mstime << "\np " << (mstime + mslen) << "\n"; - ss.SendNow(sstream.str().c_str()); - std::cout << sstream.str() << std::endl; - - HTTP_S.Clean(); - HTTP_S.protocol = "HTTP/1.1"; - HTTP_S.SetHeader("Content-Type", "video/mp4"); - HTTP_S.SetBody(""); - std::string new_strap = dynamicBootstrap(streamname, Strm.getTrackById(Quality), Strm.metadata.isMember("live"), ReqFragment); - HTTP_S.SetHeader("Transfer-Encoding", "chunked"); - 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 (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"); + HTTP_S.SendResponse("200", "OK", conn); + HTTP_R.Clean(); //clean for any possible next requests + continue; } - if (Quality > 0 && Strm.getTrackById(Quality).isMember("init")){ - tmp.DTSCVideoInit(Strm.getTrackById(Quality)); - tmp.tagTime(mstime); - HTTP_S.Chunkify(tmp.data, tmp.len, conn); + 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 + 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_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 } - 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()){ unsigned int now = Util::epoch(); @@ -286,13 +287,12 @@ namespace Connector_HTTP { lastStats = now; ss.SendNow(conn.getStats("HTTP_Dynamic").c_str()); } - if (ss.spool()){ + if (handlingRequest && ss.spool()){ while (Strm.parsePacket(ss.Received())){ if (Strm.lastType() == DTSC::PAUSEMARK){ //send an empty chunk to signify request is done - std::string empty = ""; - HTTP_S.Chunkify(empty, conn); - std::cout << "Finito!" << std::endl; + HTTP_S.Chunkify("", 0, conn); + handlingRequest = false; } if (Strm.lastType() == DTSC::VIDEO || Strm.lastType() == DTSC::AUDIO){ //send a chunk with the new data diff --git a/src/connectors/conn_http_live.cpp b/src/connectors/conn_http_live.cpp index b6b12c72..4263e699 100644 --- a/src/connectors/conn_http_live.cpp +++ b/src/connectors/conn_http_live.cpp @@ -94,9 +94,6 @@ namespace Connector_HTTP { ///\param conn A socket describing the connection the client. ///\return The exit code of the connector. int liveConnector(Socket::Connection conn){ - std::stringstream TSBuf; - long long int TSBufTime = 0; - DTSC::Stream Strm; //Incoming stream buffer. 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. Socket::Connection ss( -1); std::string streamname; + bool handlingRequest = false; std::string recBuffer = ""; TS::Packet PackData; @@ -129,100 +127,107 @@ namespace Connector_HTTP { conn.setBlocking(false); //do not block on conn.spool() when no data is available while (conn.connected()){ - if (conn.spool() || conn.Received().size()){ - if (HTTP_R.Read(conn)){ -#if DEBUG >= 5 - std::cout << "Received request: " << HTTP_R.getUrl() << std::endl; -#endif - conn.setHost(HTTP_R.GetHeader("X-Origin")); - AppleCompat = (HTTP_R.GetHeader("User-Agent").find("Apple") != std::string::npos); - streamname = HTTP_R.GetHeader("X-Stream"); - if ( !ss){ - ss = Util::Stream::getStream(streamname); - if ( !ss.connected()){ - #if DEBUG >= 1 - fprintf(stderr, "Could not connect to server!\n"); - #endif - 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")); - ready4data = false; - 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 ( !handlingRequest){ + if (conn.spool() || conn.Received().size()){ + if (HTTP_R.Read(conn)){ + #if DEBUG >= 5 + std::cout << "Received request: " << HTTP_R.getUrl() << std::endl; + #endif + conn.setHost(HTTP_R.GetHeader("X-Origin")); + AppleCompat = (HTTP_R.GetHeader("User-Agent").find("Apple") != std::string::npos); + streamname = HTTP_R.GetHeader("X-Stream"); + if ( !ss){ + ss = Util::Stream::getStream(streamname); + if ( !ss.connected()){ + #if DEBUG >= 1 + fprintf(stderr, "Could not connect to server!\n"); + #endif + 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")); + ready4data = false; + 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(".m3u") == std::string::npos){ - temp = HTTP_R.url.find("/", 5) + 1; - std::string allTracks = HTTP_R.url.substr(temp, HTTP_R.url.find("/", temp) - temp); - trackID = atoi(allTracks.c_str()); - audioTrackID = atoi(allTracks.substr(allTracks.find("_")+1).c_str()); - temp = HTTP_R.url.find("/", temp) + 1; - Segment = atoi(HTTP_R.url.substr(temp, HTTP_R.url.find("_", temp) - temp).c_str()); - lastVid = Segment * 90; - temp = HTTP_R.url.find("_", temp) + 1; - int frameCount = atoi(HTTP_R.url.substr(temp, HTTP_R.url.find(".ts", temp) - temp).c_str()); - if (Strm.metadata.isMember("live")){ - int seekable = Strm.canSeekms(Segment); - 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 @ " << Segment << " too old" << std::endl; - continue; + if (HTTP_R.url.find(".m3u") == std::string::npos){ + temp = HTTP_R.url.find("/", 5) + 1; + std::string allTracks = HTTP_R.url.substr(temp, HTTP_R.url.find("/", temp) - temp); + trackID = atoi(allTracks.c_str()); + audioTrackID = atoi(allTracks.substr(allTracks.find("_")+1).c_str()); + temp = HTTP_R.url.find("/", temp) + 1; + Segment = atoi(HTTP_R.url.substr(temp, HTTP_R.url.find("_", temp) - temp).c_str()); + lastVid = Segment * 90; + temp = HTTP_R.url.find("_", temp) + 1; + int frameCount = atoi(HTTP_R.url.substr(temp, HTTP_R.url.find(".ts", temp) - temp).c_str()); + if (Strm.metadata.isMember("live")){ + int seekable = Strm.canSeekms(Segment); + 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 @ " << Segment << " too old" << 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 @ " << Segment << " not available yet" << 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 @ " << Segment << " not available yet" << std::endl; - continue; + for (int i = 0; i < allTracks.size(); i++){ + if (allTracks[i] == '_'){ + allTracks[i] = ' '; + } } - } - for (int i = 0; i < allTracks.size(); i++){ - if (allTracks[i] == '_'){ - allTracks[i] = ' '; - } - } - std::stringstream sstream; - sstream << "t " << allTracks << "\n"; - sstream << "s " << Segment << "\n"; - sstream << "p " << frameCount << "\n"; - 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"; + std::stringstream sstream; + sstream << "t " << allTracks << "\n"; + sstream << "s " << Segment << "\n"; + sstream << "p " << frameCount << "\n"; + ss.SendNow(sstream.str().c_str()); + + HTTP_S.Clean(); + HTTP_S.SetHeader("Content-Type", "video/mp2t"); + HTTP_S.StartResponse(HTTP_R, conn); + handlingRequest = true; }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(); - 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")); + ready4data = true; + HTTP_R.Clean(); //clean for any possible next requests } - ready4data = true; - HTTP_R.Clean(); //clean for any possible next requests + }else{ + Util::sleep(250); } - }else{ - Util::sleep(1); } if (ready4data){ unsigned int now = Util::epoch(); @@ -230,23 +235,11 @@ namespace Connector_HTTP { lastStats = now; ss.SendNow(conn.getStats("HTTP_Live").c_str()); } - if (ss.spool()){ + if (handlingRequest && ss.spool()){ while (Strm.parsePacket(ss.Received())){ if (Strm.lastType() == DTSC::PAUSEMARK){ - TSBuf.flush(); - if (TSBuf.str().size()){ - 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(""); + HTTP_S.Chunkify("", 0, conn); + handlingRequest = false; } if ( !haveAvcc){ avccbox.setPayload(Strm.getTrackById(trackID)["init"].asString()); @@ -257,9 +250,9 @@ namespace Connector_HTTP { //write PAT and PMT TS packets if (PacketNumber % 42 == 0){ PackData.DefaultPAT(); - TSBuf.write(PackData.ToString(), 188); + HTTP_S.Chunkify(PackData.ToString(), 188, conn); PackData.DefaultPMT(); - TSBuf.write(PackData.ToString(), 188); + HTTP_S.Chunkify(PackData.ToString(), 188, conn); PacketNumber += 2; } @@ -310,7 +303,7 @@ namespace Connector_HTTP { unsigned int toSend = PackData.AddStuffing(ToPack.bytes(184)); std::string gonnaSend = ToPack.remove(toSend); PackData.FillFree(gonnaSend); - TSBuf.write(PackData.ToString(), 188); + HTTP_S.Chunkify(PackData.ToString(), 188, conn); PacketNumber++; //rest of packets @@ -321,7 +314,7 @@ namespace Connector_HTTP { toSend = PackData.AddStuffing(ToPack.bytes(184)); gonnaSend = ToPack.remove(toSend); PackData.FillFree(gonnaSend); - TSBuf.write(PackData.ToString(), 188); + HTTP_S.Chunkify(PackData.ToString(), 188, conn); PacketNumber++; } diff --git a/src/connectors/conn_http_progressive_flv.cpp b/src/connectors/conn_http_progressive_flv.cpp index 8db31518..2efdc7a0 100644 --- a/src/connectors/conn_http_progressive_flv.cpp +++ b/src/connectors/conn_http_progressive_flv.cpp @@ -54,12 +54,7 @@ namespace Connector_HTTP { std::cout << "Received request: " << HTTP_R.getUrl() << std::endl; #endif conn.setHost(HTTP_R.GetHeader("X-Origin")); - //we assume the URL is the stream name with a 3 letter extension - streamname = HTTP_R.getUrl().substr(1); - size_t extDot = streamname.rfind('.'); - if (extDot != std::string::npos){ - streamname.resize(extDot); - }; //strip the extension + streamname = HTTP_R.GetHeader("X-Stream"); int start = 0; if ( !HTTP_R.GetVar("start").empty()){ start = atoi(HTTP_R.GetVar("start").c_str()); @@ -126,7 +121,9 @@ namespace Connector_HTTP { byterate += Strm.getTrackById(audioID)["bps"].asInt(); } if ( !byterate){byterate = 1;} - seek_sec = (seek_byte / byterate) * 1000; + if (seek_byte){ + seek_sec = (seek_byte / byterate) * 1000; + } std::stringstream cmd; cmd << "t"; if (videoID != -1){ diff --git a/src/connectors/conn_http_progressive_mp3.cpp b/src/connectors/conn_http_progressive_mp3.cpp index 6f0fcf7e..1cd1fd10 100644 --- a/src/connectors/conn_http_progressive_mp3.cpp +++ b/src/connectors/conn_http_progressive_mp3.cpp @@ -52,12 +52,7 @@ namespace Connector_HTTP { std::cout << "Received request: " << HTTP_R.getUrl() << std::endl; #endif conn.setHost(HTTP_R.GetHeader("X-Origin")); - //we assume the URL is the stream name with a 3 letter extension - streamname = HTTP_R.getUrl().substr(1); - size_t extDot = streamname.rfind('.'); - if (extDot != std::string::npos){ - streamname.resize(extDot); - }; //strip the extension + streamname = HTTP_R.GetHeader("X-Stream"); int start = 0; if ( !HTTP_R.GetVar("start").empty()){ start = atoi(HTTP_R.GetVar("start").c_str()); @@ -121,7 +116,9 @@ namespace Connector_HTTP { byterate += Strm.getTrackById(audioID)["bps"].asInt(); } if ( !byterate){byterate = 1;} - seek_sec = (seek_byte / byterate) * 1000; + if (seek_byte){ + seek_sec = (seek_byte / byterate) * 1000; + } std::stringstream cmd; cmd << "t"; if (videoID != -1){ diff --git a/src/connectors/conn_http_progressive_ogg.cpp b/src/connectors/conn_http_progressive_ogg.cpp index abed9323..93e06d7d 100644 --- a/src/connectors/conn_http_progressive_ogg.cpp +++ b/src/connectors/conn_http_progressive_ogg.cpp @@ -60,12 +60,7 @@ namespace Connector_HTTP { std::cout << "Received request: " << HTTP_R.getUrl() << std::endl; #endif conn.setHost(HTTP_R.GetHeader("X-Origin")); - //we assume the URL is the stream name with a 3 letter extension - streamname = HTTP_R.getUrl().substr(1); - size_t extDot = streamname.rfind('.'); - if (extDot != std::string::npos){ - streamname.resize(extDot); - }; //strip the extension + streamname = HTTP_R.GetHeader("X-Stream"); int start = 0; if ( !HTTP_R.GetVar("start").empty()){ start = atoi(HTTP_R.GetVar("start").c_str()); @@ -132,7 +127,9 @@ namespace Connector_HTTP { byterate += Strm.getTrackById(audioID)["bps"].asInt(); } if ( !byterate){byterate = 1;} - seek_sec = (seek_byte / byterate) * 1000; + if (seek_byte){ + seek_sec = (seek_byte / byterate) * 1000; + } std::stringstream cmd; cmd << "t"; if (videoID != -1){ diff --git a/src/connectors/conn_http_smooth.cpp b/src/connectors/conn_http_smooth.cpp index 863f5884..c2584fe2 100644 --- a/src/connectors/conn_http_smooth.cpp +++ b/src/connectors/conn_http_smooth.cpp @@ -60,10 +60,10 @@ namespace Connector_HTTP { } if (oIt->second["type"].asString() == "video"){ allVideo[oIt->first] = oIt->second; - 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["height"].asInt() > maxHeight){ maxHeight = oIt->second["height"].asInt(); } - if (oIt->second["height"].asInt() < minHeight){ minHeight = oIt->second["height"].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["height"].asInt() > maxHeight){maxHeight = 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. Socket::Connection ss( -1);//The Stream Socket, used to connect to the desired 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 wantsAudio = false;//Indicates whether this request is an audio request. @@ -178,257 +179,253 @@ namespace Connector_HTTP { JSON::Value allVideo; while (conn.connected()){ - if (conn.spool() || conn.Received().size()){ - if (HTTP_R.Read(conn)){ -#if DEBUG >= 5 - std::cout << "Received request: " << HTTP_R.getUrl() << std::endl; -#endif - //Get data set by the proxy. - conn.setHost(HTTP_R.GetHeader("X-Origin")); - streamname = HTTP_R.GetHeader("X-Stream"); - if ( !ss){ - //initiate Stream Socket - ss = Util::Stream::getStream(streamname); - if ( !ss.connected()){ - #if DEBUG >= 1 - fprintf(stderr, "Could not connect to server!\n"); - #endif - 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")); - ready4data = false; - continue; - } - ss.setBlocking(false); - //Do nothing until metadata has been received. - while ( !Strm.metadata && ss.connected()){ - if (ss.spool()){ - while (Strm.parsePacket(ss.Received())){ - //do nothing + if ( !handlingRequest){ + if (conn.spool() || conn.Received().size()){ + if (HTTP_R.Read(conn)){ + #if DEBUG >= 5 + std::cout << "Received request: " << HTTP_R.getUrl() << std::endl; + #endif + //Get data set by the proxy. + conn.setHost(HTTP_R.GetHeader("X-Origin")); + streamname = HTTP_R.GetHeader("X-Stream"); + if ( !ss){ + //initiate Stream Socket + ss = Util::Stream::getStream(streamname); + if ( !ss.connected()){ + #if DEBUG >= 1 + fprintf(stderr, "Could not connect to server!\n"); + #endif + 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")); + ready4data = false; + continue; + } + ss.setBlocking(false); + //Do nothing until metadata has been received. + while ( !Strm.metadata && ss.connected()){ + if (ss.spool()){ + while (Strm.parsePacket(ss.Received())){ + //do nothing + } } } - } - for (JSON::ObjIter oIt = Strm.metadata["tracks"].ObjBegin(); oIt != Strm.metadata["tracks"].ObjEnd(); oIt++){ - if (oIt->second["type"].asString() == "audio"){ - allAudio[oIt->first] = oIt->second; + for (JSON::ObjIter oIt = Strm.metadata["tracks"].ObjBegin(); oIt != Strm.metadata["tracks"].ObjEnd(); oIt++){ + if (oIt->second["type"].asString() == "audio"){ + 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){ - //We have a non-manifest request, parse it. - Quality = HTTP_R.url.substr(HTTP_R.url.find("/Q(", 8) + 3); - Quality = Quality.substr(0, Quality.find(")")); - parseString = HTTP_R.url.substr(HTTP_R.url.find(")/") + 2); - wantsAudio = false; - wantsVideo = false; - if (parseString[0] == 'A'){ - wantsAudio = true; - } - if (parseString[0] == 'V'){ - wantsVideo = true; - } - parseString = parseString.substr(parseString.find("(") + 1); - requestedTime = atoll(parseString.substr(0, parseString.find(")")).c_str()); - if (Strm.metadata.isMember("live")){ - ///\todo Fix this for live stuff - int seekable = Strm.canSeekms(requestedTime / 10000); - if (seekable == 0){ - // iff the fragment in question is available, check if the next is available too - for (int i = 0; i < Strm.metadata["keytime"].size(); i++){ - if (Strm.metadata["keytime"][i].asInt() >= (requestedTime / 10000)){ - if (i + 1 == Strm.metadata["keytime"].size()){ - seekable = 1; + if (HTTP_R.url.find("Manifest") == std::string::npos){ + //We have a non-manifest request, parse it. + Quality = HTTP_R.url.substr(HTTP_R.url.find("/Q(", 8) + 3); + Quality = Quality.substr(0, Quality.find(")")); + parseString = HTTP_R.url.substr(HTTP_R.url.find(")/") + 2); + wantsAudio = false; + wantsVideo = false; + if (parseString[0] == 'A'){ + wantsAudio = true; + } + if (parseString[0] == 'V'){ + wantsVideo = true; + } + parseString = parseString.substr(parseString.find("(") + 1); + requestedTime = atoll(parseString.substr(0, parseString.find(")")).c_str()); + if (Strm.metadata.isMember("live")){ + ///\todo Fix this for live stuff + int seekable = Strm.canSeekms(requestedTime / 10000); + if (seekable == 0){ + // iff the fragment in question is available, check if the next is available too + for (int i = 0; i < Strm.metadata["keytime"].size(); i++){ + if (Strm.metadata["keytime"][i].asInt() >= (requestedTime / 10000)){ + if (i + 1 == Strm.metadata["keytime"].size()){ + 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; } } } - 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 (HTTP_R.url == "/"){continue;}//Don't continue, but continue instead. + if (Strm.metadata.isMember("live")){ + if (mstime == 0 && (requestedTime / 10000) > 1){ + 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) << " too old" << std::endl; + continue; } } - } - 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; - } + + + sstream << "t " << myRef["trackid"].asInt() << "\n"; + sstream << "s " << (requestedTime / 10000) << "\np " << (mstime + mslen) <<"\n"; + ss.SendNow(sstream.str().c_str()); + + unsigned int myDuration; + + //Wrap everything in mp4 boxes + MP4::MFHD mfhd_box; + JSON::Value trackRef; + if (wantsVideo){ + trackRef = allVideo.ObjBegin()->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; - } - } + 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; } } - } - if (HTTP_R.url == "/"){continue;}//Don't continue, but continue instead. - if (Strm.metadata.isMember("live")){ - if (mstime == 0 && (requestedTime / 10000) > 1){ - 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) << " too old" << std::endl; - continue; + + MP4::TFHD tfhd_box; + tfhd_box.setFlags(MP4::tfhdSampleFlag); + tfhd_box.setTrackID(1); + tfhd_box.setDefaultSampleFlags(0x000000C0 | MP4::noIPicture | MP4::noDisposable | MP4::noKeySample); + + MP4::TRUN trun_box; + trun_box.setFlags(MP4::trundataOffset | MP4::trunfirstSampleFlags | MP4::trunsampleDuration | MP4::trunsampleSize); + trun_box.setDataOffset(42); + 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); } - } - - - sstream << "t " << myRef["trackid"].asInt() << "\n"; - sstream << "s " << (requestedTime / 10000) << "\np " << (mstime + mslen) <<"\n"; - ss.SendNow(sstream.str().c_str()); - - 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::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::TFHD tfhd_box; - tfhd_box.setFlags(MP4::tfhdSampleFlag); - tfhd_box.setTrackID(1); - tfhd_box.setDefaultSampleFlags(0x000000C0 | MP4::noIPicture | MP4::noDisposable | MP4::noKeySample); - - MP4::TRUN trun_box; - trun_box.setFlags(MP4::trundataOffset | MP4::trunfirstSampleFlags | MP4::trunsampleDuration | MP4::trunsampleSize); - trun_box.setDataOffset(42); - 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); - 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); + + 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")); } - - 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); - - //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; + //Clean for any possible next requests + HTTP_R.Clean(); } - ready4data = true; - //Clean for any possible next requests - HTTP_R.Clean(); + }else{ + //Wait 250ms before checking for new data. + Util::sleep(250); } - }else{ - //Wait 1 second before checking for new data. - Util::sleep(1); } if (ready4data){ unsigned int now = Util::epoch(); @@ -437,12 +434,14 @@ namespace Connector_HTTP { lastStats = now; ss.SendNow(conn.getStats("HTTP_Smooth").c_str()); } - if (ss.spool()){ + if (handlingRequest && ss.spool()){ while (Strm.parsePacket(ss.Received())){ if (Strm.lastType() == DTSC::AUDIO || Strm.lastType() == DTSC::VIDEO){ - //Select only the data that the client has requested. - int tmp = Util::getMS(); - conn.SendNow(Strm.lastData()); + HTTP_S.Chunkify(Strm.lastData(), conn); + } + if (Strm.lastType() == DTSC::PAUSEMARK){ + HTTP_S.Chunkify("", 0, conn); + handlingRequest = false; } } }