From dd3e8652f530c35febcc3f595e38443395f79198 Mon Sep 17 00:00:00 2001 From: methodus Date: Sat, 29 Sep 2012 22:48:56 +0200 Subject: Streamer almost completed. First tests successful. However, there are no plugins, yet. --- httptnt/resourceStreamer.ecpp | 105 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 httptnt/resourceStreamer.ecpp (limited to 'httptnt/resourceStreamer.ecpp') diff --git a/httptnt/resourceStreamer.ecpp b/httptnt/resourceStreamer.ecpp new file mode 100644 index 0000000..2c64fed --- /dev/null +++ b/httptnt/resourceStreamer.ecpp @@ -0,0 +1,105 @@ +<%args> +objectID; +int resourceID = 0; + +<%pre> +#include +#include +#include +#include +#include "../include/tools.h" +#include "../include/media/mediaManager.h" +#include "../include/server.h" + +#include +#include +#include + +using namespace upnp; + +<# +int doRequest(tnt::HttpReply reply, tnt::HttpRequest request, std::string objectID, int resourceID) { +#> +<%cpp> + if(objectID.empty()){ + reply.out() << "Object ID missing"; + return HTTP_BAD_REQUEST; + } + + cMediaServer* server = cMediaServer::GetInstance(); + cMediaManager& manager = server->GetManager(); + std::auto_ptr streamer(manager.GetResourceStreamer(objectID, resourceID)); + + if(!streamer.get()){ + reply.out() << "Object ID not found or invalid"; + return HTTP_NOT_FOUND; + } + + int code = HTTP_OK; + + reply.setContentType(streamer->GetContentType()); + reply.setHeader("friendlyName.dlna.org ", server->GetServerDescription().friendlyName); + reply.setHeader("contentFeatures.dlna.org ", streamer->GetContentFeatures()); + reply.setHeader("transferMode.dlna.org ", streamer->GetTransferMode(reply.getHeader("transferMode.dlna.org"))); + + if(streamer->GetContentLength() > 0){ + reply.setContentLengthHeader(streamer->GetContentLength()); + if(streamer->Seekable()) reply.setHeader("Accept-Ranges", "bytes"); + } + + if(!request.isMethodHEAD()){ + + int offset = 0, length = std::numeric_limits::max(); + bool hasRange = false; + + if(streamer->Seekable() && streamer->GetContentLength() > 0){ + if(request.hasHeader("Range")){ + std::string rangeRequest = request.getHeader("Range"); + if(rangeRequest.find("bytes=",0) == 0){ + int minus = rangeRequest.find_first_of('-',6); + offset = atoi(rangeRequest.substr(6, minus - 6).c_str()); + length = atoi(rangeRequest.substr(minus + 1).c_str()) - offset; + + if(length == 0) length = std::numeric_limits::max(); + + hasRange = (offset == 0 && length == std::numeric_limits::max()) ? false : true; + } + } + + streamer->Seek(offset, SEEK_SET); + } + + char buffer[KB(16)]; + ssize_t bytesRead = 0; + size_t totalBytesRead = 0; + size_t toRead = std::min(length, sizeof(buffer)); + while (0 < (bytesRead = streamer->Read(buffer, toRead)) && length > 0) { + reply.out().write(buffer, bytesRead); + if (!reply.out()) { + code = HTTP_GONE; + goto ret; + } + length -= bytesRead; + totalBytesRead += bytesRead; + toRead = std::min(length, sizeof(buffer)); + } + + reply.setContentLengthHeader(totalBytesRead); + + if ((bytesRead < 0 || length <= 0) && hasRange) { + std::stringstream ss; + ss << "bytes " << offset << "-" << offset + totalBytesRead << "/" << streamer->GetContentLength(); + reply.setHeader("Content-Range", ss.str()); + code = HTTP_PARTIAL_CONTENT; + goto ret; + } + + } + + ret: + //reply.out() << std::flush; + return code; + +<# +} +#> -- cgit v1.2.3