diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/connection.c | 11 | ||||
-rw-r--r-- | server/connection.h | 20 | ||||
-rw-r--r-- | server/connectionHTTP.c | 360 | ||||
-rw-r--r-- | server/connectionHTTP.h | 19 | ||||
-rw-r--r-- | server/connectionIGMP.c | 4 | ||||
-rw-r--r-- | server/connectionVTP.c | 8 | ||||
-rw-r--r-- | server/livestreamer.c | 29 | ||||
-rw-r--r-- | server/livestreamer.h | 5 | ||||
-rw-r--r-- | server/menuHTTP.c | 4 | ||||
-rw-r--r-- | server/setup.c | 29 | ||||
-rw-r--r-- | server/setup.h | 4 | ||||
-rw-r--r-- | server/streamer.c | 5 | ||||
-rw-r--r-- | server/streamer.h | 8 |
13 files changed, 294 insertions, 212 deletions
diff --git a/server/connection.c b/server/connection.c index 059a63e..6bcbd1e 100644 --- a/server/connection.c +++ b/server/connection.c @@ -1,5 +1,5 @@ /* - * $Id: connection.c,v 1.10.2.2 2009/09/18 10:41:11 schmirl Exp $ + * $Id: connection.c,v 1.10.2.3 2010/07/19 13:50:14 schmirl Exp $ */ #include "server/connection.h" @@ -27,7 +27,7 @@ cServerConnection::~cServerConnection() { } -const cChannel* cServerConnection::ChannelFromString(const char *String, int *Apid) { +const cChannel* cServerConnection::ChannelFromString(const char *String, int *Apid, int *Dpid) { const cChannel *channel = NULL; char *string = strdup(String); char *ptr, *end; @@ -58,7 +58,8 @@ const cChannel* cServerConnection::ChannelFromString(const char *String, int *Ap } if (channel != NULL && apididx > 0) { - int apid = 0, index = 1; + int apid = 0, dpid = 0; + int index = 1; for (int i = 0; channel->Apid(i) != 0; ++i, ++index) { if (index == apididx) { @@ -70,7 +71,7 @@ const cChannel* cServerConnection::ChannelFromString(const char *String, int *Ap if (apid == 0) { for (int i = 0; channel->Dpid(i) != 0; ++i, ++index) { if (index == apididx) { - apid = channel->Dpid(i); + dpid = channel->Dpid(i); break; } } @@ -78,6 +79,8 @@ const cChannel* cServerConnection::ChannelFromString(const char *String, int *Ap if (Apid != NULL) *Apid = apid; + if (Dpid != NULL) + *Dpid = dpid; } free(string); diff --git a/server/connection.h b/server/connection.h index 7979e35..95881e7 100644 --- a/server/connection.h +++ b/server/connection.h @@ -1,5 +1,5 @@ /* - * $Id: connection.h,v 1.5.2.3 2009/09/18 10:41:11 schmirl Exp $ + * $Id: connection.h,v 1.5.2.4 2010/07/19 13:50:14 schmirl Exp $ */ #ifndef VDR_STREAMDEV_SERVER_CONNECTION_H @@ -8,6 +8,11 @@ #include "tools/socket.h" #include "common.h" +#include <map> + +typedef std::map<std::string,std::string> tStrStrMap; +typedef std::pair<std::string,std::string> tStrStr; + class cChannel; class cDevice; @@ -28,6 +33,8 @@ private: uint m_WriteBytes; uint m_WriteIndex; + tStrStrMap m_Headers; + protected: /* Will be called when a command terminated by a newline has been received */ @@ -41,7 +48,10 @@ protected: virtual bool Respond(const char *Message, bool Last = true, ...); //__attribute__ ((format (printf, 2, 4))); - static const cChannel *ChannelFromString(const char *String, int *Apid = NULL); + /* Add a request header */ + void SetHeader(const char *Name, const char *Value, const char *Prefix = "") { m_Headers.insert(tStrStr(std::string(Prefix) + Name, Value)); } + + static const cChannel *ChannelFromString(const char *String, int *Apid = NULL, int *Dpid = NULL); public: /* If you derive, specify a short string such as HTTP for Protocol, which @@ -89,6 +99,12 @@ public: virtual void Detach(void) = 0; virtual void Attach(void) = 0; + + /* This connections protocol name */ + virtual const char* Protocol(void) const { return m_Protocol; } + + /* std::map with additional information */ + const tStrStrMap& Headers(void) const { return m_Headers; } }; inline bool cServerConnection::HasData(void) const diff --git a/server/connectionHTTP.c b/server/connectionHTTP.c index fb275ff..b687c71 100644 --- a/server/connectionHTTP.c +++ b/server/connectionHTTP.c @@ -1,5 +1,5 @@ /* - * $Id: connectionHTTP.c,v 1.13.2.2 2009/02/13 07:02:26 schmirl Exp $ + * $Id: connectionHTTP.c,v 1.13.2.3 2010/07/19 13:50:14 schmirl Exp $ */ #include <ctype.h> @@ -13,13 +13,13 @@ cConnectionHTTP::cConnectionHTTP(void): cServerConnection("HTTP"), m_Status(hsRequest), m_LiveStreamer(NULL), - m_StreamerParameter(""), m_Channel(NULL), - m_Apid(0), m_StreamType((eStreamType)StreamdevServerSetup.HTTPStreamType), m_ChannelList(NULL) { Dprintf("constructor hsRequest\n"); + m_Apid[0] = m_Apid[1] = 0; + m_Dpid[0] = m_Dpid[1] = 0; } cConnectionHTTP::~cConnectionHTTP() @@ -37,30 +37,64 @@ bool cConnectionHTTP::Command(char *Cmd) Dprintf("command %s\n", Cmd); switch (m_Status) { case hsRequest: - Dprintf("Request\n"); - m_Request = Cmd; - m_Status = hsHeaders; - return true; + // parse METHOD PATH[?QUERY] VERSION + { + char *p, *q, *v; + p = strchr(Cmd, ' '); + if (p) { + *p = 0; + v = strchr(++p, ' '); + if (v) { + *v = 0; + SetHeader("REQUEST_METHOD", Cmd); + q = strchr(p, '?'); + if (q) + *q = 0; + SetHeader("QUERY_STRING", q ? ++q : ""); + SetHeader("PATH_INFO", p); + m_Status = hsHeaders; + return true; + } + } + } + return false; case hsHeaders: if (*Cmd == '\0') { m_Status = hsBody; return ProcessRequest(); } - if (strncasecmp(Cmd, "Host:", 5) == 0) { - Dprintf("Host-Header\n"); - m_Host = (std::string) skipspace(Cmd + 5); - return true; + else if (isspace(*Cmd)) { + ; //TODO: multi-line header } - else if (strncasecmp(Cmd, "Authorization:", 14) == 0) { - Cmd = skipspace(Cmd + 14); - if (strncasecmp(Cmd, "Basic", 5) == 0) { - Dprintf("'Authorization Basic'-Header\n"); - m_Authorization = (std::string) skipspace(Cmd + 5); - return true; + else { + // convert header name to CGI conventions: + // uppercase, '-' replaced with '_', prefix "HTTP_" + char *p; + for (p = Cmd; *p != 0 && *p != ':'; p++) { + if (*p == '-') + *p = '_'; + else + *p = toupper(*p); + } + if (*p == ':') { + *p = 0; + p = skipspace(++p); + // don't disclose Authorization header + if (strcmp(Cmd, "AUTHORIZATION") == 0) { + char *q; + for (q = p; *q != 0 && *q != ' '; q++) + *q = toupper(*q); + if (p != q) { + *q = 0; + SetHeader("AUTH_TYPE", p); + m_Authorization = (std::string) skipspace(++q); + } + } + else + SetHeader(Cmd, p, "HTTP_"); } } - Dprintf("header\n"); return true; default: // skip additional blank lines @@ -73,10 +107,31 @@ bool cConnectionHTTP::Command(char *Cmd) bool cConnectionHTTP::ProcessRequest(void) { + // keys for Headers() hash + const static std::string AUTH_TYPE("AUTH_TYPE"); + const static std::string REQUEST_METHOD("REQUEST_METHOD"); + const static std::string PATH_INFO("PATH_INFO"); + Dprintf("process\n"); - if (!StreamdevHosts.Acceptable(RemoteIpAddr())) - { - if (!opt_auth || m_Authorization.empty() || m_Authorization.compare(opt_auth) != 0) { + if (!StreamdevHosts.Acceptable(RemoteIpAddr())) { + bool authOk = opt_auth && !m_Authorization.empty(); + if (authOk) { + tStrStrMap::const_iterator it = Headers().find(AUTH_TYPE); + + if (it == Headers().end()) { + // no authorization header present + authOk = false; + } + else if (it->second.compare("BASIC") == 0) { + // basic auth + authOk &= m_Authorization.compare(opt_auth) == 0; + } + else { + // unsupported auth type + authOk = false; + } + } + if (!authOk) { isyslog("streamdev-server: HTTP authorization required"); DeferClose(); return Respond("HTTP/1.0 401 Authorization Required") @@ -84,28 +139,22 @@ bool cConnectionHTTP::ProcessRequest(void) && Respond(""); } } - if (m_Request.substr(0, 4) == "GET " && CmdGET(m_Request.substr(4))) { - switch (m_Job) { - case hjListing: - if (m_ChannelList) - return Respond("%s", true, m_ChannelList->HttpHeader().c_str()); - break; - case hjTransfer: - if (m_Channel == NULL) { - DeferClose(); - return Respond("HTTP/1.0 404 not found"); - } - - m_LiveStreamer = new cStreamdevLiveStreamer(0, m_StreamerParameter); + if (Headers().at(REQUEST_METHOD).compare("GET") == 0 && ProcessURI(Headers().at(PATH_INFO))) { + if (m_ChannelList) + return Respond("%s", true, m_ChannelList->HttpHeader().c_str()); + else if (m_Channel != NULL) { cDevice *device = GetDevice(m_Channel, 0); if (device != NULL) { device->SwitchChannel(m_Channel, false); - if (m_LiveStreamer->SetChannel(m_Channel, m_StreamType, m_Apid)) { + m_LiveStreamer = new cStreamdevLiveStreamer(0, this); + if (m_LiveStreamer->SetChannel(m_Channel, m_StreamType, m_Apid[0] ? m_Apid : NULL, m_Dpid[0] ? m_Dpid : NULL)) { m_LiveStreamer->SetDevice(device); if (!SetDSCP()) LOG_ERROR_STR("unable to set DSCP sockopt"); - if (m_StreamType == stES && (m_Apid != 0 || ISRADIO(m_Channel))) { + if (m_StreamType == stEXT) { + return Respond("HTTP/1.0 200 OK"); + } else if (ISRADIO(m_Channel) || (m_StreamType == stES && (m_Apid[0] || m_Dpid[0]))) { return Respond("HTTP/1.0 200 OK") && Respond("Content-Type: audio/mpeg") && Respond("icy-name: %s", true, m_Channel->Name()) @@ -116,12 +165,46 @@ bool cConnectionHTTP::ProcessRequest(void) && Respond(""); } } + DELETENULL(m_LiveStreamer); } - DELETENULL(m_LiveStreamer); DeferClose(); return Respond("HTTP/1.0 409 Channel not available") && Respond(""); } + else { + DeferClose(); + return Respond("HTTP/1.0 404 not found") + && Respond(""); + } + } else if (Headers().at(REQUEST_METHOD).compare("HEAD") == 0 && ProcessURI(Headers().at(PATH_INFO))) { + DeferClose(); + if (m_ChannelList) + return Respond("%s", true, m_ChannelList->HttpHeader().c_str()); + else if (m_Channel != NULL) { + cDevice *device = GetDevice(m_Channel, 0); + if (device != NULL) { + if (m_StreamType == stEXT) { + // TODO + return Respond("HTTP/1.0 200 OK") + && Respond(""); + } else if (ISRADIO(m_Channel) || (m_StreamType == stES && (m_Apid[0] || m_Dpid[0]))) { + return Respond("HTTP/1.0 200 OK") + && Respond("Content-Type: audio/mpeg") + && Respond("icy-name: %s", true, m_Channel->Name()) + && Respond(""); + } else { + return Respond("HTTP/1.0 200 OK") + && Respond("Content-Type: video/mpeg") + && Respond(""); + } + } + return Respond("HTTP/1.0 409 Channel not available") + && Respond(""); + } + else { + return Respond("HTTP/1.0 404 not found") + && Respond(""); + } } DeferClose(); @@ -136,161 +219,130 @@ void cConnectionHTTP::Flushed(void) if (m_Status != hsBody) return; - switch (m_Job) { - case hjListing: - if (m_ChannelList) { - if (m_ChannelList->HasNext()) { - if (!Respond("%s", true, m_ChannelList->Next().c_str())) - DeferClose(); - } - else { - DELETENULL(m_ChannelList); - m_Status = hsFinished; + if (m_ChannelList) { + if (m_ChannelList->HasNext()) { + if (!Respond("%s", true, m_ChannelList->Next().c_str())) DeferClose(); - } - return; } - // should never be reached - esyslog("streamdev-server cConnectionHTTP::Flushed(): no channel list"); - m_Status = hsFinished; - break; - - case hjTransfer: + else { + DELETENULL(m_ChannelList); + m_Status = hsFinished; + DeferClose(); + } + return; + } + else if (m_Channel != NULL) { Dprintf("streamer start\n"); m_LiveStreamer->Start(this); m_Status = hsFinished; - break; + } + else { + // should never be reached + esyslog("streamdev-server cConnectionHTTP::Flushed(): no job to do"); + m_Status = hsFinished; } } -bool cConnectionHTTP::CmdGET(const std::string &Opts) +cChannelList* cConnectionHTTP::ChannelListFromString(const std::string& Path, const std::string& Filebase, const std::string& Fileext) const { - const char *ptr, *sp, *pp, *fp, *xp, *qp, *ep; - const cChannel *chan; - int apid = 0; - - ptr = Opts.c_str(); - - // find begin of URL - sp = skipspace(ptr); - // find end of URL (\0 or first space character) - for (ep = sp; *ep && !isspace(*ep); ep++) - ; - // find begin of query string (first ?) - for (qp = sp; qp < ep && *qp != '?'; qp++) - ; - // find begin of filename (last /) - for (fp = qp; fp > sp && *fp != '/'; --fp) - ; - // find begin of section params (first ;) - for (pp = sp; pp < fp && *pp != ';'; pp++) - ; - // find filename extension (first .) - for (xp = fp; xp < qp && *xp != '.'; xp++) - ; - if (qp - xp > 5) // too long for a filename extension - xp = qp; - - std::string type, filespec, fileext, query; - // Streamtype with leading / stripped off - if (pp > sp) - type = Opts.substr(sp - ptr + 1, pp - sp - 1); - // Section parameters with leading ; stripped off - if (fp > pp) - m_StreamerParameter = Opts.substr(pp - ptr + 1, fp - pp - 1); - // file basename with leading / stripped off - if (xp > fp) - filespec = Opts.substr(fp - ptr + 1, xp - fp - 1); - // file extension including leading . - fileext = Opts.substr(xp - ptr, qp - xp); - // query string including leading ? - query = Opts.substr(qp - ptr, ep - qp); + // keys for Headers() hash + const static std::string QUERY_STRING("QUERY_STRING"); + const static std::string HOST("HTTP_HOST"); - Dprintf("before channelfromstring: type(%s) param(%s) filespec(%s) fileext(%s) query(%s)\n", type.c_str(), m_StreamerParameter.c_str(), filespec.c_str(), fileext.c_str(), query.c_str()); - - const char* pType = type.c_str(); - if (strcasecmp(pType, "PS") == 0) { - m_StreamType = stPS; - } else if (strcasecmp(pType, "PES") == 0) { - m_StreamType = stPES; - } else if (strcasecmp(pType, "TS") == 0) { - m_StreamType = stTS; - } else if (strcasecmp(pType, "ES") == 0) { - m_StreamType = stES; - } else if (strcasecmp(pType, "Extern") == 0) { - m_StreamType = stExtern; - } + const std::string query = Headers().at(QUERY_STRING); std::string groupTarget; cChannelIterator *iterator = NULL; - if (filespec.compare("tree") == 0) { + if (Filebase.compare("tree") == 0) { const cChannel* c = NULL; size_t groupIndex = query.find("group="); if (groupIndex != std::string::npos) c = cChannelList::GetGroup(atoi(query.c_str() + groupIndex + 6)); iterator = new cListTree(c); - groupTarget = filespec + fileext; - } else if (filespec.compare("groups") == 0) { + groupTarget = Filebase + Fileext; + } else if (Filebase.compare("groups") == 0) { iterator = new cListGroups(); - groupTarget = (std::string) "group" + fileext; - } else if (filespec.compare("group") == 0) { + groupTarget = (std::string) "group" + Fileext; + } else if (Filebase.compare("group") == 0) { const cChannel* c = NULL; size_t groupIndex = query.find("group="); if (groupIndex != std::string::npos) c = cChannelList::GetGroup(atoi(query.c_str() + groupIndex + 6)); iterator = new cListGroup(c); - } else if (filespec.compare("channels") == 0) { + } else if (Filebase.compare("channels") == 0) { iterator = new cListChannels(); - } else if (filespec.compare("all") == 0 || - (filespec.empty() && fileext.empty())) { + } else if (Filebase.compare("all") == 0 || + (Filebase.empty() && Fileext.empty())) { iterator = new cListAll(); } if (iterator) { - if (filespec.empty() || fileext.compare(".htm") == 0 || fileext.compare(".html") == 0) { - m_ChannelList = new cHtmlChannelList(iterator, m_StreamType, (filespec + fileext + query).c_str(), groupTarget.c_str()); - m_Job = hjListing; - } else if (fileext.compare(".m3u") == 0) { + if (Filebase.empty() || Fileext.compare(".htm") == 0 || Fileext.compare(".html") == 0) { + std::string self = Filebase + Fileext; + if (!query.empty()) + self += '?' + query; + return new cHtmlChannelList(iterator, m_StreamType, self.c_str(), groupTarget.c_str()); + } else if (Fileext.compare(".m3u") == 0) { std::string base; - if (*(m_Host.c_str())) - base = "http://" + m_Host + "/"; + tStrStrMap::const_iterator it = Headers().find(HOST); + if (it != Headers().end()) + base = "http://" + it->second + "/"; else base = (std::string) "http://" + LocalIp() + ":" + (const char*) itoa(StreamdevServerSetup.HTTPServerPort) + "/"; - if (type.empty()) - { - switch (m_StreamType) - { - case stTS: base += "TS/"; break; - case stPS: base += "PS/"; break; - case stPES: base += "PES/"; break; - case stES: base += "ES/"; break; - case stExtern: base += "Extern/"; break; - default: break; - - } - } else { - base += type; - if (!m_StreamerParameter.empty()) - base += ";" + m_StreamerParameter; - base += "/"; - } - m_ChannelList = new cM3uChannelList(iterator, base.c_str()); - m_Job = hjListing; + base += Path; + return new cM3uChannelList(iterator, base.c_str()); } else { delete iterator; - return false; } - } else if ((chan = ChannelFromString(filespec.c_str(), &apid)) != NULL) { - m_Channel = chan; - m_Apid = apid; - Dprintf("Apid is %d\n", apid); - m_Job = hjTransfer; + } + return NULL; +} + +bool cConnectionHTTP::ProcessURI(const std::string& PathInfo) +{ + std::string filespec, fileext; + size_t file_pos = PathInfo.rfind('/'); + + if (file_pos != std::string::npos) { + size_t ext_pos = PathInfo.rfind('.'); + // file basename with leading / stripped off + filespec = PathInfo.substr(file_pos + 1, ext_pos - file_pos - 1); + if (ext_pos != std::string::npos) + // file extension including leading . + fileext = PathInfo.substr(ext_pos); + } + if (fileext.length() > 5) { + //probably not an extension + filespec += fileext; + fileext.clear(); + } + + // Streamtype with leading / stripped off + std::string type = PathInfo.substr(1, PathInfo.find_first_of("/;", 1) - 1); + const char* pType = type.c_str(); + if (strcasecmp(pType, "PS") == 0) { + m_StreamType = stPS; + } else if (strcasecmp(pType, "PES") == 0) { + m_StreamType = stPES; + } else if (strcasecmp(pType, "TS") == 0) { + m_StreamType = stTS; + } else if (strcasecmp(pType, "ES") == 0) { + m_StreamType = stES; + } else if (strcasecmp(pType, "EXT") == 0) { + m_StreamType = stEXT; + } + + Dprintf("before channelfromstring: type(%s) filespec(%s) fileext(%s)\n", type.c_str(), filespec.c_str(), fileext.c_str()); + + if ((m_ChannelList = ChannelListFromString(PathInfo.substr(0, file_pos), filespec.c_str(), fileext.c_str())) != NULL) { + Dprintf("Channel list requested\n"); + return true; + } else if ((m_Channel = ChannelFromString(filespec.c_str(), &m_Apid[0], &m_Dpid[0])) != NULL) { + Dprintf("Channel found. Apid/Dpid is %d/%d\n", m_Apid[0], m_Dpid[0]); + return true; } else return false; - - Dprintf("after channelfromstring\n"); - return true; } diff --git a/server/connectionHTTP.h b/server/connectionHTTP.h index d7aa22b..c67272e 100644 --- a/server/connectionHTTP.h +++ b/server/connectionHTTP.h @@ -1,5 +1,5 @@ /* - * $Id: connectionHTTP.h,v 1.5.2.1 2008/10/14 11:05:59 schmirl Exp $ + * $Id: connectionHTTP.h,v 1.5.2.2 2010/07/19 13:50:14 schmirl Exp $ */ #ifndef VDR_STREAMDEV_SERVERS_CONNECTIONHTTP_H @@ -8,6 +8,7 @@ #include "connection.h" #include "server/livestreamer.h" +#include <map> #include <tools/select.h> class cChannel; @@ -23,26 +24,19 @@ private: hsFinished, }; - enum eHTTPJob { - hjTransfer, - hjListing, - }; - - std::string m_Request; - std::string m_Host; std::string m_Authorization; - //std::map<std::string,std::string> m_Headers; TODO: later? eHTTPStatus m_Status; - eHTTPJob m_Job; // job: transfer cStreamdevLiveStreamer *m_LiveStreamer; - std::string m_StreamerParameter; const cChannel *m_Channel; - int m_Apid; + int m_Apid[2]; + int m_Dpid[2]; eStreamType m_StreamType; // job: listing cChannelList *m_ChannelList; + cChannelList* ChannelListFromString(const std::string &PathInfo, const std::string &Filebase, const std::string &Fileext) const; + bool ProcessURI(const std::string &PathInfo); protected: bool ProcessRequest(void); @@ -56,7 +50,6 @@ public: virtual bool CanAuthenticate(void); virtual bool Command(char *Cmd); - bool CmdGET(const std::string &Opts); virtual bool Abort(void) const; virtual void Flushed(void); diff --git a/server/connectionIGMP.c b/server/connectionIGMP.c index b579754..4a2484e 100644 --- a/server/connectionIGMP.c +++ b/server/connectionIGMP.c @@ -1,5 +1,5 @@ /* - * $Id: connectionIGMP.c,v 1.1.2.2 2009/02/13 10:39:42 schmirl Exp $ + * $Id: connectionIGMP.c,v 1.1.2.3 2010/07/19 13:50:14 schmirl Exp $ */ #include <ctype.h> @@ -31,7 +31,7 @@ bool cConnectionIGMP::Start(cChannel *Channel, in_addr_t Dst) struct in_addr ip; ip.s_addr = Dst; if (Connect(inet_ntoa(ip), m_ClientPort)) { - m_LiveStreamer = new cStreamdevLiveStreamer(0); + m_LiveStreamer = new cStreamdevLiveStreamer(0, this); if (m_LiveStreamer->SetChannel(Channel, m_StreamType)) { m_LiveStreamer->SetDevice(device); if (!SetDSCP()) diff --git a/server/connectionVTP.c b/server/connectionVTP.c index 804c6f4..91d9265 100644 --- a/server/connectionVTP.c +++ b/server/connectionVTP.c @@ -1,5 +1,5 @@ /* - * $Id: connectionVTP.c,v 1.18.2.6 2010/01/29 12:02:44 schmirl Exp $ + * $Id: connectionVTP.c,v 1.18.2.7 2010/07/19 13:50:14 schmirl Exp $ */ #include "server/connectionVTP.h" @@ -861,8 +861,8 @@ bool cConnectionVTP::CmdCAPS(char *Opts) return Respond(220, "Capability \"%s\" accepted", Opts); } - if (strcasecmp(Opts, "EXTERN") == 0) { - m_StreamType = stExtern; + if (strcasecmp(Opts, "EXT") == 0) { + m_StreamType = stEXT; return Respond(220, "Capability \"%s\" accepted", Opts); } @@ -1058,7 +1058,7 @@ bool cConnectionVTP::CmdTUNE(char *Opts) return Respond(560, "Channel not available"); delete m_LiveStreamer; - m_LiveStreamer = new cStreamdevLiveStreamer(1); + m_LiveStreamer = new cStreamdevLiveStreamer(1, this); m_LiveStreamer->SetChannel(chan, m_StreamType); m_LiveStreamer->SetDevice(dev); if(m_LiveSocket) diff --git a/server/livestreamer.c b/server/livestreamer.c index c894468..ff4f708 100644 --- a/server/livestreamer.c +++ b/server/livestreamer.c @@ -343,10 +343,9 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i // --- cStreamdevLiveStreamer ------------------------------------------------- -cStreamdevLiveStreamer::cStreamdevLiveStreamer(int Priority, std::string Parameter): - cStreamdevStreamer("streamdev-livestreaming"), +cStreamdevLiveStreamer::cStreamdevLiveStreamer(int Priority, const cServerConnection *Connection): + cStreamdevStreamer("streamdev-livestreaming", Connection), m_Priority(Priority), - m_Parameter(Parameter), m_NumPids(0), m_StreamType(stTSPIDS), m_Channel(NULL), @@ -460,40 +459,38 @@ void cStreamdevLiveStreamer::StartReceiver(void) } } -bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType StreamType, int Apid) +bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType StreamType, const int* Apid, const int *Dpid) { Dprintf("Initializing Remuxer for full channel transfer\n"); //printf("ca pid: %d\n", Channel->Ca()); m_Channel = Channel; m_StreamType = StreamType; - int apid[2] = { Apid, 0 }; - const int *Apids = Apid ? apid : m_Channel->Apids(); - const int *Dpids = Apid ? NULL : m_Channel->Dpids(); + const int *Apids = Apid ? Apid : m_Channel->Apids(); + const int *Dpids = Dpid ? Dpid : m_Channel->Dpids(); switch (m_StreamType) { case stES: { int pid = ISRADIO(m_Channel) ? m_Channel->Apid(0) : m_Channel->Vpid(); - if (Apid != 0) - pid = Apid; + if (Apid && Apid[0]) + pid = Apid[0]; + else if (Dpid && Dpid[0]) + pid = Dpid[0]; m_Remux = new cTS2ESRemux(pid); return SetPids(pid); } case stPES: - m_Remux = new cTS2PESRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(), - m_Channel->Spids()); + m_Remux = new cTS2PESRemux(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids()); return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids()); case stPS: - m_Remux = new cTS2PSRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(), - m_Channel->Spids()); + m_Remux = new cTS2PSRemux(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids()); return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids()); - case stExtern: - m_Remux = new cExternRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(), - m_Channel->Spids(), m_Parameter); + case stEXT: + m_Remux = new cExternRemux(Connection(), m_Channel, Apids, Dpids); // fall through case stTS: // This should never happen, but ... diff --git a/server/livestreamer.h b/server/livestreamer.h index 92448bb..283a395 100644 --- a/server/livestreamer.h +++ b/server/livestreamer.h @@ -18,7 +18,6 @@ class cStreamdevLiveReceiver; class cStreamdevLiveStreamer: public cStreamdevStreamer { private: int m_Priority; - std::string m_Parameter; int m_Pids[MAXRECEIVEPIDS + 1]; int m_NumPids; eStreamType m_StreamType; @@ -32,13 +31,13 @@ private: bool HasPid(int Pid); public: - cStreamdevLiveStreamer(int Priority, std::string Parameter = ""); + cStreamdevLiveStreamer(int Priority, const cServerConnection *Connection); virtual ~cStreamdevLiveStreamer(); void SetDevice(cDevice *Device) { m_Device = Device; } bool SetPid(int Pid, bool On); bool SetPids(int Pid, const int *Pids1 = NULL, const int *Pids2 = NULL, const int *Pids3 = NULL); - bool SetChannel(const cChannel *Channel, eStreamType StreamType, int Apid = 0); + bool SetChannel(const cChannel *Channel, eStreamType StreamType, const int* Apid = NULL, const int* Dpid = NULL); virtual int Put(const uchar *Data, int Count); virtual uchar *Get(int &Count); diff --git a/server/menuHTTP.c b/server/menuHTTP.c index 7277473..47df3a8 100644 --- a/server/menuHTTP.c +++ b/server/menuHTTP.c @@ -205,8 +205,8 @@ std::string cHtmlChannelList::StreamTypeMenu() (std::string) "[<a href=\"/PES/" + self + "\">PES</a>] "); typeMenu += (streamType == stES ? (std::string) "[ES] " : (std::string) "[<a href=\"/ES/" + self + "\">ES</a>] "); - typeMenu += (streamType == stExtern ? (std::string) "[Extern] " : - (std::string) "[<a href=\"/Extern/" + self + "\">Extern</a>] "); + typeMenu += (streamType == stEXT ? (std::string) "[EXT] " : + (std::string) "[<a href=\"/EXT/" + self + "\">EXT</a>] "); return typeMenu; } diff --git a/server/setup.c b/server/setup.c index 3c3db1c..a35d38d 100644 --- a/server/setup.c +++ b/server/setup.c @@ -1,5 +1,5 @@ /* - * $Id: setup.c,v 1.3.2.3 2009/10/13 06:38:58 schmirl Exp $ + * $Id: setup.c,v 1.3.2.4 2010/07/19 13:50:14 schmirl Exp $ */ #include <vdr/menuitems.h> @@ -51,7 +51,7 @@ const char* cStreamdevServerMenuSetupPage::StreamTypes[st_Count - 1] = { "PES", "PS", "ES", - "Extern" + "EXT" }; const char* cStreamdevServerMenuSetupPage::SuspendModes[sm_Count] = { @@ -63,15 +63,25 @@ const char* cStreamdevServerMenuSetupPage::SuspendModes[sm_Count] = { cStreamdevServerMenuSetupPage::cStreamdevServerMenuSetupPage(void) { m_NewSetup = StreamdevServerSetup; + Set(); +} + +cStreamdevServerMenuSetupPage::~cStreamdevServerMenuSetupPage() { +} + +void cStreamdevServerMenuSetupPage::Set(void) { static const char* modes[sm_Count]; for (int i = 0; i < sm_Count; i++) modes[i] = tr(SuspendModes[i]); + int current = Current(); + Clear(); AddCategory (tr("Common Settings")); Add(new cMenuEditIntItem (tr("Maximum Number of Clients"), &m_NewSetup.MaxClients, 0, 100)); Add(new cMenuEditStraItem(tr("Suspend behaviour"), &m_NewSetup.SuspendMode, sm_Count, modes)); - Add(new cMenuEditBoolItem(tr("Client may suspend"), &m_NewSetup.AllowSuspend)); + if (m_NewSetup.SuspendMode == smOffer) + Add(new cMenuEditBoolItem(tr("Client may suspend"), &m_NewSetup.AllowSuspend)); AddCategory (tr("VDR-to-VDR Server")); Add(new cMenuEditBoolItem(tr("Start VDR-to-VDR Server"), &m_NewSetup.StartVTPServer)); @@ -88,10 +98,8 @@ cStreamdevServerMenuSetupPage::cStreamdevServerMenuSetupPage(void) { Add(new cMenuEditIntItem (tr("Multicast Client Port"), &m_NewSetup.IGMPClientPort, 0, 65535)); Add(new cMenuEditStraItem(tr("Multicast Streamtype"), &m_NewSetup.IGMPStreamType, st_Count - 1, StreamTypes)); Add(new cMenuEditIpItem (tr("Bind to IP"), m_NewSetup.IGMPBindIP)); - SetCurrent(Get(1)); -} - -cStreamdevServerMenuSetupPage::~cStreamdevServerMenuSetupPage() { + SetCurrent(Get(current)); + Display(); } void cStreamdevServerMenuSetupPage::AddCategory(const char *Title) { @@ -140,3 +148,10 @@ void cStreamdevServerMenuSetupPage::Store(void) { cStreamdevServer::Initialize(); } +eOSState cStreamdevServerMenuSetupPage::ProcessKey(eKeys Key) { + int oldMode = m_NewSetup.SuspendMode; + eOSState state = cMenuSetupPage::ProcessKey(Key); + if (oldMode != m_NewSetup.SuspendMode) + Set(); + return state; +} diff --git a/server/setup.h b/server/setup.h index 06c2e67..0bc3b13 100644 --- a/server/setup.h +++ b/server/setup.h @@ -1,5 +1,5 @@ /* - * $Id: setup.h,v 1.1.1.1.2.2 2009/09/18 10:41:12 schmirl Exp $ + * $Id: setup.h,v 1.1.1.1.2.3 2010/07/19 13:50:14 schmirl Exp $ */ #ifndef VDR_STREAMDEV_SETUPSERVER_H @@ -37,8 +37,10 @@ private: cStreamdevServerSetup m_NewSetup; void AddCategory(const char *Title); + void Set(); protected: virtual void Store(void); + virtual eOSState ProcessKey(eKeys Key); public: cStreamdevServerMenuSetupPage(void); diff --git a/server/streamer.c b/server/streamer.c index 97e4ab6..a10c1f4 100644 --- a/server/streamer.c +++ b/server/streamer.c @@ -1,5 +1,5 @@ /* - * $Id: streamer.c,v 1.16.2.3 2009/06/29 06:25:30 schmirl Exp $ + * $Id: streamer.c,v 1.16.2.4 2010/07/19 13:50:14 schmirl Exp $ */ #include <vdr/ringbuffer.h> @@ -100,8 +100,9 @@ void cStreamdevWriter::Action(void) // --- cStreamdevStreamer ----------------------------------------------------- -cStreamdevStreamer::cStreamdevStreamer(const char *Name): +cStreamdevStreamer::cStreamdevStreamer(const char *Name, const cServerConnection *Connection): cThread(Name), + m_Connection(Connection), m_Writer(NULL), m_RingBuffer(new cStreamdevBuffer(STREAMERBUFSIZE, TS_SIZE * 2, true, "streamdev-streamer")), diff --git a/server/streamer.h b/server/streamer.h index acb5486..ec09b0f 100644 --- a/server/streamer.h +++ b/server/streamer.h @@ -1,5 +1,5 @@ /* - * $Id: streamer.h,v 1.8.2.3 2009/06/29 06:25:30 schmirl Exp $ + * $Id: streamer.h,v 1.8.2.4 2010/07/19 13:50:14 schmirl Exp $ */ #ifndef VDR_STREAMDEV_STREAMER_H @@ -11,6 +11,7 @@ class cTBSocket; class cStreamdevStreamer; +class cServerConnection; #ifndef TS_SIZE #define TS_SIZE 188 @@ -64,6 +65,7 @@ public: class cStreamdevStreamer: public cThread { private: + const cServerConnection *m_Connection; cStreamdevWriter *m_Writer; cStreamdevBuffer *m_RingBuffer; cStreamdevBuffer *m_SendBuffer; @@ -74,9 +76,11 @@ protected: bool IsRunning(void) const { return m_Writer; } public: - cStreamdevStreamer(const char *Name); + cStreamdevStreamer(const char *Name, const cServerConnection *Connection = NULL); virtual ~cStreamdevStreamer(); + const cServerConnection* Connection(void) const { return m_Connection; } + virtual void Start(cTBSocket *Socket); virtual void Stop(void); bool Abort(void); |