<%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/media/requestCounter.h" using namespace upnp; <%request> boost::shared_ptr streamer; request_counter_t counter; <%cpp> _unused(counter); if(objectID.empty()){ reply.out() << "Object ID missing"; return HTTP_BAD_REQUEST; } cMediaServer* server = cMediaServer::GetInstance(); cMediaManager& manager = server->GetManager(); streamer = boost::shared_ptr(manager.GetResourceStreamer(objectID, resourceID)); if(!streamer.get()){ reply.out() << "Object ID not found or invalid"; return HTTP_NOT_FOUND; } int code = HTTP_OK; string codeText = "OK"; // DLNA requires KeepAlive timeout of 60s. reply.setKeepAliveTimeout(60000); 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"))); size_t from = 0, to = 0, contentLength = streamer->GetContentLength(), length = contentLength; bool hasRange = false; if(contentLength > 0){ reply.setContentLengthHeader(contentLength); if(streamer->Seekable()){ reply.setHeader("Accept-Ranges ", "bytes"); if(request.hasHeader("getAvailableSeekRange.dlna.org:")){ std::stringstream availableRangeHeader; availableRangeHeader << "1 bytes=0-" << contentLength; reply.setHeader("availableSeekRange.dlna.org ", availableRangeHeader.str()); } } if(request.hasHeader("Range:")){ std::string rangeRequest = request.getHeader("Range:"); if(rangeRequest.find("bytes=",0) == 0){ unsigned int minus = rangeRequest.find_first_of('-',6); if(minus != std::string::npos){ from = atol(rangeRequest.substr(6, minus - 6).c_str()); to = atol(rangeRequest.substr(minus + 1).c_str()); if(from){ // If range is off the road, reset it to correct values. if(from <= 0 || from > contentLength) from = 0; if(to <= 0 || to > contentLength) to = contentLength; length = to - from; hasRange = true; std::stringstream contentRangeHeader; contentRangeHeader << "bytes " << from << "-" << to << "/" << contentLength; reply.setHeader("Content-Range ", contentRangeHeader.str()); reply.setContentLengthHeader(length); } } } } } if(!request.isMethodHEAD()){ if(!streamer->Open()){ return HTTP_INTERNAL_SERVER_ERROR; } if(hasRange && streamer->Seekable() && contentLength > 0){ if(!streamer->Seek(from, SEEK_SET)){ return HTTP_INTERNAL_SERVER_ERROR; } code = HTTP_PARTIAL_CONTENT; codeText = "Partial Content"; } reply.setDirectMode(code, codeText.c_str()); size_t bytesRead = 0; char buffer[KB(16)]; while ((bytesRead = streamer->Read(buffer, KB(16))) > 0 && length) { if(!(reply.out().write(buffer, bytesRead))) break; length -= bytesRead; request.touch(); } } reply.out() << std::flush; return code;